@nuxt/scripts 1.0.0-beta.1 → 1.0.0-beta.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/client/200.html +1 -1
- package/dist/client/404.html +1 -1
- package/dist/client/_nuxt/48AF9EJD.js +1 -0
- package/dist/client/_nuxt/Bk6ed9rg.js +1 -0
- package/dist/client/_nuxt/C4Cj8gBr.js +162 -0
- package/dist/client/_nuxt/{DTDyDxvR.js → DP0kj6Xn.js} +1 -1
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/919b81d8-ed3a-4222-8a40-df0031cc3b99.json +1 -0
- package/dist/client/_nuxt/entry.D45OuV0w.css +1 -0
- package/dist/client/_nuxt/error-404.B57D-jUQ.css +1 -0
- package/dist/client/_nuxt/error-500.DTHUW7BI.css +1 -0
- package/dist/client/index.html +1 -1
- package/dist/module.d.mts +87 -2
- package/dist/module.d.ts +176 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +710 -273
- package/dist/registry.d.ts +6 -0
- package/dist/registry.mjs +42 -19
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.d.vue.ts +1 -1
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue +6 -6
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMaps.vue.d.ts +1 -1
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsAdvancedMarkerElement.vue +6 -6
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsCircle.vue +7 -7
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsHeatmapLayer.vue +6 -6
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue +12 -12
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarker.vue +6 -6
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.d.vue.ts +1 -1
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue +6 -6
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsMarkerClusterer.vue.d.ts +1 -1
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPinElement.vue +5 -5
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolygon.vue +7 -7
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsPolyline.vue +7 -7
- package/dist/runtime/components/GoogleMaps/ScriptGoogleMapsRectangle.vue +7 -7
- package/dist/runtime/components/ScriptCrisp.vue +1 -1
- package/dist/runtime/components/ScriptGoogleAdsense.vue +1 -1
- package/dist/runtime/components/ScriptInstagramEmbed.d.vue.ts +53 -0
- package/dist/runtime/components/ScriptInstagramEmbed.vue +38 -0
- package/dist/runtime/components/ScriptInstagramEmbed.vue.d.ts +53 -0
- package/dist/runtime/components/ScriptIntercom.vue +4 -3
- package/dist/runtime/components/ScriptPayPalButtons.d.vue.ts +2 -2
- package/dist/runtime/components/ScriptPayPalButtons.vue +13 -11
- package/dist/runtime/components/ScriptPayPalButtons.vue.d.ts +2 -2
- package/dist/runtime/components/ScriptPayPalMarks.d.vue.ts +2 -2
- package/dist/runtime/components/ScriptPayPalMarks.vue +10 -8
- package/dist/runtime/components/ScriptPayPalMarks.vue.d.ts +2 -2
- package/dist/runtime/components/ScriptPayPalMessages.d.vue.ts +2 -2
- package/dist/runtime/components/ScriptPayPalMessages.vue +11 -9
- package/dist/runtime/components/ScriptPayPalMessages.vue.d.ts +2 -2
- package/dist/runtime/components/ScriptStripePricingTable.vue +2 -2
- package/dist/runtime/components/ScriptVimeoPlayer.vue +1 -1
- package/dist/runtime/components/ScriptXEmbed.d.vue.ts +82 -0
- package/dist/runtime/components/ScriptXEmbed.vue +76 -0
- package/dist/runtime/components/ScriptXEmbed.vue.d.ts +82 -0
- package/dist/runtime/components/ScriptYouTubePlayer.vue +7 -4
- package/dist/runtime/composables/useScript.js +26 -5
- package/dist/runtime/composables/useScriptEventPage.js +2 -2
- package/dist/runtime/composables/useScriptTriggerConsent.js +1 -1
- package/dist/runtime/composables/useScriptTriggerElement.js +1 -1
- package/dist/runtime/composables/useScriptTriggerIdleTimeout.js +1 -1
- package/dist/runtime/composables/useScriptTriggerServiceWorker.d.ts +7 -0
- package/dist/runtime/composables/useScriptTriggerServiceWorker.js +39 -0
- package/dist/runtime/registry/clarity.js +21 -25
- package/dist/runtime/registry/cloudflare-web-analytics.js +1 -1
- package/dist/runtime/registry/crisp.js +1 -1
- package/dist/runtime/registry/databuddy-analytics.js +1 -1
- package/dist/runtime/registry/fathom-analytics.js +1 -1
- package/dist/runtime/registry/google-adsense.js +1 -1
- package/dist/runtime/registry/google-analytics.js +2 -2
- package/dist/runtime/registry/google-maps.d.ts +1 -1
- package/dist/runtime/registry/google-maps.js +1 -1
- package/dist/runtime/registry/google-recaptcha.js +2 -2
- package/dist/runtime/registry/google-sign-in.js +1 -1
- package/dist/runtime/registry/google-tag-manager.d.ts +1 -1
- package/dist/runtime/registry/google-tag-manager.js +2 -2
- package/dist/runtime/registry/hotjar.js +1 -1
- package/dist/runtime/registry/instagram-embed.d.ts +23 -0
- package/dist/runtime/registry/instagram-embed.js +22 -0
- package/dist/runtime/registry/intercom.js +1 -1
- package/dist/runtime/registry/lemon-squeezy.d.ts +0 -1
- package/dist/runtime/registry/matomo-analytics.js +2 -2
- package/dist/runtime/registry/meta-pixel.js +1 -1
- package/dist/runtime/registry/npm.js +1 -1
- package/dist/runtime/registry/paypal.d.ts +1 -1
- package/dist/runtime/registry/paypal.js +2 -2
- package/dist/runtime/registry/plausible-analytics.js +15 -9
- package/dist/runtime/registry/posthog.d.ts +3 -2
- package/dist/runtime/registry/posthog.js +8 -12
- package/dist/runtime/registry/reddit-pixel.js +1 -1
- package/dist/runtime/registry/rybbit-analytics.js +5 -3
- package/dist/runtime/registry/segment.js +1 -1
- package/dist/runtime/registry/snapchat-pixel.js +1 -1
- package/dist/runtime/registry/stripe.d.ts +1 -1
- package/dist/runtime/registry/stripe.js +1 -1
- package/dist/runtime/registry/tiktok-pixel.d.ts +1 -0
- package/dist/runtime/registry/tiktok-pixel.js +2 -1
- package/dist/runtime/registry/umami-analytics.js +1 -1
- package/dist/runtime/registry/vimeo-player.d.ts +2 -2
- package/dist/runtime/registry/vimeo-player.js +1 -1
- package/dist/runtime/registry/x-embed.d.ts +77 -0
- package/dist/runtime/registry/x-embed.js +41 -0
- package/dist/runtime/registry/x-pixel.js +1 -1
- package/dist/runtime/registry/youtube-player.d.ts +7 -7
- package/dist/runtime/registry/youtube-player.js +1 -1
- package/dist/runtime/server/google-static-maps-proxy.js +1 -1
- package/dist/runtime/server/instagram-embed-asset.d.ts +2 -0
- package/dist/runtime/server/instagram-embed-asset.js +42 -0
- package/dist/runtime/server/instagram-embed-image.d.ts +2 -0
- package/dist/runtime/server/instagram-embed-image.js +54 -0
- package/dist/runtime/server/instagram-embed.d.ts +2 -0
- package/dist/runtime/server/instagram-embed.js +91 -0
- package/dist/runtime/server/proxy-handler.d.ts +6 -0
- package/dist/runtime/server/proxy-handler.js +264 -0
- package/dist/runtime/server/utils/privacy.d.ts +141 -0
- package/dist/runtime/server/utils/privacy.js +324 -0
- package/dist/runtime/server/x-embed-image.d.ts +2 -0
- package/dist/runtime/server/x-embed-image.js +53 -0
- package/dist/runtime/server/x-embed.d.ts +49 -0
- package/dist/runtime/server/x-embed.js +31 -0
- package/dist/runtime/types.d.ts +51 -22
- package/dist/runtime/utils/pure.d.ts +9 -0
- package/dist/runtime/utils/pure.js +0 -0
- package/dist/runtime/utils.d.ts +3 -3
- package/dist/runtime/utils.js +3 -2
- package/dist/shared/scripts.DLRgvHQg.mjs +288 -0
- package/dist/stats.d.mts +39 -0
- package/dist/stats.d.ts +39 -0
- package/dist/stats.mjs +711 -0
- package/dist/types.d.mts +1 -1
- package/package.json +48 -41
- package/dist/client/_nuxt/Bdf7Qtwg.js +0 -1
- package/dist/client/_nuxt/CoyZWCgl.js +0 -162
- package/dist/client/_nuxt/Ds1k3yKJ.js +0 -1
- package/dist/client/_nuxt/builds/meta/62574f80-71d4-4f9e-8b96-145c85230d99.json +0 -1
- package/dist/client/_nuxt/entry.BjfcJo5q.css +0 -1
- package/dist/client/_nuxt/error-404.D45Vtjcx.css +0 -1
- package/dist/client/_nuxt/error-500.BOm1rWQf.css +0 -1
package/dist/module.mjs
CHANGED
|
@@ -1,79 +1,36 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { useNuxt, addDevServerHandler, extendRouteRules, tryUseNuxt, extendViteConfig, logger as logger$1, useLogger, addTypeTemplate, defineNuxtModule, createResolver, hasNuxtModule, addImports, addComponentsDir, addTemplate, addPluginTemplate, addServerHandler, addBuildPlugin } from '@nuxt/kit';
|
|
2
3
|
import { defu } from 'defu';
|
|
3
|
-
import { resolvePackageJSON, readPackageJSON } from 'pkg-types';
|
|
4
|
-
import { existsSync } from 'node:fs';
|
|
5
|
-
import { createHash } from 'node:crypto';
|
|
6
|
-
import fsp from 'node:fs/promises';
|
|
7
|
-
import { createUnplugin } from 'unplugin';
|
|
8
|
-
import MagicString from 'magic-string';
|
|
9
|
-
import { asyncWalk, walk } from 'estree-walker';
|
|
10
|
-
import { joinURL, parseURL, parseQuery, hasProtocol } from 'ufo';
|
|
11
|
-
import { hash } from 'ohash';
|
|
12
4
|
import { join, resolve, relative } from 'pathe';
|
|
13
|
-
import {
|
|
14
|
-
import { fetch, $fetch } from 'ofetch';
|
|
5
|
+
import { resolvePackageJSON, readPackageJSON } from 'pkg-types';
|
|
15
6
|
import { lazyEventHandler, eventHandler, createError } from 'h3';
|
|
7
|
+
import { fetch, $fetch } from 'ofetch';
|
|
8
|
+
import { joinURL, parseURL, parseQuery, hasProtocol } from 'ufo';
|
|
16
9
|
import { createStorage } from 'unstorage';
|
|
17
10
|
import fsDriver from 'unstorage/drivers/fs-lite';
|
|
18
|
-
import {
|
|
11
|
+
import { addCustomTab } from '@nuxt/devtools-kit';
|
|
19
12
|
import { isCI, provider } from 'std-env';
|
|
13
|
+
import { parseAndWalk } from 'oxc-walker';
|
|
14
|
+
import { createUnplugin } from 'unplugin';
|
|
15
|
+
import { pathToFileURL } from 'node:url';
|
|
16
|
+
import { createHash } from 'node:crypto';
|
|
17
|
+
import fsp from 'node:fs/promises';
|
|
18
|
+
import { colors } from 'consola/utils';
|
|
19
|
+
import MagicString from 'magic-string';
|
|
20
|
+
import { hash } from 'ohash';
|
|
21
|
+
import { a as getProxyConfig, g as getAllProxyConfigs, r as routesToInterceptRules } from './shared/scripts.DLRgvHQg.mjs';
|
|
20
22
|
import { registry } from './registry.mjs';
|
|
21
23
|
|
|
22
|
-
const DEVTOOLS_UI_ROUTE = "/__nuxt-scripts";
|
|
23
|
-
const DEVTOOLS_UI_LOCAL_PORT = 3300;
|
|
24
|
-
|
|
25
|
-
async function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
|
|
26
|
-
const clientPath = await resolve("./client");
|
|
27
|
-
const isProductionBuild = existsSync(clientPath);
|
|
28
|
-
if (isProductionBuild) {
|
|
29
|
-
nuxt.hook("vite:serverCreated", async (server) => {
|
|
30
|
-
const sirv = await import('sirv').then((r) => r.default || r);
|
|
31
|
-
server.middlewares.use(
|
|
32
|
-
DEVTOOLS_UI_ROUTE,
|
|
33
|
-
sirv(clientPath, { dev: true, single: true })
|
|
34
|
-
);
|
|
35
|
-
});
|
|
36
|
-
} else {
|
|
37
|
-
extendViteConfig((config) => {
|
|
38
|
-
config.server = config.server || {};
|
|
39
|
-
config.server.proxy = config.server.proxy || {};
|
|
40
|
-
config.server.proxy[DEVTOOLS_UI_ROUTE] = {
|
|
41
|
-
target: `http://localhost:${DEVTOOLS_UI_LOCAL_PORT}${DEVTOOLS_UI_ROUTE}`,
|
|
42
|
-
changeOrigin: true,
|
|
43
|
-
followRedirects: true,
|
|
44
|
-
rewrite: (path) => path.replace(DEVTOOLS_UI_ROUTE, "")
|
|
45
|
-
};
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
nuxt.hook("devtools:customTabs", (tabs) => {
|
|
49
|
-
tabs.push({
|
|
50
|
-
// unique identifier
|
|
51
|
-
name: "nuxt-scripts",
|
|
52
|
-
// title to display in the tab
|
|
53
|
-
title: "Scripts",
|
|
54
|
-
// any icon from Iconify, or a URL to an image
|
|
55
|
-
icon: "carbon:script",
|
|
56
|
-
// iframe view
|
|
57
|
-
view: {
|
|
58
|
-
type: "iframe",
|
|
59
|
-
src: DEVTOOLS_UI_ROUTE
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const logger = useLogger("@nuxt/scripts");
|
|
66
|
-
|
|
67
24
|
const renderedScript = /* @__PURE__ */ new Map();
|
|
68
25
|
const ONE_YEAR_IN_SECONDS = 60 * 60 * 24 * 365;
|
|
69
|
-
|
|
26
|
+
function bundleStorage() {
|
|
70
27
|
const nuxt = tryUseNuxt();
|
|
71
28
|
return createStorage({
|
|
72
29
|
driver: fsDriver({
|
|
73
30
|
base: resolve(nuxt?.options.rootDir || "", "node_modules/.cache/nuxt/scripts")
|
|
74
31
|
})
|
|
75
32
|
});
|
|
76
|
-
}
|
|
33
|
+
}
|
|
77
34
|
function setupPublicAssetStrategy(options = {}) {
|
|
78
35
|
const assetsBaseURL = options.prefix || "/_scripts";
|
|
79
36
|
const nuxt = useNuxt();
|
|
@@ -86,6 +43,9 @@ function setupPublicAssetStrategy(options = {}) {
|
|
|
86
43
|
const scriptDescriptor = renderedScript.get(join(assetsBaseURL, event.path.slice(1)));
|
|
87
44
|
if (!scriptDescriptor || scriptDescriptor instanceof Error)
|
|
88
45
|
throw createError({ statusCode: 404 });
|
|
46
|
+
if (scriptDescriptor.content) {
|
|
47
|
+
return scriptDescriptor.content;
|
|
48
|
+
}
|
|
89
49
|
const key = `bundle:${filename}`;
|
|
90
50
|
let res = await storage.getItemRaw(key);
|
|
91
51
|
if (!res) {
|
|
@@ -97,31 +57,112 @@ function setupPublicAssetStrategy(options = {}) {
|
|
|
97
57
|
})
|
|
98
58
|
});
|
|
99
59
|
if (nuxt.options.dev) {
|
|
100
|
-
|
|
101
|
-
nuxt.options.routeRules[joinURL(assetsBaseURL, "**")] = {
|
|
60
|
+
extendRouteRules(joinURL(assetsBaseURL, "**"), {
|
|
102
61
|
cache: {
|
|
103
62
|
maxAge: ONE_YEAR_IN_SECONDS
|
|
104
63
|
}
|
|
105
|
-
};
|
|
64
|
+
});
|
|
106
65
|
}
|
|
107
|
-
nuxt.options.nitro.publicAssets ||= [];
|
|
108
66
|
const cacheDir = join(nuxt.options.buildDir, "cache", "scripts");
|
|
109
|
-
nuxt.
|
|
110
|
-
|
|
111
|
-
publicAssets
|
|
67
|
+
nuxt.hook("nitro:config", (nitroConfig) => {
|
|
68
|
+
nitroConfig.publicAssets ||= [];
|
|
69
|
+
nitroConfig.publicAssets.push({
|
|
112
70
|
dir: cacheDir,
|
|
113
71
|
maxAge: ONE_YEAR_IN_SECONDS,
|
|
114
72
|
baseURL: assetsBaseURL
|
|
115
|
-
}
|
|
116
|
-
prerender
|
|
117
|
-
|
|
118
|
-
|
|
73
|
+
});
|
|
74
|
+
nitroConfig.prerender ||= {};
|
|
75
|
+
nitroConfig.prerender.ignore ||= [];
|
|
76
|
+
nitroConfig.prerender.ignore.push(assetsBaseURL);
|
|
119
77
|
});
|
|
120
78
|
return {
|
|
121
79
|
renderedScript
|
|
122
80
|
};
|
|
123
81
|
}
|
|
124
82
|
|
|
83
|
+
const DEVTOOLS_UI_ROUTE = "/__nuxt-scripts";
|
|
84
|
+
const DEVTOOLS_UI_LOCAL_PORT = 3300;
|
|
85
|
+
|
|
86
|
+
async function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
|
|
87
|
+
const clientPath = await resolve("./client");
|
|
88
|
+
const isProductionBuild = existsSync(clientPath);
|
|
89
|
+
if (isProductionBuild) {
|
|
90
|
+
nuxt.hook("vite:serverCreated", async (server) => {
|
|
91
|
+
const sirv = await import('sirv').then((r) => r.default || r);
|
|
92
|
+
server.middlewares.use(
|
|
93
|
+
DEVTOOLS_UI_ROUTE,
|
|
94
|
+
sirv(clientPath, { dev: true, single: true })
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
} else {
|
|
98
|
+
extendViteConfig((config) => {
|
|
99
|
+
config.server = config.server || {};
|
|
100
|
+
config.server.proxy = config.server.proxy || {};
|
|
101
|
+
config.server.proxy[DEVTOOLS_UI_ROUTE] = {
|
|
102
|
+
target: `http://localhost:${DEVTOOLS_UI_LOCAL_PORT}${DEVTOOLS_UI_ROUTE}`,
|
|
103
|
+
changeOrigin: true,
|
|
104
|
+
followRedirects: true,
|
|
105
|
+
rewrite: (path) => path.replace(DEVTOOLS_UI_ROUTE, "")
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
addCustomTab({
|
|
110
|
+
// unique identifier
|
|
111
|
+
name: "nuxt-scripts",
|
|
112
|
+
// title to display in the tab
|
|
113
|
+
title: "Scripts",
|
|
114
|
+
// any icon from Iconify, or a URL to an image
|
|
115
|
+
icon: "carbon:script",
|
|
116
|
+
// iframe view
|
|
117
|
+
view: {
|
|
118
|
+
type: "iframe",
|
|
119
|
+
src: DEVTOOLS_UI_ROUTE
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const isStackblitz = provider === "stackblitz";
|
|
125
|
+
async function promptToInstall(name, installCommand, options) {
|
|
126
|
+
if (await resolvePackageJSON(name).catch(() => null))
|
|
127
|
+
return true;
|
|
128
|
+
logger$1.info(`Package ${name} is missing`);
|
|
129
|
+
if (isCI)
|
|
130
|
+
return false;
|
|
131
|
+
if (options.prompt === true || options.prompt !== false && !isStackblitz) {
|
|
132
|
+
const confirm = await logger$1.prompt(`Do you want to install ${name} package?`, {
|
|
133
|
+
type: "confirm",
|
|
134
|
+
name: "confirm",
|
|
135
|
+
initial: true
|
|
136
|
+
});
|
|
137
|
+
if (!confirm)
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
logger$1.info(`Installing ${name}...`);
|
|
141
|
+
try {
|
|
142
|
+
await installCommand();
|
|
143
|
+
logger$1.success(`Installed ${name}`);
|
|
144
|
+
return true;
|
|
145
|
+
} catch (err) {
|
|
146
|
+
logger$1.error(err);
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const installPrompts = /* @__PURE__ */ new Set();
|
|
151
|
+
function installNuxtModule(name, options) {
|
|
152
|
+
if (installPrompts.has(name))
|
|
153
|
+
return;
|
|
154
|
+
installPrompts.add(name);
|
|
155
|
+
const nuxt = tryUseNuxt();
|
|
156
|
+
if (!nuxt)
|
|
157
|
+
return;
|
|
158
|
+
return promptToInstall(name, async () => {
|
|
159
|
+
const { runCommand } = await import(String("nuxi"));
|
|
160
|
+
await runCommand("module", ["add", name, "--cwd", nuxt.options.rootDir]);
|
|
161
|
+
}, { rootDir: nuxt.options.rootDir, searchPaths: nuxt.options.modulesDir, ...options });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const logger = useLogger("@nuxt/scripts");
|
|
165
|
+
|
|
125
166
|
function isVue(id, opts = {}) {
|
|
126
167
|
const { search } = parseURL(decodeURIComponent(pathToFileURL(id).href));
|
|
127
168
|
if (id.endsWith(".vue") && !search) {
|
|
@@ -149,6 +190,173 @@ function isJS(id) {
|
|
|
149
190
|
return JS_RE.test(pathname);
|
|
150
191
|
}
|
|
151
192
|
|
|
193
|
+
function NuxtScriptsCheckScripts() {
|
|
194
|
+
return createUnplugin(() => {
|
|
195
|
+
return {
|
|
196
|
+
name: "nuxt-scripts:check-scripts",
|
|
197
|
+
transform: {
|
|
198
|
+
filter: {
|
|
199
|
+
id: /\.vue/
|
|
200
|
+
},
|
|
201
|
+
handler(code, id) {
|
|
202
|
+
if (!isVue(id, { type: ["script"] }))
|
|
203
|
+
return;
|
|
204
|
+
if (!code.includes("useScript"))
|
|
205
|
+
return;
|
|
206
|
+
let nameNode;
|
|
207
|
+
let errorNode;
|
|
208
|
+
parseAndWalk(code, id, (_node) => {
|
|
209
|
+
if (_node.type === "VariableDeclaration" && _node.declarations?.[0]?.id?.type === "ObjectPattern") {
|
|
210
|
+
const objPattern = _node.declarations[0]?.id;
|
|
211
|
+
for (const property of objPattern.properties) {
|
|
212
|
+
if (property.type === "Property" && property.key.type === "Identifier" && property.key.name === "$script" && property.value.type === "Identifier") {
|
|
213
|
+
nameNode = _node;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (nameNode) {
|
|
218
|
+
let sequence = _node.type === "SequenceExpression" ? _node : null;
|
|
219
|
+
let assignmentExpression;
|
|
220
|
+
if (_node.type === "VariableDeclaration") {
|
|
221
|
+
if (_node.declarations[0]?.init?.type === "SequenceExpression") {
|
|
222
|
+
sequence = _node.declarations[0]?.init;
|
|
223
|
+
assignmentExpression = _node.declarations[0]?.init?.expressions?.[0];
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (sequence && !assignmentExpression) {
|
|
227
|
+
assignmentExpression = sequence.expressions[0]?.type === "AssignmentExpression" ? sequence.expressions[0] : null;
|
|
228
|
+
}
|
|
229
|
+
if (assignmentExpression) {
|
|
230
|
+
const right = assignmentExpression?.right;
|
|
231
|
+
if (right.callee?.name === "_withAsyncContext") {
|
|
232
|
+
if (right.arguments[0]?.body?.name === "$script" || right.arguments[0]?.body?.callee?.object?.name === "$script") {
|
|
233
|
+
errorNode = nameNode;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
if (errorNode) {
|
|
240
|
+
return this.error(new Error("You can't use a top-level await on $script as it will never resolve."));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function isPropertyKeyAST(parent, ctx) {
|
|
249
|
+
return parent?.type === "Property" && ctx.key === "key" || parent?.type === "SwitchCase" && ctx.key === "test";
|
|
250
|
+
}
|
|
251
|
+
function matchAndRewrite(value, rewrites) {
|
|
252
|
+
for (const { from, to } of rewrites) {
|
|
253
|
+
const isSuffixMatch = from.startsWith(".");
|
|
254
|
+
const fromSlashIdx = from.indexOf("/");
|
|
255
|
+
const fromHost = fromSlashIdx > 0 ? from.slice(0, fromSlashIdx) : from;
|
|
256
|
+
const fromPath = fromSlashIdx > 0 ? from.slice(fromSlashIdx) : "";
|
|
257
|
+
if (!value.includes(fromHost))
|
|
258
|
+
continue;
|
|
259
|
+
const url = parseURL(value);
|
|
260
|
+
let shouldRewrite = false;
|
|
261
|
+
let rewriteSuffix = "";
|
|
262
|
+
if (url.host) {
|
|
263
|
+
const hostMatches = isSuffixMatch ? url.host.endsWith(fromHost) : url.host === fromHost;
|
|
264
|
+
if (hostMatches) {
|
|
265
|
+
const fullPath = url.pathname + (url.search || "") + (url.hash || "");
|
|
266
|
+
if (fromPath && fullPath.startsWith(fromPath)) {
|
|
267
|
+
shouldRewrite = true;
|
|
268
|
+
rewriteSuffix = fullPath.slice(fromPath.length);
|
|
269
|
+
} else if (!fromPath) {
|
|
270
|
+
shouldRewrite = true;
|
|
271
|
+
rewriteSuffix = fullPath;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
} else if (value.startsWith("//")) {
|
|
275
|
+
const hostPart = value.slice(2).split("/")[0];
|
|
276
|
+
const hostMatches = isSuffixMatch ? hostPart?.endsWith(fromHost) ?? false : hostPart === fromHost;
|
|
277
|
+
if (hostMatches) {
|
|
278
|
+
const remainder = value.slice(2 + (hostPart?.length ?? 0));
|
|
279
|
+
if (fromPath && remainder.startsWith(fromPath)) {
|
|
280
|
+
shouldRewrite = true;
|
|
281
|
+
rewriteSuffix = remainder.slice(fromPath.length);
|
|
282
|
+
} else if (!fromPath) {
|
|
283
|
+
shouldRewrite = true;
|
|
284
|
+
rewriteSuffix = remainder;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
} else if (fromPath && (value.startsWith(from) || isSuffixMatch && value.includes(from))) {
|
|
288
|
+
const domainEnd = value.indexOf(from) + from.length;
|
|
289
|
+
const nextChar = value[domainEnd];
|
|
290
|
+
if (!nextChar || nextChar === "/" || nextChar === "?" || nextChar === "#") {
|
|
291
|
+
shouldRewrite = true;
|
|
292
|
+
rewriteSuffix = value.slice(domainEnd);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (shouldRewrite) {
|
|
296
|
+
return rewriteSuffix === "/" || rewriteSuffix.startsWith("?") || rewriteSuffix.startsWith("#") ? to + rewriteSuffix : joinURL(to, rewriteSuffix);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
function rewriteScriptUrlsAST(content, filename, rewrites) {
|
|
302
|
+
const s = new MagicString(content);
|
|
303
|
+
parseAndWalk(content, filename, (node, parent, ctx) => {
|
|
304
|
+
if (node.type === "Literal" && typeof node.value === "string") {
|
|
305
|
+
const value = node.value;
|
|
306
|
+
const rewritten = matchAndRewrite(value, rewrites);
|
|
307
|
+
if (rewritten === null)
|
|
308
|
+
return;
|
|
309
|
+
const quote = content[node.start];
|
|
310
|
+
if (isPropertyKeyAST(parent, ctx)) {
|
|
311
|
+
s.overwrite(node.start, node.end, quote + rewritten + quote);
|
|
312
|
+
} else {
|
|
313
|
+
s.overwrite(node.start, node.end, `self.location.origin+${quote}${rewritten}${quote}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (node.type === "TemplateLiteral" && node.expressions?.length === 0) {
|
|
317
|
+
const quasis = node.quasis;
|
|
318
|
+
if (quasis?.length === 1) {
|
|
319
|
+
const value = quasis[0].value?.cooked ?? quasis[0].value?.raw;
|
|
320
|
+
if (typeof value !== "string")
|
|
321
|
+
return;
|
|
322
|
+
const rewritten = matchAndRewrite(value, rewrites);
|
|
323
|
+
if (rewritten === null)
|
|
324
|
+
return;
|
|
325
|
+
if (isPropertyKeyAST(parent, ctx)) {
|
|
326
|
+
s.overwrite(node.start, node.end, `\`${rewritten}\``);
|
|
327
|
+
} else {
|
|
328
|
+
s.overwrite(node.start, node.end, `self.location.origin+\`${rewritten}\``);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (node.type === "CallExpression") {
|
|
333
|
+
const callee = node.callee;
|
|
334
|
+
if (callee?.type === "MemberExpression" && !callee.computed && callee.object?.type === "Identifier" && callee.object.name === "navigator" && callee.property?.name === "sendBeacon") {
|
|
335
|
+
s.overwrite(callee.start, callee.end, "__nuxtScripts.sendBeacon");
|
|
336
|
+
}
|
|
337
|
+
if (callee?.type === "Identifier" && callee.name === "fetch") {
|
|
338
|
+
s.overwrite(callee.start, callee.end, "__nuxtScripts.fetch");
|
|
339
|
+
}
|
|
340
|
+
if (callee?.type === "MemberExpression" && !callee.computed && callee.object?.type === "Identifier" && (callee.object.name === "window" || callee.object.name === "self" || callee.object.name === "globalThis") && callee.property?.name === "fetch") {
|
|
341
|
+
s.overwrite(callee.start, callee.end, "__nuxtScripts.fetch");
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
let output = s.toString();
|
|
346
|
+
const gaRewrite = rewrites.find((r) => r.from.includes("google-analytics.com/g/collect"));
|
|
347
|
+
if (gaRewrite) {
|
|
348
|
+
output = output.replace(
|
|
349
|
+
/"https:\/\/"\+\(.*?\)\+"\.google-analytics\.com\/g\/collect"/g,
|
|
350
|
+
`self.location.origin+"${gaRewrite.to}"`
|
|
351
|
+
);
|
|
352
|
+
output = output.replace(
|
|
353
|
+
/"https:\/\/"\+\(.*?\)\+"\.analytics\.google\.com\/g\/collect"/g,
|
|
354
|
+
`self.location.origin+"${gaRewrite.to}"`
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
return output;
|
|
358
|
+
}
|
|
359
|
+
|
|
152
360
|
const SEVEN_DAYS_IN_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
153
361
|
function calculateIntegrity(content, algorithm = "sha384") {
|
|
154
362
|
const hash = createHash(algorithm).update(content).digest("base64");
|
|
@@ -166,10 +374,8 @@ function normalizeScriptData(src, assetsBaseURL = "/_scripts") {
|
|
|
166
374
|
if (hasProtocol(src, { acceptRelative: true })) {
|
|
167
375
|
src = src.replace(/^\/\//, "https://");
|
|
168
376
|
const url = parseURL(src);
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
// force an extension
|
|
172
|
-
].filter(Boolean).join("-");
|
|
377
|
+
const h = hash(url);
|
|
378
|
+
const file = `${h.startsWith("-") ? `_${h.slice(1)}` : h}.js`;
|
|
173
379
|
const nuxt = tryUseNuxt();
|
|
174
380
|
const cdnURL = nuxt?.options.runtimeConfig?.app?.cdnURL || nuxt?.options.app?.cdnURL || "";
|
|
175
381
|
const baseURL = cdnURL || nuxt?.options.app.baseURL || "";
|
|
@@ -178,7 +384,7 @@ function normalizeScriptData(src, assetsBaseURL = "/_scripts") {
|
|
|
178
384
|
return { url: src };
|
|
179
385
|
}
|
|
180
386
|
async function downloadScript(opts, renderedScript, fetchOptions, cacheMaxAge) {
|
|
181
|
-
const { src, url, filename, forceDownload, integrity } = opts;
|
|
387
|
+
const { src, url, filename, forceDownload, integrity, proxyRewrites } = opts;
|
|
182
388
|
if (src === url || !filename) {
|
|
183
389
|
return;
|
|
184
390
|
}
|
|
@@ -186,7 +392,8 @@ async function downloadScript(opts, renderedScript, fetchOptions, cacheMaxAge) {
|
|
|
186
392
|
const scriptContent = renderedScript.get(src);
|
|
187
393
|
let res = scriptContent instanceof Error ? void 0 : scriptContent?.content;
|
|
188
394
|
if (!res) {
|
|
189
|
-
const
|
|
395
|
+
const proxyRewritesHash = proxyRewrites?.length ? `-${hash(proxyRewrites)}` : "";
|
|
396
|
+
const cacheKey = proxyRewrites?.length ? `bundle-proxy:${filename.replace(".js", `${proxyRewritesHash}.js`)}` : `bundle:${filename}`;
|
|
190
397
|
const shouldUseCache = !forceDownload && await storage.hasItem(cacheKey) && !await isCacheExpired(storage, filename, cacheMaxAge);
|
|
191
398
|
if (shouldUseCache) {
|
|
192
399
|
const cachedContent = await storage.getItemRaw(cacheKey);
|
|
@@ -212,8 +419,15 @@ async function downloadScript(opts, renderedScript, fetchOptions, cacheMaxAge) {
|
|
|
212
419
|
size = contentLength ? Number(contentLength) / 1024 : 0;
|
|
213
420
|
return Buffer.from(r._data || await r.arrayBuffer());
|
|
214
421
|
});
|
|
215
|
-
const integrityHash = integrity && res ? calculateIntegrity(res, integrity === true ? "sha384" : integrity) : void 0;
|
|
216
422
|
await storage.setItemRaw(`bundle:${filename}`, res);
|
|
423
|
+
if (proxyRewrites?.length && res) {
|
|
424
|
+
const content = res.toString("utf-8");
|
|
425
|
+
const rewritten = rewriteScriptUrlsAST(content, filename || "script.js", proxyRewrites);
|
|
426
|
+
res = Buffer.from(rewritten, "utf-8");
|
|
427
|
+
logger.debug(`Rewrote ${proxyRewrites.length} URL patterns in ${filename}`);
|
|
428
|
+
}
|
|
429
|
+
const integrityHash = integrity && res ? calculateIntegrity(res, integrity === true ? "sha384" : integrity) : void 0;
|
|
430
|
+
await storage.setItemRaw(cacheKey, res);
|
|
217
431
|
await storage.setItem(`bundle-meta:${filename}`, {
|
|
218
432
|
timestamp: Date.now(),
|
|
219
433
|
src,
|
|
@@ -262,16 +476,21 @@ function NuxtScriptBundleTransformer(options = {
|
|
|
262
476
|
return createUnplugin(() => {
|
|
263
477
|
return {
|
|
264
478
|
name: "nuxt:scripts:bundler-transformer",
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
479
|
+
transform: {
|
|
480
|
+
filter: {
|
|
481
|
+
id: {
|
|
482
|
+
include: [/\.vue/, /\.[cm]?[jt]sx?$/],
|
|
483
|
+
exclude: [/\.(?:test|spec)\./]
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
async handler(code, id) {
|
|
487
|
+
if (!isVue(id, { type: ["template", "script"] }) && !isJS(id))
|
|
488
|
+
return;
|
|
489
|
+
if (!code.includes("useScript"))
|
|
490
|
+
return;
|
|
491
|
+
const s = new MagicString(code);
|
|
492
|
+
const deferredOps = [];
|
|
493
|
+
parseAndWalk(code, id, (_node) => {
|
|
275
494
|
const calleeName = _node.callee?.name;
|
|
276
495
|
if (!calleeName)
|
|
277
496
|
return;
|
|
@@ -281,6 +500,11 @@ function NuxtScriptBundleTransformer(options = {
|
|
|
281
500
|
const node = _node;
|
|
282
501
|
let scriptSrcNode;
|
|
283
502
|
let src;
|
|
503
|
+
let registryKey;
|
|
504
|
+
if (fnName !== "useScript") {
|
|
505
|
+
const baseName = fnName.replace(/^useScript/, "");
|
|
506
|
+
registryKey = baseName.length > 0 ? baseName.charAt(0).toLowerCase() + baseName.slice(1) : void 0;
|
|
507
|
+
}
|
|
284
508
|
if (fnName === "useScript") {
|
|
285
509
|
if (node.arguments[0]?.type === "Literal") {
|
|
286
510
|
scriptSrcNode = node.arguments[0];
|
|
@@ -297,9 +521,7 @@ function NuxtScriptBundleTransformer(options = {
|
|
|
297
521
|
}
|
|
298
522
|
if (!registryNode.scriptBundling && !registryNode.src)
|
|
299
523
|
return;
|
|
300
|
-
const
|
|
301
|
-
const registryKey = baseName.length > 0 ? baseName.charAt(0).toLowerCase() + baseName.slice(1) : "";
|
|
302
|
-
const registryConfig = options.registryConfig?.[registryKey] || {};
|
|
524
|
+
const registryConfig = options.registryConfig?.[registryKey || ""] || {};
|
|
303
525
|
const fnArg0 = {};
|
|
304
526
|
if (node.arguments[0]?.type === "ObjectExpression") {
|
|
305
527
|
const optionsNode = node.arguments[0];
|
|
@@ -319,6 +541,8 @@ function NuxtScriptBundleTransformer(options = {
|
|
|
319
541
|
src = registryNode.scriptBundling && registryNode.scriptBundling(mergedOptions);
|
|
320
542
|
if (src === false)
|
|
321
543
|
return;
|
|
544
|
+
if (!src && registryNode.src)
|
|
545
|
+
src = registryNode.src;
|
|
322
546
|
}
|
|
323
547
|
}
|
|
324
548
|
if (!scriptSrcNode && !src) {
|
|
@@ -333,8 +557,7 @@ function NuxtScriptBundleTransformer(options = {
|
|
|
333
557
|
if (bundleProperty && bundleProperty.value.type === "Literal") {
|
|
334
558
|
const bundleValue = bundleProperty.value.value;
|
|
335
559
|
if (bundleValue === true || bundleValue === "force" || String(bundleValue) === "true") {
|
|
336
|
-
|
|
337
|
-
s.overwrite(valueNode.start, valueNode.end, `'unsupported'`);
|
|
560
|
+
s.overwrite(bundleProperty.value.start, bundleProperty.value.end, `'unsupported'`);
|
|
338
561
|
}
|
|
339
562
|
}
|
|
340
563
|
}
|
|
@@ -351,8 +574,7 @@ function NuxtScriptBundleTransformer(options = {
|
|
|
351
574
|
(p) => (p.key?.name === "bundle" || p.key?.value === "bundle") && p.type === "Property"
|
|
352
575
|
);
|
|
353
576
|
if (bundleProperty && bundleProperty.value.type === "Literal") {
|
|
354
|
-
const
|
|
355
|
-
const bundleValue = value.value;
|
|
577
|
+
const bundleValue = bundleProperty.value.value;
|
|
356
578
|
if (bundleValue !== true && bundleValue !== "force" && String(bundleValue) !== "true") {
|
|
357
579
|
canBundle = false;
|
|
358
580
|
return;
|
|
@@ -380,175 +602,104 @@ function NuxtScriptBundleTransformer(options = {
|
|
|
380
602
|
canBundle = bundleValue === true || bundleValue === "force" || String(bundleValue) === "true";
|
|
381
603
|
forceDownload = bundleValue === "force";
|
|
382
604
|
}
|
|
605
|
+
const firstPartyOption = scriptOptions?.value.properties?.find((prop) => {
|
|
606
|
+
return prop.type === "Property" && prop.key?.name === "firstParty" && prop.value.type === "Literal";
|
|
607
|
+
});
|
|
608
|
+
let firstPartyOptOut = firstPartyOption?.value.value === false;
|
|
609
|
+
if (!firstPartyOptOut && node.arguments[1]?.type === "ObjectExpression") {
|
|
610
|
+
const secondArgFirstPartyProp = node.arguments[1].properties.find(
|
|
611
|
+
(p) => p.type === "Property" && p.key?.name === "firstParty" && p.value.type === "Literal"
|
|
612
|
+
);
|
|
613
|
+
firstPartyOptOut = secondArgFirstPartyProp?.value.value === false;
|
|
614
|
+
}
|
|
615
|
+
if (!firstPartyOptOut && node.arguments[0]?.type === "ObjectExpression") {
|
|
616
|
+
const firstArgFirstPartyProp = node.arguments[0].properties.find(
|
|
617
|
+
(p) => p.type === "Property" && p.key?.name === "firstParty" && p.value.type === "Literal"
|
|
618
|
+
);
|
|
619
|
+
firstPartyOptOut = firstArgFirstPartyProp?.value.value === false;
|
|
620
|
+
}
|
|
383
621
|
if (canBundle) {
|
|
384
622
|
const { url: _url, filename } = normalizeScriptData(src, options.assetsBaseURL);
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
url
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
623
|
+
const script = options.scripts?.find((s2) => s2.import.name === fnName);
|
|
624
|
+
const proxyConfigKey = script?.proxy !== false ? script?.proxy || registryKey : void 0;
|
|
625
|
+
const proxyRewrites = options.firstPartyEnabled && !firstPartyOptOut && proxyConfigKey && options.firstPartyCollectPrefix ? getProxyConfig(proxyConfigKey, options.firstPartyCollectPrefix)?.rewrite : void 0;
|
|
626
|
+
deferredOps.push(async () => {
|
|
627
|
+
let url = _url;
|
|
628
|
+
try {
|
|
629
|
+
await downloadScript({ src, url, filename, forceDownload, proxyRewrites, integrity: options.integrity }, renderedScript, options.fetchOptions, options.cacheMaxAge);
|
|
630
|
+
} catch (e) {
|
|
631
|
+
if (options.fallbackOnSrcOnBundleFail) {
|
|
632
|
+
logger.warn(`[Nuxt Scripts: Bundle Transformer] Failed to bundle ${src}. Fallback to remote loading.`);
|
|
633
|
+
url = src;
|
|
634
|
+
} else {
|
|
635
|
+
const errorMessage = e?.message || "Unknown error";
|
|
636
|
+
if (errorMessage.includes("timeout") || errorMessage.includes("network") || errorMessage.includes("ENOTFOUND") || errorMessage.includes("certificate")) {
|
|
637
|
+
logger.error(`[Nuxt Scripts: Bundle Transformer] Network issue while bundling ${src}: ${errorMessage}`);
|
|
638
|
+
logger.error(`[Nuxt Scripts: Bundle Transformer] Tip: Set 'fallbackOnSrcOnBundleFail: true' in module options or disable bundling in Docker environments`);
|
|
639
|
+
}
|
|
640
|
+
throw e;
|
|
397
641
|
}
|
|
398
|
-
throw e;
|
|
399
642
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
logger.warn(`[Nuxt Scripts: Bundle Transformer] Failed to bundle ${src}.`);
|
|
406
|
-
}
|
|
407
|
-
const scriptMeta = renderedScript.get(url);
|
|
408
|
-
const integrityHash = scriptMeta instanceof Error ? void 0 : scriptMeta?.integrity;
|
|
409
|
-
if (scriptSrcNode) {
|
|
410
|
-
if (integrityHash && fnName === "useScript" && node.arguments[0]?.type === "Literal") {
|
|
411
|
-
s.overwrite(scriptSrcNode.start, scriptSrcNode.end, `{ src: '${url}', integrity: '${integrityHash}', crossorigin: 'anonymous' }`);
|
|
412
|
-
} else if (integrityHash && fnName === "useScript" && node.arguments[0]?.type === "ObjectExpression") {
|
|
413
|
-
s.overwrite(scriptSrcNode.start, scriptSrcNode.end, `'${url}'`);
|
|
414
|
-
const objArg = node.arguments[0];
|
|
415
|
-
s.appendLeft(objArg.end - 1, `, integrity: '${integrityHash}', crossorigin: 'anonymous'`);
|
|
416
|
-
} else {
|
|
417
|
-
s.overwrite(scriptSrcNode.start, scriptSrcNode.end, `'${url}'`);
|
|
643
|
+
if (src === url) {
|
|
644
|
+
if (src && src.startsWith("/"))
|
|
645
|
+
logger.warn(`[Nuxt Scripts: Bundle Transformer] Relative scripts are already bundled. Skipping bundling for \`${src}\`.`);
|
|
646
|
+
else
|
|
647
|
+
logger.warn(`[Nuxt Scripts: Bundle Transformer] Failed to bundle ${src}.`);
|
|
418
648
|
}
|
|
419
|
-
|
|
420
|
-
const
|
|
421
|
-
if (
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
649
|
+
const scriptMeta = renderedScript.get(url);
|
|
650
|
+
const integrityHash = scriptMeta instanceof Error ? void 0 : scriptMeta?.integrity;
|
|
651
|
+
if (scriptSrcNode) {
|
|
652
|
+
if (integrityHash && fnName === "useScript" && node.arguments[0]?.type === "Literal") {
|
|
653
|
+
s.overwrite(scriptSrcNode.start, scriptSrcNode.end, `{ src: '${url}', integrity: '${integrityHash}', crossorigin: 'anonymous' }`);
|
|
654
|
+
} else if (integrityHash && fnName === "useScript" && node.arguments[0]?.type === "ObjectExpression") {
|
|
655
|
+
s.overwrite(scriptSrcNode.start, scriptSrcNode.end, `'${url}'`);
|
|
656
|
+
s.appendLeft(node.arguments[0].end - 1, `, integrity: '${integrityHash}', crossorigin: 'anonymous'`);
|
|
657
|
+
} else {
|
|
658
|
+
s.overwrite(scriptSrcNode.start, scriptSrcNode.end, `'${url}'`);
|
|
659
|
+
}
|
|
660
|
+
} else {
|
|
661
|
+
const integrityProps = integrityHash ? `, integrity: '${integrityHash}', crossorigin: 'anonymous'` : "";
|
|
662
|
+
if (node.arguments[0]) {
|
|
663
|
+
const optionsNode = node.arguments[0];
|
|
664
|
+
const scriptInputProperty = optionsNode.properties.find(
|
|
665
|
+
(p) => p.key?.name === "scriptInput" || p.key?.value === "scriptInput"
|
|
666
|
+
);
|
|
667
|
+
if (scriptInputProperty) {
|
|
668
|
+
const scriptInput = scriptInputProperty.value;
|
|
669
|
+
if (scriptInput.type === "ObjectExpression") {
|
|
670
|
+
const srcProperty = scriptInput.properties.find(
|
|
671
|
+
(p) => p.key?.name === "src" || p.key?.value === "src"
|
|
672
|
+
);
|
|
673
|
+
if (srcProperty) {
|
|
674
|
+
s.overwrite(srcProperty.value.start, srcProperty.value.end, `'${url}'`);
|
|
675
|
+
if (integrityHash)
|
|
676
|
+
s.appendLeft(scriptInput.end - 1, integrityProps);
|
|
677
|
+
} else {
|
|
678
|
+
s.appendRight(scriptInput.end - 1, `, src: '${url}'${integrityProps}`);
|
|
679
|
+
}
|
|
438
680
|
}
|
|
681
|
+
} else {
|
|
682
|
+
s.appendRight(node.arguments[0].start + 1, ` scriptInput: { src: '${url}'${integrityProps} }, `);
|
|
439
683
|
}
|
|
440
684
|
} else {
|
|
441
|
-
s.
|
|
685
|
+
s.overwrite(node.callee.end, node.end, `({ scriptInput: { src: '${url}'${integrityProps} } })`);
|
|
442
686
|
}
|
|
443
|
-
} else {
|
|
444
|
-
s.appendRight(node.callee.end, `({ scriptInput: { src: '${url}'${integrityProps} } })`);
|
|
445
687
|
}
|
|
446
|
-
}
|
|
688
|
+
});
|
|
447
689
|
}
|
|
448
690
|
}
|
|
449
691
|
}
|
|
450
692
|
}
|
|
693
|
+
});
|
|
694
|
+
for (const op of deferredOps) {
|
|
695
|
+
await op();
|
|
451
696
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
};
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
};
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
const isStackblitz = provider === "stackblitz";
|
|
465
|
-
async function promptToInstall(name, installCommand, options) {
|
|
466
|
-
if (await resolvePackageJSON(name).catch(() => null))
|
|
467
|
-
return true;
|
|
468
|
-
logger$1.info(`Package ${name} is missing`);
|
|
469
|
-
if (isCI)
|
|
470
|
-
return false;
|
|
471
|
-
if (options.prompt === true || options.prompt !== false && !isStackblitz) {
|
|
472
|
-
const confirm = await logger$1.prompt(`Do you want to install ${name} package?`, {
|
|
473
|
-
type: "confirm",
|
|
474
|
-
name: "confirm",
|
|
475
|
-
initial: true
|
|
476
|
-
});
|
|
477
|
-
if (!confirm)
|
|
478
|
-
return false;
|
|
479
|
-
}
|
|
480
|
-
logger$1.info(`Installing ${name}...`);
|
|
481
|
-
try {
|
|
482
|
-
await installCommand();
|
|
483
|
-
logger$1.success(`Installed ${name}`);
|
|
484
|
-
return true;
|
|
485
|
-
} catch (err) {
|
|
486
|
-
logger$1.error(err);
|
|
487
|
-
return false;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
const installPrompts = /* @__PURE__ */ new Set();
|
|
491
|
-
function installNuxtModule(name, options) {
|
|
492
|
-
if (installPrompts.has(name))
|
|
493
|
-
return;
|
|
494
|
-
installPrompts.add(name);
|
|
495
|
-
const nuxt = tryUseNuxt();
|
|
496
|
-
if (!nuxt)
|
|
497
|
-
return;
|
|
498
|
-
return promptToInstall(name, async () => {
|
|
499
|
-
const { runCommand } = await import(String("nuxi"));
|
|
500
|
-
await runCommand("module", ["add", name, "--cwd", nuxt.options.rootDir]);
|
|
501
|
-
}, { rootDir: nuxt.options.rootDir, searchPaths: nuxt.options.modulesDir, ...options });
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
function NuxtScriptsCheckScripts() {
|
|
505
|
-
return createUnplugin(() => {
|
|
506
|
-
return {
|
|
507
|
-
name: "nuxt-scripts:check-scripts",
|
|
508
|
-
transformInclude(id) {
|
|
509
|
-
return isVue(id, { type: ["script"] });
|
|
510
|
-
},
|
|
511
|
-
async transform(code) {
|
|
512
|
-
if (!code.includes("useScript"))
|
|
513
|
-
return;
|
|
514
|
-
const ast = this.parse(code);
|
|
515
|
-
let nameNode;
|
|
516
|
-
let errorNode;
|
|
517
|
-
walk(ast, {
|
|
518
|
-
enter(_node) {
|
|
519
|
-
if (_node.type === "VariableDeclaration" && _node.declarations?.[0]?.id?.type === "ObjectPattern") {
|
|
520
|
-
const objPattern = _node.declarations[0]?.id;
|
|
521
|
-
for (const property of objPattern.properties) {
|
|
522
|
-
if (property.type === "Property" && property.key.type === "Identifier" && property.key.name === "$script" && property.value.type === "Identifier") {
|
|
523
|
-
nameNode = _node;
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
if (nameNode) {
|
|
528
|
-
let sequence = _node.type === "SequenceExpression" ? _node : null;
|
|
529
|
-
let assignmentExpression;
|
|
530
|
-
if (_node.type === "VariableDeclaration") {
|
|
531
|
-
if (_node.declarations[0]?.init?.type === "SequenceExpression") {
|
|
532
|
-
sequence = _node.declarations[0]?.init;
|
|
533
|
-
assignmentExpression = _node.declarations[0]?.init?.expressions?.[0];
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
if (sequence && !assignmentExpression) {
|
|
537
|
-
assignmentExpression = sequence.expressions[0]?.type === "AssignmentExpression" ? sequence.expressions[0] : null;
|
|
538
|
-
}
|
|
539
|
-
if (assignmentExpression) {
|
|
540
|
-
const right = assignmentExpression?.right;
|
|
541
|
-
if (right.callee?.name === "_withAsyncContext") {
|
|
542
|
-
if (right.arguments[0]?.body?.name === "$script" || right.arguments[0]?.body?.callee?.object?.name === "$script") {
|
|
543
|
-
errorNode = nameNode;
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
}
|
|
697
|
+
if (s.hasChanged()) {
|
|
698
|
+
return {
|
|
699
|
+
code: s.toString(),
|
|
700
|
+
map: s.generateMap({ includeContent: true, source: id })
|
|
701
|
+
};
|
|
548
702
|
}
|
|
549
|
-
});
|
|
550
|
-
if (errorNode) {
|
|
551
|
-
return this.error(new Error("You can't use a top-level await on $script as it will never resolve."));
|
|
552
703
|
}
|
|
553
704
|
}
|
|
554
705
|
};
|
|
@@ -596,6 +747,7 @@ export {}`;
|
|
|
596
747
|
function templateTriggerResolver(defaultScriptOptions) {
|
|
597
748
|
const needsIdleTimeout = defaultScriptOptions?.trigger && typeof defaultScriptOptions.trigger === "object" && "idleTimeout" in defaultScriptOptions.trigger;
|
|
598
749
|
const needsInteraction = defaultScriptOptions?.trigger && typeof defaultScriptOptions.trigger === "object" && "interaction" in defaultScriptOptions.trigger;
|
|
750
|
+
const needsServiceWorker = defaultScriptOptions?.trigger && typeof defaultScriptOptions.trigger === "object" && "serviceWorker" in defaultScriptOptions.trigger;
|
|
599
751
|
const imports = [];
|
|
600
752
|
if (needsIdleTimeout) {
|
|
601
753
|
imports.push(`import { useScriptTriggerIdleTimeout } from '#nuxt-scripts/composables/useScriptTriggerIdleTimeout'`);
|
|
@@ -603,11 +755,15 @@ function templateTriggerResolver(defaultScriptOptions) {
|
|
|
603
755
|
if (needsInteraction) {
|
|
604
756
|
imports.push(`import { useScriptTriggerInteraction } from '#nuxt-scripts/composables/useScriptTriggerInteraction'`);
|
|
605
757
|
}
|
|
758
|
+
if (needsServiceWorker) {
|
|
759
|
+
imports.push(`import { useScriptTriggerServiceWorker } from '#nuxt-scripts/composables/useScriptTriggerServiceWorker'`);
|
|
760
|
+
}
|
|
606
761
|
return [
|
|
607
762
|
...imports,
|
|
608
763
|
`export function resolveTrigger(trigger) {`,
|
|
609
764
|
needsIdleTimeout ? ` if ('idleTimeout' in trigger) return useScriptTriggerIdleTimeout({ timeout: trigger.idleTimeout })` : "",
|
|
610
765
|
needsInteraction ? ` if ('interaction' in trigger) return useScriptTriggerInteraction({ events: trigger.interaction })` : "",
|
|
766
|
+
needsServiceWorker ? ` if ('serviceWorker' in trigger) return useScriptTriggerServiceWorker()` : "",
|
|
611
767
|
` return null`,
|
|
612
768
|
`}`
|
|
613
769
|
].filter(Boolean).join("\n");
|
|
@@ -624,6 +780,9 @@ function resolveTriggerForTemplate(trigger) {
|
|
|
624
780
|
if ("interaction" in trigger) {
|
|
625
781
|
return `useScriptTriggerInteraction({ events: ${JSON.stringify(trigger.interaction)} })`;
|
|
626
782
|
}
|
|
783
|
+
if ("serviceWorker" in trigger) {
|
|
784
|
+
return `useScriptTriggerServiceWorker()`;
|
|
785
|
+
}
|
|
627
786
|
}
|
|
628
787
|
return null;
|
|
629
788
|
}
|
|
@@ -634,27 +793,37 @@ function templatePlugin(config, registry) {
|
|
|
634
793
|
}
|
|
635
794
|
const imports = [];
|
|
636
795
|
const inits = [];
|
|
796
|
+
const resolvedRegistryKeys = [];
|
|
637
797
|
let needsIdleTimeoutImport = false;
|
|
638
798
|
let needsInteractionImport = false;
|
|
799
|
+
let needsServiceWorkerImport = false;
|
|
639
800
|
for (const [k, c] of Object.entries(config.registry || {})) {
|
|
640
|
-
const importDefinition = registry.find((i) => i.import.name === `
|
|
801
|
+
const importDefinition = registry.find((i) => i.import.name.toLowerCase() === `usescript${k.toLowerCase()}`);
|
|
641
802
|
if (importDefinition) {
|
|
803
|
+
resolvedRegistryKeys.push(k);
|
|
642
804
|
imports.unshift(`import { ${importDefinition.import.name} } from '${importDefinition.import.from}'`);
|
|
643
|
-
const args = (typeof c !== "object" ? {} : c) || {};
|
|
644
805
|
if (c === "mock") {
|
|
645
|
-
|
|
646
|
-
} else if (Array.isArray(c) && c.length === 2
|
|
647
|
-
const
|
|
806
|
+
inits.push(`const ${k} = ${importDefinition.import.name}({ scriptOptions: { trigger: 'manual', skipValidation: true } })`);
|
|
807
|
+
} else if (Array.isArray(c) && c.length === 2) {
|
|
808
|
+
const input = c[0] || {};
|
|
809
|
+
const scriptOptions = { ...c[1] };
|
|
810
|
+
const triggerResolved = resolveTriggerForTemplate(scriptOptions?.trigger);
|
|
648
811
|
if (triggerResolved) {
|
|
649
|
-
|
|
650
|
-
if (
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
if (triggerResolved.includes("
|
|
812
|
+
scriptOptions.trigger = "__TRIGGER_PLACEHOLDER__";
|
|
813
|
+
if (triggerResolved.includes("useScriptTriggerIdleTimeout"))
|
|
814
|
+
needsIdleTimeoutImport = true;
|
|
815
|
+
if (triggerResolved.includes("useScriptTriggerInteraction"))
|
|
816
|
+
needsInteractionImport = true;
|
|
817
|
+
if (triggerResolved.includes("useScriptTriggerServiceWorker"))
|
|
818
|
+
needsServiceWorkerImport = true;
|
|
655
819
|
}
|
|
820
|
+
const args = { ...input, scriptOptions };
|
|
821
|
+
const argsJson = triggerResolved ? JSON.stringify(args).replace(/"__TRIGGER_PLACEHOLDER__"/g, triggerResolved) : JSON.stringify(args);
|
|
822
|
+
inits.push(`const ${k} = ${importDefinition.import.name}(${argsJson})`);
|
|
823
|
+
} else {
|
|
824
|
+
const args = (typeof c !== "object" ? {} : c) || {};
|
|
825
|
+
inits.push(`const ${k} = ${importDefinition.import.name}(${JSON.stringify(args)})`);
|
|
656
826
|
}
|
|
657
|
-
inits.push(`const ${k} = ${importDefinition.import.name}(${JSON.stringify(args).replace(/"__TRIGGER_(.*?)__"/g, "$1")})`);
|
|
658
827
|
}
|
|
659
828
|
}
|
|
660
829
|
for (const [k, c] of Object.entries(config.globals || {})) {
|
|
@@ -664,20 +833,30 @@ function templatePlugin(config, registry) {
|
|
|
664
833
|
const options = c[1];
|
|
665
834
|
const triggerResolved = resolveTriggerForTemplate(options?.trigger);
|
|
666
835
|
if (triggerResolved) {
|
|
667
|
-
if (triggerResolved.includes("useScriptTriggerIdleTimeout"))
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
836
|
+
if (triggerResolved.includes("useScriptTriggerIdleTimeout"))
|
|
837
|
+
needsIdleTimeoutImport = true;
|
|
838
|
+
if (triggerResolved.includes("useScriptTriggerInteraction"))
|
|
839
|
+
needsInteractionImport = true;
|
|
840
|
+
if (triggerResolved.includes("useScriptTriggerServiceWorker"))
|
|
841
|
+
needsServiceWorkerImport = true;
|
|
842
|
+
const resolvedOptions = { ...options, trigger: "__TRIGGER_PLACEHOLDER__" };
|
|
843
|
+
const optionsJson = JSON.stringify(resolvedOptions).replace(/"__TRIGGER_PLACEHOLDER__"/g, triggerResolved);
|
|
844
|
+
inits.push(`const ${k} = useScript(${JSON.stringify({ key: k, ...typeof c[0] === "string" ? { src: c[0] } : c[0] })}, { ...${optionsJson}, use: () => ({ ${k}: window.${k} }) })`);
|
|
671
845
|
} else {
|
|
672
846
|
inits.push(`const ${k} = useScript(${JSON.stringify({ key: k, ...typeof c[0] === "string" ? { src: c[0] } : c[0] })}, { ...${JSON.stringify(c[1])}, use: () => ({ ${k}: window.${k} }) })`);
|
|
673
847
|
}
|
|
674
848
|
} else if (typeof c === "object" && c !== null) {
|
|
675
849
|
const triggerResolved = resolveTriggerForTemplate(c.trigger);
|
|
676
850
|
if (triggerResolved) {
|
|
677
|
-
if (triggerResolved.includes("useScriptTriggerIdleTimeout"))
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
851
|
+
if (triggerResolved.includes("useScriptTriggerIdleTimeout"))
|
|
852
|
+
needsIdleTimeoutImport = true;
|
|
853
|
+
if (triggerResolved.includes("useScriptTriggerInteraction"))
|
|
854
|
+
needsInteractionImport = true;
|
|
855
|
+
if (triggerResolved.includes("useScriptTriggerServiceWorker"))
|
|
856
|
+
needsServiceWorkerImport = true;
|
|
857
|
+
const resolvedOptions = { ...c, trigger: "__TRIGGER_PLACEHOLDER__" };
|
|
858
|
+
const argsJson = JSON.stringify({ key: k, ...resolvedOptions }).replace(/"__TRIGGER_PLACEHOLDER__"/g, triggerResolved);
|
|
859
|
+
inits.push(`const ${k} = useScript(${argsJson}, { use: () => ({ ${k}: window.${k} }) })`);
|
|
681
860
|
} else {
|
|
682
861
|
inits.push(`const ${k} = useScript(${JSON.stringify({ key: k, ...c })}, { use: () => ({ ${k}: window.${k} }) })`);
|
|
683
862
|
}
|
|
@@ -690,6 +869,9 @@ function templatePlugin(config, registry) {
|
|
|
690
869
|
if (needsInteractionImport) {
|
|
691
870
|
triggerImports.push(`import { useScriptTriggerInteraction } from '#nuxt-scripts/composables/useScriptTriggerInteraction'`);
|
|
692
871
|
}
|
|
872
|
+
if (needsServiceWorkerImport) {
|
|
873
|
+
triggerImports.push(`import { useScriptTriggerServiceWorker } from '#nuxt-scripts/composables/useScriptTriggerServiceWorker'`);
|
|
874
|
+
}
|
|
693
875
|
return [
|
|
694
876
|
`import { useScript } from '#nuxt-scripts/composables/useScript'`,
|
|
695
877
|
`import { defineNuxtPlugin } from 'nuxt/app'`,
|
|
@@ -702,12 +884,78 @@ function templatePlugin(config, registry) {
|
|
|
702
884
|
` parallel: true,`,
|
|
703
885
|
` setup() {`,
|
|
704
886
|
...inits.map((i) => ` ${i}`),
|
|
705
|
-
` return { provide: {
|
|
887
|
+
` return { provide: { scripts: { ${[...Object.keys(config.globals || {}), ...resolvedRegistryKeys].join(", ")} } } }`,
|
|
706
888
|
` }`,
|
|
707
889
|
`})`
|
|
708
890
|
].join("\n");
|
|
709
891
|
}
|
|
710
892
|
|
|
893
|
+
const SELF_CLOSING_SCRIPT_RE = /<((?:Script[A-Z]|script-)\w[\w-]*)\b([^>]*?)\/\s*>/g;
|
|
894
|
+
function fixSelfClosingScriptComponents(nuxt) {
|
|
895
|
+
function expandTags(content) {
|
|
896
|
+
SELF_CLOSING_SCRIPT_RE.lastIndex = 0;
|
|
897
|
+
if (!SELF_CLOSING_SCRIPT_RE.test(content))
|
|
898
|
+
return null;
|
|
899
|
+
SELF_CLOSING_SCRIPT_RE.lastIndex = 0;
|
|
900
|
+
return content.replace(SELF_CLOSING_SCRIPT_RE, (_, tag, attrs) => `<${tag}${attrs.trimEnd()}></${tag}>`);
|
|
901
|
+
}
|
|
902
|
+
function fixFile(filePath) {
|
|
903
|
+
if (!existsSync(filePath))
|
|
904
|
+
return;
|
|
905
|
+
const content = readFileSync(filePath, "utf-8");
|
|
906
|
+
const fixed = expandTags(content);
|
|
907
|
+
if (fixed)
|
|
908
|
+
nuxt.vfs[filePath] = fixed;
|
|
909
|
+
}
|
|
910
|
+
function scanDir(dir) {
|
|
911
|
+
if (!existsSync(dir))
|
|
912
|
+
return;
|
|
913
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
914
|
+
const fullPath = resolve(dir, entry.name);
|
|
915
|
+
if (entry.isDirectory())
|
|
916
|
+
scanDir(fullPath);
|
|
917
|
+
else if (entry.name.endsWith(".vue"))
|
|
918
|
+
fixFile(fullPath);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
const pagesDirs = /* @__PURE__ */ new Set();
|
|
922
|
+
for (const layer of nuxt.options._layers) {
|
|
923
|
+
pagesDirs.add(resolve(
|
|
924
|
+
layer.config.srcDir,
|
|
925
|
+
layer.config.dir?.pages || "pages"
|
|
926
|
+
));
|
|
927
|
+
}
|
|
928
|
+
for (const dir of pagesDirs) scanDir(dir);
|
|
929
|
+
if (nuxt.options.dev) {
|
|
930
|
+
nuxt.hook("builder:watch", (_event, relativePath) => {
|
|
931
|
+
if (!relativePath.endsWith(".vue"))
|
|
932
|
+
return;
|
|
933
|
+
for (const layer of nuxt.options._layers) {
|
|
934
|
+
const fullPath = resolve(layer.config.srcDir, relativePath);
|
|
935
|
+
for (const dir of pagesDirs) {
|
|
936
|
+
if (fullPath.startsWith(`${dir}/`)) {
|
|
937
|
+
fixFile(fullPath);
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
const PARTYTOWN_FORWARDS = {
|
|
946
|
+
googleAnalytics: ["dataLayer.push", "gtag"],
|
|
947
|
+
plausible: ["plausible"],
|
|
948
|
+
fathom: ["fathom", "fathom.trackEvent", "fathom.trackPageview"],
|
|
949
|
+
umami: ["umami", "umami.track"],
|
|
950
|
+
matomo: ["_paq.push"],
|
|
951
|
+
segment: ["analytics", "analytics.track", "analytics.page", "analytics.identify"],
|
|
952
|
+
metaPixel: ["fbq"],
|
|
953
|
+
xPixel: ["twq"],
|
|
954
|
+
tiktokPixel: ["ttq.track", "ttq.page", "ttq.identify"],
|
|
955
|
+
snapchatPixel: ["snaptr"],
|
|
956
|
+
redditPixel: ["rdt"],
|
|
957
|
+
cloudflareWebAnalytics: ["__cfBeacon"]
|
|
958
|
+
};
|
|
711
959
|
const module$1 = defineNuxtModule({
|
|
712
960
|
meta: {
|
|
713
961
|
name: "@nuxt/scripts",
|
|
@@ -717,6 +965,7 @@ const module$1 = defineNuxtModule({
|
|
|
717
965
|
}
|
|
718
966
|
},
|
|
719
967
|
defaults: {
|
|
968
|
+
firstParty: true,
|
|
720
969
|
defaultScriptOptions: {
|
|
721
970
|
trigger: "onNuxtReady"
|
|
722
971
|
},
|
|
@@ -772,13 +1021,57 @@ const module$1 = defineNuxtModule({
|
|
|
772
1021
|
config.registry
|
|
773
1022
|
);
|
|
774
1023
|
}
|
|
1024
|
+
if (config.defaultScriptOptions?.bundle !== void 0) {
|
|
1025
|
+
logger.warn(
|
|
1026
|
+
"`scripts.defaultScriptOptions.bundle` is deprecated. Use `scripts.firstParty: true` instead. First-party mode is now enabled by default."
|
|
1027
|
+
);
|
|
1028
|
+
}
|
|
1029
|
+
const staticPresets = ["static", "github-pages", "cloudflare-pages-static"];
|
|
1030
|
+
const preset = process.env.NITRO_PRESET || "";
|
|
1031
|
+
const isStaticPreset = staticPresets.includes(preset);
|
|
1032
|
+
const firstPartyEnabled = !!config.firstParty;
|
|
1033
|
+
const firstPartyPrefix = typeof config.firstParty === "object" ? config.firstParty.prefix : void 0;
|
|
1034
|
+
const firstPartyCollectPrefix = typeof config.firstParty === "object" ? config.firstParty.collectPrefix || "/_proxy" : "/_proxy";
|
|
1035
|
+
const firstPartyPrivacy = typeof config.firstParty === "object" ? config.firstParty.privacy : void 0;
|
|
1036
|
+
const assetsPrefix = firstPartyPrefix || config.assets?.prefix || "/_scripts";
|
|
1037
|
+
if (config.partytown?.length) {
|
|
1038
|
+
config.registry = config.registry || {};
|
|
1039
|
+
const requiredForwards = [];
|
|
1040
|
+
for (const scriptKey of config.partytown) {
|
|
1041
|
+
const forwards = PARTYTOWN_FORWARDS[scriptKey];
|
|
1042
|
+
if (forwards) {
|
|
1043
|
+
requiredForwards.push(...forwards);
|
|
1044
|
+
} else if (import.meta.dev) {
|
|
1045
|
+
logger.warn(`[partytown] "${scriptKey}" has no known Partytown forwards configured. It may not work correctly or may require manual forward configuration.`);
|
|
1046
|
+
}
|
|
1047
|
+
const reg = config.registry;
|
|
1048
|
+
const existing = reg[scriptKey];
|
|
1049
|
+
if (Array.isArray(existing)) {
|
|
1050
|
+
existing[1] = { ...existing[1], partytown: true };
|
|
1051
|
+
} else if (existing && typeof existing === "object" && existing !== true && existing !== "mock") {
|
|
1052
|
+
reg[scriptKey] = [existing, { partytown: true }];
|
|
1053
|
+
} else if (existing === true || existing === "mock") {
|
|
1054
|
+
reg[scriptKey] = [{}, { partytown: true }];
|
|
1055
|
+
} else {
|
|
1056
|
+
reg[scriptKey] = [{}, { partytown: true }];
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
if (requiredForwards.length && hasNuxtModule("@nuxtjs/partytown")) {
|
|
1060
|
+
const partytownConfig = nuxt.options.partytown || {};
|
|
1061
|
+
const existingForwards = partytownConfig.forward || [];
|
|
1062
|
+
const newForwards = [.../* @__PURE__ */ new Set([...existingForwards, ...requiredForwards])];
|
|
1063
|
+
nuxt.options.partytown = { ...partytownConfig, forward: newForwards };
|
|
1064
|
+
logger.info(`[partytown] Auto-configured forwards: ${requiredForwards.join(", ")}`);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
775
1067
|
const composables = [
|
|
776
1068
|
"useScript",
|
|
777
1069
|
"useScriptEventPage",
|
|
778
1070
|
"useScriptTriggerConsent",
|
|
779
1071
|
"useScriptTriggerElement",
|
|
780
1072
|
"useScriptTriggerIdleTimeout",
|
|
781
|
-
"useScriptTriggerInteraction"
|
|
1073
|
+
"useScriptTriggerInteraction",
|
|
1074
|
+
"useScriptTriggerServiceWorker"
|
|
782
1075
|
];
|
|
783
1076
|
for (const composable of composables) {
|
|
784
1077
|
addImports({
|
|
@@ -792,12 +1085,60 @@ const module$1 = defineNuxtModule({
|
|
|
792
1085
|
path: await resolvePath("./runtime/components"),
|
|
793
1086
|
pathPrefix: false
|
|
794
1087
|
});
|
|
1088
|
+
fixSelfClosingScriptComponents(nuxt);
|
|
795
1089
|
addTemplate({
|
|
796
1090
|
filename: "nuxt-scripts-trigger-resolver.mjs",
|
|
797
1091
|
getContents() {
|
|
798
1092
|
return templateTriggerResolver(config.defaultScriptOptions);
|
|
799
1093
|
}
|
|
800
1094
|
});
|
|
1095
|
+
logger.debug("[nuxt-scripts] First-party config:", { firstPartyEnabled, firstPartyPrivacy, firstPartyCollectPrefix });
|
|
1096
|
+
let interceptRules = [];
|
|
1097
|
+
if (firstPartyEnabled) {
|
|
1098
|
+
addPluginTemplate({
|
|
1099
|
+
filename: "nuxt-scripts-intercept.client.mjs",
|
|
1100
|
+
getContents() {
|
|
1101
|
+
const rulesJson = JSON.stringify(interceptRules);
|
|
1102
|
+
return `export default defineNuxtPlugin({
|
|
1103
|
+
name: 'nuxt-scripts:intercept',
|
|
1104
|
+
enforce: 'pre',
|
|
1105
|
+
setup() {
|
|
1106
|
+
const rules = ${rulesJson};
|
|
1107
|
+
const origBeacon = typeof navigator !== 'undefined' && navigator.sendBeacon
|
|
1108
|
+
? navigator.sendBeacon.bind(navigator)
|
|
1109
|
+
: () => false;
|
|
1110
|
+
const origFetch = globalThis.fetch.bind(globalThis);
|
|
1111
|
+
|
|
1112
|
+
function rewriteUrl(url) {
|
|
1113
|
+
try {
|
|
1114
|
+
const parsed = new URL(url, location.origin);
|
|
1115
|
+
for (const rule of rules) {
|
|
1116
|
+
if (parsed.hostname === rule.pattern || parsed.hostname.endsWith('.' + rule.pattern)) {
|
|
1117
|
+
if (rule.pathPrefix && !parsed.pathname.startsWith(rule.pathPrefix)) continue;
|
|
1118
|
+
const path = rule.pathPrefix ? parsed.pathname.slice(rule.pathPrefix.length) : parsed.pathname;
|
|
1119
|
+
return location.origin + rule.target + (path.startsWith('/') ? '' : '/') + path + parsed.search;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
} catch {}
|
|
1123
|
+
return url;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
globalThis.__nuxtScripts = {
|
|
1127
|
+
sendBeacon: (url, data) => origBeacon(rewriteUrl(url), data),
|
|
1128
|
+
fetch: (url, opts) => origFetch(typeof url === 'string' ? rewriteUrl(url) : url, opts),
|
|
1129
|
+
};
|
|
1130
|
+
},
|
|
1131
|
+
})
|
|
1132
|
+
`;
|
|
1133
|
+
}
|
|
1134
|
+
});
|
|
1135
|
+
const proxyHandlerPath = await resolvePath("./runtime/server/proxy-handler");
|
|
1136
|
+
logger.debug("[nuxt-scripts] Registering proxy handler:", `${firstPartyCollectPrefix}/**`, "->", proxyHandlerPath);
|
|
1137
|
+
addServerHandler({
|
|
1138
|
+
route: `${firstPartyCollectPrefix}/**`,
|
|
1139
|
+
handler: proxyHandlerPath
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
801
1142
|
const scripts = await registry(resolvePath);
|
|
802
1143
|
for (const script of scripts) {
|
|
803
1144
|
if (script.import?.name) {
|
|
@@ -825,6 +1166,79 @@ const module$1 = defineNuxtModule({
|
|
|
825
1166
|
});
|
|
826
1167
|
}
|
|
827
1168
|
const { renderedScript } = setupPublicAssetStrategy(config.assets);
|
|
1169
|
+
if (firstPartyEnabled) {
|
|
1170
|
+
const proxyConfigs = getAllProxyConfigs(firstPartyCollectPrefix);
|
|
1171
|
+
const registryKeys = Object.keys(config.registry || {});
|
|
1172
|
+
const neededRoutes = {};
|
|
1173
|
+
const routePrivacyOverrides = {};
|
|
1174
|
+
const unsupportedScripts = [];
|
|
1175
|
+
for (const key of registryKeys) {
|
|
1176
|
+
const script = registryScriptsWithImport.find((s) => s.import.name.toLowerCase() === `usescript${key.toLowerCase()}`);
|
|
1177
|
+
const proxyKey = script?.proxy || void 0;
|
|
1178
|
+
if (proxyKey) {
|
|
1179
|
+
const proxyConfig = proxyConfigs[proxyKey];
|
|
1180
|
+
if (proxyConfig?.routes) {
|
|
1181
|
+
Object.assign(neededRoutes, proxyConfig.routes);
|
|
1182
|
+
for (const routePath of Object.keys(proxyConfig.routes)) {
|
|
1183
|
+
routePrivacyOverrides[routePath] = proxyConfig.privacy;
|
|
1184
|
+
}
|
|
1185
|
+
} else {
|
|
1186
|
+
unsupportedScripts.push(key);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
if (config.registry?.posthog && typeof config.registry.posthog === "object") {
|
|
1191
|
+
const phConfig = config.registry.posthog;
|
|
1192
|
+
if (!phConfig.apiHost) {
|
|
1193
|
+
const region = phConfig.region || "us";
|
|
1194
|
+
phConfig.apiHost = region === "eu" ? `${firstPartyCollectPrefix}/ph-eu` : `${firstPartyCollectPrefix}/ph`;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
if (unsupportedScripts.length && nuxt.options.dev) {
|
|
1198
|
+
logger.warn(
|
|
1199
|
+
`First-party mode is enabled but these scripts don't support it yet: ${unsupportedScripts.join(", ")}.
|
|
1200
|
+
They will load directly from third-party servers. Request support at https://github.com/nuxt/scripts/issues`
|
|
1201
|
+
);
|
|
1202
|
+
}
|
|
1203
|
+
interceptRules = routesToInterceptRules(neededRoutes);
|
|
1204
|
+
const flatRoutes = {};
|
|
1205
|
+
for (const [path, config2] of Object.entries(neededRoutes)) {
|
|
1206
|
+
flatRoutes[path] = config2.proxy;
|
|
1207
|
+
}
|
|
1208
|
+
nuxt.options.runtimeConfig["nuxt-scripts-proxy"] = {
|
|
1209
|
+
routes: flatRoutes,
|
|
1210
|
+
privacy: firstPartyPrivacy,
|
|
1211
|
+
// undefined = use per-script defaults, set = global override
|
|
1212
|
+
routePrivacy: routePrivacyOverrides
|
|
1213
|
+
// per-script privacy from registry
|
|
1214
|
+
};
|
|
1215
|
+
if (Object.keys(neededRoutes).length) {
|
|
1216
|
+
if (nuxt.options.dev) {
|
|
1217
|
+
const routeCount = Object.keys(neededRoutes).length;
|
|
1218
|
+
const scriptsCount = registryKeys.length;
|
|
1219
|
+
const privacyLabel = firstPartyPrivacy === void 0 ? "per-script" : typeof firstPartyPrivacy === "boolean" ? firstPartyPrivacy ? "anonymize" : "passthrough" : "custom";
|
|
1220
|
+
logger.success(`First-party mode enabled for ${scriptsCount} script(s), ${routeCount} proxy route(s) configured (privacy: ${privacyLabel})`);
|
|
1221
|
+
if (logger.level >= 4) {
|
|
1222
|
+
for (const [path, config2] of Object.entries(neededRoutes)) {
|
|
1223
|
+
logger.debug(` ${path} \u2192 ${config2.proxy}`);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
if (isStaticPreset) {
|
|
1229
|
+
logger.warn(
|
|
1230
|
+
`First-party collection endpoints require a server runtime (detected: ${preset || "static"}).
|
|
1231
|
+
Scripts will be bundled, but collection requests will not be proxied.
|
|
1232
|
+
|
|
1233
|
+
Options:
|
|
1234
|
+
1. Configure platform rewrites (Vercel, Netlify, Cloudflare)
|
|
1235
|
+
2. Switch to server-rendered mode (ssr: true)
|
|
1236
|
+
3. Disable with firstParty: false
|
|
1237
|
+
|
|
1238
|
+
See: https://scripts.nuxt.com/docs/guides/first-party#static-hosting`
|
|
1239
|
+
);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
828
1242
|
const moduleInstallPromises = /* @__PURE__ */ new Map();
|
|
829
1243
|
addBuildPlugin(NuxtScriptsCheckScripts(), {
|
|
830
1244
|
dev: true
|
|
@@ -832,12 +1246,14 @@ const module$1 = defineNuxtModule({
|
|
|
832
1246
|
addBuildPlugin(NuxtScriptBundleTransformer({
|
|
833
1247
|
scripts: registryScriptsWithImport,
|
|
834
1248
|
registryConfig: nuxt.options.runtimeConfig.public.scripts,
|
|
835
|
-
defaultBundle: config.defaultScriptOptions?.bundle,
|
|
1249
|
+
defaultBundle: firstPartyEnabled || config.defaultScriptOptions?.bundle,
|
|
1250
|
+
firstPartyEnabled,
|
|
1251
|
+
firstPartyCollectPrefix,
|
|
836
1252
|
moduleDetected(module) {
|
|
837
1253
|
if (nuxt.options.dev && module !== "@nuxt/scripts" && !moduleInstallPromises.has(module) && !hasNuxtModule(module))
|
|
838
1254
|
moduleInstallPromises.set(module, () => installNuxtModule(module));
|
|
839
1255
|
},
|
|
840
|
-
assetsBaseURL:
|
|
1256
|
+
assetsBaseURL: assetsPrefix,
|
|
841
1257
|
fallbackOnSrcOnBundleFail: config.assets?.fallbackOnSrcOnBundleFail,
|
|
842
1258
|
fetchOptions: config.assets?.fetchOptions,
|
|
843
1259
|
cacheMaxAge: config.assets?.cacheMaxAge,
|
|
@@ -856,8 +1272,29 @@ const module$1 = defineNuxtModule({
|
|
|
856
1272
|
handler: await resolvePath("./runtime/server/google-static-maps-proxy")
|
|
857
1273
|
});
|
|
858
1274
|
}
|
|
859
|
-
|
|
1275
|
+
addServerHandler({
|
|
1276
|
+
route: "/api/_scripts/x-embed",
|
|
1277
|
+
handler: await resolvePath("./runtime/server/x-embed")
|
|
1278
|
+
});
|
|
1279
|
+
addServerHandler({
|
|
1280
|
+
route: "/api/_scripts/x-embed-image",
|
|
1281
|
+
handler: await resolvePath("./runtime/server/x-embed-image")
|
|
1282
|
+
});
|
|
1283
|
+
addServerHandler({
|
|
1284
|
+
route: "/api/_scripts/instagram-embed",
|
|
1285
|
+
handler: await resolvePath("./runtime/server/instagram-embed")
|
|
1286
|
+
});
|
|
1287
|
+
addServerHandler({
|
|
1288
|
+
route: "/api/_scripts/instagram-embed-image",
|
|
1289
|
+
handler: await resolvePath("./runtime/server/instagram-embed-image")
|
|
1290
|
+
});
|
|
1291
|
+
addServerHandler({
|
|
1292
|
+
route: "/api/_scripts/instagram-embed-asset",
|
|
1293
|
+
handler: await resolvePath("./runtime/server/instagram-embed-asset")
|
|
1294
|
+
});
|
|
1295
|
+
if (nuxt.options.dev) {
|
|
860
1296
|
setupDevToolsUI(config, resolvePath);
|
|
1297
|
+
}
|
|
861
1298
|
}
|
|
862
1299
|
});
|
|
863
1300
|
|