vinext 0.1.3 → 0.1.4
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/dist/build/client-build-config.d.ts +11 -2
- package/dist/build/client-build-config.js +17 -6
- package/dist/build/prerender.js +1 -0
- package/dist/client/pages-router-link-navigation.d.ts +33 -7
- package/dist/client/pages-router-link-navigation.js +32 -2
- package/dist/client/vinext-next-data.js +2 -0
- package/dist/config/config-matchers.d.ts +11 -1
- package/dist/config/config-matchers.js +14 -2
- package/dist/config/tsconfig-paths.js +14 -1
- package/dist/deploy.js +20 -13
- package/dist/entries/app-rsc-entry.js +3 -2
- package/dist/entries/pages-client-entry.js +14 -13
- package/dist/entries/pages-server-entry.js +6 -26
- package/dist/index.js +217 -40
- package/dist/plugins/dynamic-preload-metadata.js +2 -4
- package/dist/plugins/fonts.js +5 -4
- package/dist/plugins/strip-server-exports.d.ts +9 -7
- package/dist/plugins/strip-server-exports.js +493 -46
- package/dist/routing/app-route-graph.js +2 -2
- package/dist/server/app-browser-action-result.js +1 -1
- package/dist/server/app-browser-entry.js +8 -1
- package/dist/server/app-browser-navigation-controller.d.ts +1 -1
- package/dist/server/app-browser-state.d.ts +1 -1
- package/dist/server/app-browser-state.js +19 -11
- package/dist/server/app-browser-visible-commit.d.ts +1 -1
- package/dist/server/app-pages-bridge.d.ts +5 -1
- package/dist/server/app-pages-bridge.js +5 -13
- package/dist/server/app-rsc-handler.d.ts +3 -0
- package/dist/server/app-rsc-handler.js +51 -15
- package/dist/server/app-rsc-route-matching.js +6 -2
- package/dist/server/app-server-action-execution.js +5 -2
- package/dist/server/app-ssr-entry.js +1 -29
- package/dist/server/before-interactive-head.d.ts +17 -0
- package/dist/server/before-interactive-head.js +35 -0
- package/dist/server/csp.js +1 -4
- package/dist/server/dev-server.js +81 -36
- package/dist/server/middleware-matcher.js +12 -3
- package/dist/server/middleware-runtime.d.ts +3 -4
- package/dist/server/middleware-runtime.js +2 -0
- package/dist/server/navigation-planner.d.ts +3 -12
- package/dist/server/navigation-planner.js +24 -0
- package/dist/server/navigation-trace.d.ts +2 -1
- package/dist/server/navigation-trace.js +1 -0
- package/dist/server/operation-token.d.ts +40 -0
- package/dist/server/operation-token.js +85 -0
- package/dist/server/pages-data-route.d.ts +1 -1
- package/dist/server/pages-data-route.js +7 -4
- package/dist/server/pages-dev-module-url.d.ts +4 -0
- package/dist/server/pages-dev-module-url.js +15 -0
- package/dist/server/pages-document-initial-props.d.ts +4 -15
- package/dist/server/pages-document-initial-props.js +27 -56
- package/dist/server/pages-i18n.js +2 -2
- package/dist/server/pages-page-data.js +3 -1
- package/dist/server/pages-page-handler.js +3 -1
- package/dist/server/pages-page-response.d.ts +2 -0
- package/dist/server/pages-page-response.js +4 -4
- package/dist/server/pages-readiness.js +1 -1
- package/dist/server/pages-request-pipeline.d.ts +7 -7
- package/dist/server/pages-request-pipeline.js +63 -21
- package/dist/server/prod-server.d.ts +3 -1
- package/dist/server/prod-server.js +41 -10
- package/dist/server/static-file-cache.js +16 -4
- package/dist/shims/before-interactive-context.d.ts +14 -3
- package/dist/shims/document.d.ts +15 -20
- package/dist/shims/document.js +5 -8
- package/dist/shims/image.js +9 -2
- package/dist/shims/internal/pages-data-fetch-dedup.d.ts +6 -7
- package/dist/shims/internal/pages-data-fetch-dedup.js +67 -14
- package/dist/shims/internal/pages-data-target.js +1 -1
- package/dist/shims/link.js +37 -16
- package/dist/shims/metadata.js +4 -4
- package/dist/shims/navigation.js +2 -0
- package/dist/shims/router.d.ts +6 -2
- package/dist/shims/router.js +99 -20
- package/dist/shims/script.js +8 -4
- package/dist/utils/has-trailing-comma.d.ts +24 -0
- package/dist/utils/has-trailing-comma.js +62 -0
- package/dist/utils/text-stream.d.ts +1 -1
- package/dist/utils/text-stream.js +2 -2
- package/dist/utils/vite-version.d.ts +12 -1
- package/dist/utils/vite-version.js +9 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { buildViteResolveExtensions, createValidFileMatcher, findFileWithExts, n
|
|
|
5
5
|
import { apiRouter, invalidateRouteCache, matchRoute, pagesRouter } from "./routing/pages-router.js";
|
|
6
6
|
import { INTERNAL_HEADERS, NEXTJS_DEPLOYMENT_ID_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_MW_CTX_HEADER, VINEXT_TIMING_HEADER } from "./server/headers.js";
|
|
7
7
|
import { normalizePath as normalizePath$1 } from "./server/normalize-path.js";
|
|
8
|
-
import { proxyExternalRequest } from "./config/config-matchers.js";
|
|
8
|
+
import { matchesRewriteSource, proxyExternalRequest } from "./config/config-matchers.js";
|
|
9
9
|
import { filterInternalHeaders, isOpenRedirectShaped, normalizeTrailingSlash } from "./server/request-pipeline.js";
|
|
10
10
|
import { findMiddlewareFile, runMiddleware } from "./server/middleware.js";
|
|
11
11
|
import { generateServerEntry } from "./entries/pages-server-entry.js";
|
|
@@ -31,7 +31,7 @@ import { planRouteClassificationInjection } from "./build/route-classification-i
|
|
|
31
31
|
import { PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD } from "./shims/constants.js";
|
|
32
32
|
import { resolveAssetsDir } from "./utils/asset-prefix.js";
|
|
33
33
|
import { RESOLVED_VIRTUAL_GOOGLE_FONTS, VIRTUAL_GOOGLE_FONTS, createGoogleFontsPlugin, createLocalFontsPlugin, generateGoogleFontsVirtualModule, parseStaticObjectLiteral } from "./plugins/fonts.js";
|
|
34
|
-
import { getViteMajorVersion } from "./utils/vite-version.js";
|
|
34
|
+
import { getDepOptimizeNodeEnvOptions, getViteMajorVersion, serializeViteDefine } from "./utils/vite-version.js";
|
|
35
35
|
import { createRscCompatibilityId, findNextConfigPath, loadNextConfig, resolveNextConfig, resolveNextConfigInput } from "./config/next-config.js";
|
|
36
36
|
import { isNextDataPathname, parseNextDataPathname } from "./server/pages-data-route.js";
|
|
37
37
|
import { precompressAssets } from "./build/precompress.js";
|
|
@@ -63,7 +63,7 @@ import { resolvePostcssStringPlugins } from "./plugins/postcss.js";
|
|
|
63
63
|
import { buildSassPreprocessorOptions, createSassAwareFileSystemLoader, createSassTildeImporter } from "./plugins/sass.js";
|
|
64
64
|
import { createClientAssetFileNames, createClientCodeSplittingConfig, createClientFileNameConfig, createClientManualChunks, createClientOutputConfig, createRscFrameworkChunkOutputConfig, getBuildBundlerOptions, getClientTreeshakeConfigForVite, withBuildBundlerOptions } from "./build/client-build-config.js";
|
|
65
65
|
import { markCssUrlAssetReferences, restoreDedupedCssAssetReferences } from "./build/css-url-assets.js";
|
|
66
|
-
import { stripServerExports } from "./plugins/strip-server-exports.js";
|
|
66
|
+
import { hasExportAllCandidate, hasServerExportCandidate, stripServerExports, validatePageExports } from "./plugins/strip-server-exports.js";
|
|
67
67
|
import { removeConsoleCalls } from "./plugins/remove-console.js";
|
|
68
68
|
import { createImportMetaUrlPlugin } from "./plugins/import-meta-url.js";
|
|
69
69
|
import { createRequireContextPlugin } from "./plugins/require-context.js";
|
|
@@ -78,7 +78,7 @@ import fs from "node:fs";
|
|
|
78
78
|
import path from "node:path";
|
|
79
79
|
import { loadEnv, parseAst, transformWithOxc } from "vite";
|
|
80
80
|
import { pathToFileURL } from "node:url";
|
|
81
|
-
import { randomBytes, randomUUID } from "node:crypto";
|
|
81
|
+
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
82
82
|
import commonjs from "vite-plugin-commonjs";
|
|
83
83
|
import MagicString from "magic-string";
|
|
84
84
|
import tsconfigPaths from "vite-tsconfig-paths";
|
|
@@ -162,6 +162,19 @@ function resolveTsconfigPathCandidate(candidate) {
|
|
|
162
162
|
for (const item of candidates) if (fs.existsSync(item) && fs.statSync(item).isFile()) return item;
|
|
163
163
|
return null;
|
|
164
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* Normalize a tsconfig `extends` field into a list of specifier strings.
|
|
167
|
+
*
|
|
168
|
+
* TypeScript 5.0+ allows `extends` to be either a string or an array of
|
|
169
|
+
* strings. Matches Next.js's handling in
|
|
170
|
+
* packages/next/src/build/next-config-ts/transpile-config.ts, where parents
|
|
171
|
+
* are iterated in order and later entries override earlier ones.
|
|
172
|
+
*/
|
|
173
|
+
function normalizeTsconfigExtends(extendsField) {
|
|
174
|
+
if (typeof extendsField === "string") return [extendsField];
|
|
175
|
+
if (Array.isArray(extendsField)) return extendsField.filter((value) => typeof value === "string");
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
165
178
|
function resolveTsconfigExtends(configPath, specifier) {
|
|
166
179
|
const fromDir = path.dirname(configPath);
|
|
167
180
|
if (specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("\\")) return resolveTsconfigPathCandidate(path.resolve(fromDir, specifier));
|
|
@@ -221,9 +234,12 @@ function loadTsconfigPathAliases(configPath, projectRoot, seen = /* @__PURE__ */
|
|
|
221
234
|
}
|
|
222
235
|
if (!parsed) return {};
|
|
223
236
|
let aliases = {};
|
|
224
|
-
|
|
225
|
-
const extendedPath = resolveTsconfigExtends(normalizedPath,
|
|
226
|
-
if (extendedPath) aliases =
|
|
237
|
+
for (const extendsSpecifier of normalizeTsconfigExtends(parsed.extends)) {
|
|
238
|
+
const extendedPath = resolveTsconfigExtends(normalizedPath, extendsSpecifier);
|
|
239
|
+
if (extendedPath) aliases = {
|
|
240
|
+
...aliases,
|
|
241
|
+
...loadTsconfigPathAliases(extendedPath, projectRoot, seen)
|
|
242
|
+
};
|
|
227
243
|
}
|
|
228
244
|
const compilerOptions = isUnknownRecord(parsed.compilerOptions) ? parsed.compilerOptions : null;
|
|
229
245
|
const pathsConfig = compilerOptions && isUnknownRecord(compilerOptions.paths) ? compilerOptions.paths : null;
|
|
@@ -288,6 +304,14 @@ const RESOLVED_INSTRUMENTATION_CLIENT = `\0${VIRTUAL_INSTRUMENTATION_CLIENT}.mjs
|
|
|
288
304
|
/** Image file extensions handled by the vinext:image-imports plugin.
|
|
289
305
|
* Shared between the Rolldown hook filter and the transform handler regex. */
|
|
290
306
|
const IMAGE_EXTS = "png|jpe?g|gif|webp|avif|svg|ico|bmp|tiff?";
|
|
307
|
+
function createStaticImageAsset(imagePath) {
|
|
308
|
+
const source = fs.readFileSync(imagePath);
|
|
309
|
+
const extension = path.extname(imagePath);
|
|
310
|
+
return {
|
|
311
|
+
fileName: `media/${path.basename(imagePath, extension)}.${createHash("sha256").update(source).digest("hex").slice(0, 8)}${extension}`,
|
|
312
|
+
source
|
|
313
|
+
};
|
|
314
|
+
}
|
|
291
315
|
/**
|
|
292
316
|
* Absolute path to vinext's shims directory, with a trailing slash. Normalized
|
|
293
317
|
* to forward slashes because it is prefix-matched against Vite module ids (which
|
|
@@ -394,6 +418,7 @@ function vinext(options = {}) {
|
|
|
394
418
|
const viteMajorVersion = getViteMajorVersion();
|
|
395
419
|
let root;
|
|
396
420
|
let pagesDir;
|
|
421
|
+
let canonicalPagesDir;
|
|
397
422
|
let appDir;
|
|
398
423
|
let hasAppDir = false;
|
|
399
424
|
let hasPagesDir = false;
|
|
@@ -413,6 +438,19 @@ function vinext(options = {}) {
|
|
|
413
438
|
let rscClassificationManifest = null;
|
|
414
439
|
const shimsDir = path.resolve(__dirname, "shims");
|
|
415
440
|
const canonicalize = (p) => tryRealpathSync(p) ?? p;
|
|
441
|
+
const pageTransformCanonicalPaths = /* @__PURE__ */ new Map();
|
|
442
|
+
const canonicalizePageTransformPath = (modulePath) => {
|
|
443
|
+
const cached = pageTransformCanonicalPaths.get(modulePath);
|
|
444
|
+
if (cached) return cached;
|
|
445
|
+
const canonicalPath = canonicalize(modulePath);
|
|
446
|
+
pageTransformCanonicalPaths.set(modulePath, canonicalPath);
|
|
447
|
+
return canonicalPath;
|
|
448
|
+
};
|
|
449
|
+
const isWithinPagesDirectory = (modulePath) => modulePath === pagesDir || modulePath.startsWith(`${pagesDir}/`) || modulePath === canonicalPagesDir || modulePath.startsWith(`${canonicalPagesDir}/`);
|
|
450
|
+
const isApiPage = (canonicalId) => {
|
|
451
|
+
const relativePath = fileMatcher.stripExtension(canonicalId.slice(canonicalPagesDir.length));
|
|
452
|
+
return relativePath === "/api" || relativePath.startsWith("/api/");
|
|
453
|
+
};
|
|
416
454
|
const dynamicShimPaths = new Set([
|
|
417
455
|
resolveShimModulePath(shimsDir, "headers"),
|
|
418
456
|
resolveShimModulePath(shimsDir, "server"),
|
|
@@ -481,6 +519,9 @@ function vinext(options = {}) {
|
|
|
481
519
|
});
|
|
482
520
|
}
|
|
483
521
|
const imageImportDimCache = /* @__PURE__ */ new Map();
|
|
522
|
+
const staticImageAssets = /* @__PURE__ */ new Map();
|
|
523
|
+
const staticImageImportsByModule = /* @__PURE__ */ new Map();
|
|
524
|
+
const writtenStaticImageFiles = /* @__PURE__ */ new Set();
|
|
484
525
|
let mdxDelegate = null;
|
|
485
526
|
let mdxDelegatePromise = null;
|
|
486
527
|
let hasUserMdxPlugin = false;
|
|
@@ -572,6 +613,7 @@ function vinext(options = {}) {
|
|
|
572
613
|
else baseDir = root;
|
|
573
614
|
}
|
|
574
615
|
pagesDir = path.posix.join(baseDir, "pages");
|
|
616
|
+
canonicalPagesDir = canonicalize(pagesDir);
|
|
575
617
|
appDir = path.posix.join(baseDir, "app");
|
|
576
618
|
hasPagesDir = fs.existsSync(pagesDir);
|
|
577
619
|
hasAppDir = !options.disableAppRouter && fs.existsSync(appDir);
|
|
@@ -605,7 +647,10 @@ function vinext(options = {}) {
|
|
|
605
647
|
clientInjectModule = instrumentationClientInjects.length ? generateInstrumentationClientInjectModule(instrumentationClientInjects, instrumentationClientPath, INSTRUMENTATION_CLIENT_EMPTY_MODULE) : null;
|
|
606
648
|
if (env?.command === "build") await writeRouteTypes();
|
|
607
649
|
const defines = getNextPublicEnvDefines();
|
|
608
|
-
|
|
650
|
+
const userNodeEnvDefine = config.define?.["process.env.NODE_ENV"];
|
|
651
|
+
const hasUserNodeEnvDefine = Object.hasOwn(config.define ?? {}, "process.env.NODE_ENV");
|
|
652
|
+
const nodeEnvDefine = hasUserNodeEnvDefine ? serializeViteDefine(userNodeEnvDefine) : JSON.stringify(resolvedNodeEnv);
|
|
653
|
+
if (!hasUserNodeEnvDefine) defines["process.env.NODE_ENV"] = nodeEnvDefine;
|
|
609
654
|
for (const [key, value] of Object.entries(nextConfig.env)) {
|
|
610
655
|
if (key === "NODE_ENV") continue;
|
|
611
656
|
defines[`process.env.${key}`] = JSON.stringify(value);
|
|
@@ -836,10 +881,15 @@ function vinext(options = {}) {
|
|
|
836
881
|
if (shimBase !== void 0) return resolveShimModulePath(shimsDir, shimBase);
|
|
837
882
|
}
|
|
838
883
|
};
|
|
884
|
+
const depOptimizeNodeEnvOptions = getDepOptimizeNodeEnvOptions(viteMajorVersion, nodeEnvDefine);
|
|
839
885
|
viteConfig.optimizeDeps = {
|
|
840
886
|
exclude: mergeOptimizeDepsExclude(incomingExclude, VINEXT_OPTIMIZE_DEPS_EXCLUDE, ["@tailwindcss/oxide"]),
|
|
841
887
|
...incomingInclude.length > 0 ? { include: incomingInclude } : {},
|
|
842
|
-
|
|
888
|
+
...depOptimizeNodeEnvOptions,
|
|
889
|
+
rolldownOptions: {
|
|
890
|
+
...depOptimizeNodeEnvOptions.rolldownOptions,
|
|
891
|
+
plugins: [depOptimizeAliasPlugin]
|
|
892
|
+
}
|
|
843
893
|
};
|
|
844
894
|
const pagesOptimizeEntries = !hasAppDir ? [...hasPagesDir ? [toRelativeFileEntry(root, pagesDir) + "/**/*.{tsx,ts,jsx,js}"] : [], ...[instrumentationPath, instrumentationClientPath].flatMap((entry) => entry ? [toRelativeFileEntry(root, entry)] : [])] : [];
|
|
845
895
|
if (hasAppDir) {
|
|
@@ -861,7 +911,9 @@ function vinext(options = {}) {
|
|
|
861
911
|
} },
|
|
862
912
|
optimizeDeps: {
|
|
863
913
|
exclude: mergeOptimizeDepsExclude(incomingExclude, VINEXT_OPTIMIZE_DEPS_EXCLUDE),
|
|
864
|
-
entries: optimizeEntries
|
|
914
|
+
entries: optimizeEntries,
|
|
915
|
+
include: [...new Set([...incomingInclude, "react-server-dom-webpack/static.edge"])],
|
|
916
|
+
...depOptimizeNodeEnvOptions
|
|
865
917
|
},
|
|
866
918
|
build: {
|
|
867
919
|
outDir: options.rscOutDir ?? "dist/server",
|
|
@@ -878,7 +930,8 @@ function vinext(options = {}) {
|
|
|
878
930
|
} },
|
|
879
931
|
optimizeDeps: {
|
|
880
932
|
exclude: mergeOptimizeDepsExclude(incomingExclude, VINEXT_OPTIMIZE_DEPS_EXCLUDE, ["ipaddr.js"], userSsrExternal === true ? SSR_EXTERNAL_REACT_ENTRIES : []),
|
|
881
|
-
entries: optimizeEntries
|
|
933
|
+
entries: optimizeEntries,
|
|
934
|
+
...depOptimizeNodeEnvOptions
|
|
882
935
|
},
|
|
883
936
|
build: {
|
|
884
937
|
outDir: options.ssrOutDir ?? "dist/server/ssr",
|
|
@@ -951,7 +1004,10 @@ function vinext(options = {}) {
|
|
|
951
1004
|
],
|
|
952
1005
|
noExternal: true
|
|
953
1006
|
},
|
|
954
|
-
optimizeDeps: {
|
|
1007
|
+
optimizeDeps: {
|
|
1008
|
+
exclude: ["ipaddr.js"],
|
|
1009
|
+
...depOptimizeNodeEnvOptions
|
|
1010
|
+
},
|
|
955
1011
|
build: {
|
|
956
1012
|
outDir: "dist/server",
|
|
957
1013
|
...withBuildBundlerOptions(viteMajorVersion, {
|
|
@@ -1435,6 +1491,51 @@ function vinext(options = {}) {
|
|
|
1435
1491
|
});
|
|
1436
1492
|
installDevStackSourcemapMiddleware(server);
|
|
1437
1493
|
return () => {
|
|
1494
|
+
const viteFilesystemMiddlewares = server.middlewares.stack.filter(({ handle }) => {
|
|
1495
|
+
const name = typeof handle === "function" ? handle.name : "";
|
|
1496
|
+
return name === "viteServePublicMiddleware" || name === "viteServeStaticMiddleware";
|
|
1497
|
+
}).map(({ handle }) => handle).filter((handle) => typeof handle === "function");
|
|
1498
|
+
const serveRewrittenViteFilesystemRoute = async (req, res, requestPathname, stagedHeaders) => {
|
|
1499
|
+
const originalUrl = req.url;
|
|
1500
|
+
const originalStatusCode = res.statusCode;
|
|
1501
|
+
const originalStatusMessage = res.statusMessage;
|
|
1502
|
+
const originalHeaders = res.getHeaders();
|
|
1503
|
+
req.url = requestPathname;
|
|
1504
|
+
for (const [key, value] of Object.entries(stagedHeaders)) res.setHeader(key, value);
|
|
1505
|
+
const restore = () => {
|
|
1506
|
+
req.url = originalUrl;
|
|
1507
|
+
res.statusCode = originalStatusCode;
|
|
1508
|
+
res.statusMessage = originalStatusMessage;
|
|
1509
|
+
for (const key of Object.keys(res.getHeaders())) res.removeHeader(key);
|
|
1510
|
+
for (const [key, value] of Object.entries(originalHeaders)) if (value !== void 0) res.setHeader(key, value);
|
|
1511
|
+
};
|
|
1512
|
+
try {
|
|
1513
|
+
for (const middleware of viteFilesystemMiddlewares) if (await new Promise((resolve, reject) => {
|
|
1514
|
+
let settled = false;
|
|
1515
|
+
const settle = (value, error) => {
|
|
1516
|
+
if (settled) return;
|
|
1517
|
+
settled = true;
|
|
1518
|
+
res.off("finish", onServed);
|
|
1519
|
+
res.off("close", onServed);
|
|
1520
|
+
if (error) reject(error);
|
|
1521
|
+
else resolve(value);
|
|
1522
|
+
};
|
|
1523
|
+
const onServed = () => settle("served");
|
|
1524
|
+
res.once("finish", onServed);
|
|
1525
|
+
res.once("close", onServed);
|
|
1526
|
+
middleware(req, res, (error) => settle("next", error));
|
|
1527
|
+
if (res.writableEnded) settle("served");
|
|
1528
|
+
}) === "served") {
|
|
1529
|
+
req.url = originalUrl;
|
|
1530
|
+
return true;
|
|
1531
|
+
}
|
|
1532
|
+
} catch (error) {
|
|
1533
|
+
restore();
|
|
1534
|
+
throw error;
|
|
1535
|
+
}
|
|
1536
|
+
restore();
|
|
1537
|
+
return false;
|
|
1538
|
+
};
|
|
1438
1539
|
if (instrumentationPath && !hasAppDir) runInstrumentation(getPagesRunner(), instrumentationPath).catch((err) => {
|
|
1439
1540
|
console.error("[vinext] Instrumentation error:", err);
|
|
1440
1541
|
});
|
|
@@ -1556,6 +1657,7 @@ function vinext(options = {}) {
|
|
|
1556
1657
|
return;
|
|
1557
1658
|
}
|
|
1558
1659
|
}
|
|
1660
|
+
if (hasCloudflarePlugin) return next();
|
|
1559
1661
|
let isDataReq = false;
|
|
1560
1662
|
if (isNextDataPathname(pathname)) {
|
|
1561
1663
|
const devBuildId = nextConfig?.buildId ?? process.env.__VINEXT_BUILD_ID ?? "development";
|
|
@@ -1575,10 +1677,17 @@ function vinext(options = {}) {
|
|
|
1575
1677
|
return;
|
|
1576
1678
|
}
|
|
1577
1679
|
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1680
|
+
const filePathMatchesRewrite = [
|
|
1681
|
+
...nextConfig?.rewrites.beforeFiles ?? [],
|
|
1682
|
+
...nextConfig?.rewrites.afterFiles ?? [],
|
|
1683
|
+
...nextConfig?.rewrites.fallback ?? []
|
|
1684
|
+
].some((rewrite) => matchesRewriteSource(pathname, rewrite, {
|
|
1685
|
+
basePath: bp,
|
|
1686
|
+
hadBasePath: true
|
|
1687
|
+
}));
|
|
1688
|
+
if (pathname.includes(".") && !pathname.endsWith(".html") && !filePathMatchesRewrite) return next();
|
|
1580
1689
|
const rawHeaders = new Headers(Object.fromEntries(Object.entries(req.headers).filter(([k, v]) => v !== void 0 && !k.startsWith(":")).map(([k, v]) => [k, Array.isArray(v) ? v.join(", ") : String(v)])));
|
|
1581
|
-
const isDataRequest =
|
|
1690
|
+
const isDataRequest = isDataReq;
|
|
1582
1691
|
const nodeRequestHeaders = filterInternalHeaders(rawHeaders);
|
|
1583
1692
|
for (const header of INTERNAL_HEADERS) delete req.headers[header];
|
|
1584
1693
|
for (const header of VINEXT_INTERNAL_HEADERS) delete req.headers[header];
|
|
@@ -1649,6 +1758,10 @@ function vinext(options = {}) {
|
|
|
1649
1758
|
externalInit.duplex = "half";
|
|
1650
1759
|
}
|
|
1651
1760
|
return proxyExternalRequest(new Request(new URL(url, requestOrigin), externalInit), externalUrl);
|
|
1761
|
+
},
|
|
1762
|
+
serveFilesystemRoute: async (requestPathname, stagedHeaders, phase) => {
|
|
1763
|
+
if (phase === "direct" || req.method !== "GET" && req.method !== "HEAD" || requestPathname === "/" || requestPathname === "/api" || requestPathname.startsWith("/api/")) return false;
|
|
1764
|
+
return serveRewrittenViteFilesystemRoute(req, res, requestPathname, stagedHeaders);
|
|
1652
1765
|
}
|
|
1653
1766
|
});
|
|
1654
1767
|
if (pipelineResult.type === "response") {
|
|
@@ -1713,6 +1826,42 @@ function vinext(options = {}) {
|
|
|
1713
1826
|
};
|
|
1714
1827
|
}
|
|
1715
1828
|
},
|
|
1829
|
+
{
|
|
1830
|
+
name: "vinext:validate-page-exports",
|
|
1831
|
+
transform: { handler(code, id) {
|
|
1832
|
+
if (this.environment?.name !== "client") return null;
|
|
1833
|
+
if (!hasPagesDir || id.startsWith("\0") || !hasExportAllCandidate(code)) return null;
|
|
1834
|
+
const modulePath = stripViteModuleQuery(id);
|
|
1835
|
+
if (!isWithinPagesDirectory(modulePath)) return null;
|
|
1836
|
+
const canonicalId = canonicalizePageTransformPath(modulePath);
|
|
1837
|
+
if (!isWithinPagesDirectory(canonicalId)) return null;
|
|
1838
|
+
if (!fileMatcher.isPageFile(canonicalId)) return null;
|
|
1839
|
+
if (isApiPage(canonicalId)) return null;
|
|
1840
|
+
validatePageExports(code);
|
|
1841
|
+
return null;
|
|
1842
|
+
} }
|
|
1843
|
+
},
|
|
1844
|
+
{
|
|
1845
|
+
name: "vinext:strip-server-exports",
|
|
1846
|
+
transform: { handler(code, id) {
|
|
1847
|
+
if (this.environment?.name !== "client") return null;
|
|
1848
|
+
if (!hasPagesDir || id.startsWith("\0") || !hasServerExportCandidate(code)) return null;
|
|
1849
|
+
const modulePath = stripViteModuleQuery(id);
|
|
1850
|
+
if (!isWithinPagesDirectory(modulePath)) return null;
|
|
1851
|
+
const canonicalId = canonicalizePageTransformPath(modulePath);
|
|
1852
|
+
if (!isWithinPagesDirectory(canonicalId)) return null;
|
|
1853
|
+
if (!fileMatcher.isPageFile(canonicalId)) return null;
|
|
1854
|
+
const relativePath = canonicalId.slice(canonicalPagesDir.length);
|
|
1855
|
+
if (isApiPage(canonicalId)) return null;
|
|
1856
|
+
if (/^\/(?:_app|_document|_error)(?:\.[^/]*)?$/.test(relativePath)) return null;
|
|
1857
|
+
const result = stripServerExports(code);
|
|
1858
|
+
if (!result) return null;
|
|
1859
|
+
return {
|
|
1860
|
+
code: result,
|
|
1861
|
+
map: null
|
|
1862
|
+
};
|
|
1863
|
+
} }
|
|
1864
|
+
},
|
|
1716
1865
|
{
|
|
1717
1866
|
name: "vinext:validate-server-only-client-imports",
|
|
1718
1867
|
transform: {
|
|
@@ -1729,26 +1878,6 @@ function vinext(options = {}) {
|
|
|
1729
1878
|
}
|
|
1730
1879
|
}
|
|
1731
1880
|
},
|
|
1732
|
-
{
|
|
1733
|
-
name: "vinext:strip-server-exports",
|
|
1734
|
-
transform: {
|
|
1735
|
-
filter: { id: /\.(tsx?|jsx?|mjs)$/ },
|
|
1736
|
-
handler(code, id) {
|
|
1737
|
-
if (this.environment?.name !== "client") return null;
|
|
1738
|
-
if (!hasPagesDir) return null;
|
|
1739
|
-
if (!id.startsWith(pagesDir)) return null;
|
|
1740
|
-
const relativePath = id.slice(pagesDir.length);
|
|
1741
|
-
if (relativePath.startsWith("/api/") || relativePath === "/api") return null;
|
|
1742
|
-
if (/\/_(?:app|document|error)\b/.test(relativePath)) return null;
|
|
1743
|
-
const result = stripServerExports(code);
|
|
1744
|
-
if (!result) return null;
|
|
1745
|
-
return {
|
|
1746
|
-
code: result,
|
|
1747
|
-
map: null
|
|
1748
|
-
};
|
|
1749
|
-
}
|
|
1750
|
-
}
|
|
1751
|
-
},
|
|
1752
1881
|
{
|
|
1753
1882
|
name: "vinext:remove-console",
|
|
1754
1883
|
apply: "build",
|
|
@@ -1792,16 +1921,36 @@ function vinext(options = {}) {
|
|
|
1792
1921
|
name: "vinext:image-imports",
|
|
1793
1922
|
enforce: "pre",
|
|
1794
1923
|
_dimCache: imageImportDimCache,
|
|
1924
|
+
buildStart() {
|
|
1925
|
+
imageImportDimCache.clear();
|
|
1926
|
+
staticImageAssets.clear();
|
|
1927
|
+
},
|
|
1928
|
+
watchChange(id) {
|
|
1929
|
+
imageImportDimCache.delete(id);
|
|
1930
|
+
staticImageAssets.delete(id);
|
|
1931
|
+
staticImageImportsByModule.delete(id);
|
|
1932
|
+
},
|
|
1795
1933
|
resolveId: {
|
|
1796
|
-
filter: { id: /\?vinext-meta$/ },
|
|
1934
|
+
filter: { id: /\?vinext-(?:image-url|meta)$/ },
|
|
1797
1935
|
handler(source, _importer) {
|
|
1798
|
-
if (
|
|
1799
|
-
return `\0vinext-image-meta:${source.
|
|
1936
|
+
if (source.endsWith("?vinext-image-url")) return `\0vinext-image-url:${source.slice(0, -17)}`;
|
|
1937
|
+
if (source.endsWith("?vinext-meta")) return `\0vinext-image-meta:${source.slice(0, -12)}`;
|
|
1938
|
+
return null;
|
|
1800
1939
|
}
|
|
1801
1940
|
},
|
|
1802
1941
|
async load(id) {
|
|
1942
|
+
if (id.startsWith("\0vinext-image-url:")) {
|
|
1943
|
+
const imagePath = id.replace("\0vinext-image-url:", "");
|
|
1944
|
+
this.addWatchFile(imagePath);
|
|
1945
|
+
if (this.environment.config.command === "serve") return `import url from ${JSON.stringify(imagePath + "?url")}; export default url;`;
|
|
1946
|
+
const asset = createStaticImageAsset(imagePath);
|
|
1947
|
+
staticImageAssets.set(imagePath, asset);
|
|
1948
|
+
const builtFileName = `${resolveAssetsDir(nextConfig.assetPrefix)}/${asset.fileName}`;
|
|
1949
|
+
return `export default ${JSON.stringify(renderVinextBuiltUrl(builtFileName, nextConfig.assetPrefix, nextConfig.deploymentId))};`;
|
|
1950
|
+
}
|
|
1803
1951
|
if (!id.startsWith("\0vinext-image-meta:")) return null;
|
|
1804
1952
|
const imagePath = id.replace("\0vinext-image-meta:", "");
|
|
1953
|
+
this.addWatchFile(imagePath);
|
|
1805
1954
|
const cache = imageImportDimCache;
|
|
1806
1955
|
let dims = cache.get(imagePath);
|
|
1807
1956
|
if (!dims) try {
|
|
@@ -1842,6 +1991,7 @@ function vinext(options = {}) {
|
|
|
1842
1991
|
}
|
|
1843
1992
|
const s = new MagicString(code);
|
|
1844
1993
|
let hasChanges = false;
|
|
1994
|
+
const imageImports = /* @__PURE__ */ new Set();
|
|
1845
1995
|
for (const node of ast.body) {
|
|
1846
1996
|
if (node.type !== "ImportDeclaration") continue;
|
|
1847
1997
|
const importNode = node;
|
|
@@ -1857,18 +2007,45 @@ function vinext(options = {}) {
|
|
|
1857
2007
|
const dir = path.dirname(id);
|
|
1858
2008
|
const absImagePath = normalizePathSeparators(path.resolve(dir, importPath));
|
|
1859
2009
|
if (!fs.existsSync(absImagePath)) continue;
|
|
2010
|
+
imageImports.add(absImagePath);
|
|
1860
2011
|
const urlVar = `__vinext_img_url_${varName}`;
|
|
1861
2012
|
const metaVar = `__vinext_img_meta_${varName}`;
|
|
1862
|
-
const replacement = `import ${urlVar} from ${JSON.stringify(
|
|
2013
|
+
const replacement = `import ${urlVar} from ${JSON.stringify(absImagePath + "?vinext-image-url")};\nimport ${metaVar} from ${JSON.stringify(absImagePath + "?vinext-meta")};\nconst ${varName} = { src: ${urlVar}, width: ${metaVar}.width, height: ${metaVar}.height };`;
|
|
1863
2014
|
s.overwrite(importNode.start, importNode.end, replacement);
|
|
1864
2015
|
hasChanges = true;
|
|
1865
2016
|
}
|
|
1866
|
-
if (!hasChanges)
|
|
2017
|
+
if (!hasChanges) {
|
|
2018
|
+
staticImageImportsByModule.delete(id);
|
|
2019
|
+
return null;
|
|
2020
|
+
}
|
|
2021
|
+
staticImageImportsByModule.set(id, imageImports);
|
|
1867
2022
|
return {
|
|
1868
2023
|
code: s.toString(),
|
|
1869
2024
|
map: s.generateMap({ hires: "boundary" })
|
|
1870
2025
|
};
|
|
1871
2026
|
}
|
|
2027
|
+
},
|
|
2028
|
+
writeBundle: {
|
|
2029
|
+
sequential: true,
|
|
2030
|
+
order: "post",
|
|
2031
|
+
handler(outputOptions) {
|
|
2032
|
+
if (this.environment?.name !== "client") return;
|
|
2033
|
+
const clientOutDir = outputOptions.dir ? path.resolve(root, outputOptions.dir) : path.resolve(root, options.clientOutDir ?? "dist/client");
|
|
2034
|
+
const assetsDir = resolveAssetsDir(nextConfig.assetPrefix);
|
|
2035
|
+
const activeImagePaths = new Set(Array.from(staticImageImportsByModule.values()).flatMap((imports) => [...imports]));
|
|
2036
|
+
const nextWrittenFiles = /* @__PURE__ */ new Set();
|
|
2037
|
+
for (const imagePath of activeImagePaths) {
|
|
2038
|
+
if (!fs.existsSync(imagePath)) continue;
|
|
2039
|
+
const asset = staticImageAssets.get(imagePath) ?? createStaticImageAsset(imagePath);
|
|
2040
|
+
const outputPath = path.join(clientOutDir, assetsDir, asset.fileName);
|
|
2041
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
2042
|
+
fs.writeFileSync(outputPath, asset.source);
|
|
2043
|
+
nextWrittenFiles.add(outputPath);
|
|
2044
|
+
}
|
|
2045
|
+
for (const outputPath of writtenStaticImageFiles) if (!nextWrittenFiles.has(outputPath)) fs.rmSync(outputPath, { force: true });
|
|
2046
|
+
writtenStaticImageFiles.clear();
|
|
2047
|
+
for (const outputPath of nextWrittenFiles) writtenStaticImageFiles.add(outputPath);
|
|
2048
|
+
}
|
|
1872
2049
|
}
|
|
1873
2050
|
},
|
|
1874
2051
|
createGoogleFontsPlugin(_fontGoogleShimPath, _shimsDir),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isUnknownRecord } from "../utils/record.js";
|
|
2
|
+
import { hasTrailingComma } from "../utils/has-trailing-comma.js";
|
|
2
3
|
import { relativeWithinRoot, tryRealpathSync } from "../build/ssr-manifest.js";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { parseAst } from "vite";
|
|
@@ -281,15 +282,12 @@ function appendObjectProperty(output, objectNode, property) {
|
|
|
281
282
|
output.appendLeft(propertyEnd, `, ${property}`);
|
|
282
283
|
return true;
|
|
283
284
|
}
|
|
284
|
-
function stripComments(source) {
|
|
285
|
-
return source.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
|
|
286
|
-
}
|
|
287
285
|
function insertSecondOptionsArgument(output, code, callNode, firstArg, optionsLiteral) {
|
|
288
286
|
const callEnd = getNumber(callNode, "end");
|
|
289
287
|
const firstArgEnd = getNumber(firstArg, "end");
|
|
290
288
|
if (callEnd === null || firstArgEnd === null) return false;
|
|
291
289
|
const closeParen = callEnd - 1;
|
|
292
|
-
const separator =
|
|
290
|
+
const separator = hasTrailingComma(code.slice(firstArgEnd, closeParen)) ? " " : ", ";
|
|
293
291
|
output.appendLeft(closeParen, `${separator}${optionsLiteral}`);
|
|
294
292
|
return true;
|
|
295
293
|
}
|
package/dist/plugins/fonts.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { escapeRegExp } from "../utils/regex.js";
|
|
2
|
+
import { lastSignificantChar } from "../utils/has-trailing-comma.js";
|
|
2
3
|
import { buildFallbackFontFace, getFallbackFontOverrideMetrics } from "../build/google-fonts/fallback-metrics.js";
|
|
3
4
|
import { validateGoogleFontOptions } from "../build/google-fonts/validate.js";
|
|
4
5
|
import { getFontAxes } from "../build/google-fonts/get-axes.js";
|
|
@@ -552,8 +553,8 @@ function createGoogleFontsPlugin(fontGoogleShimPath, shimsDir) {
|
|
|
552
553
|
if (validatedFontStyle) internalFontProperties.push(`fontStyle: ${JSON.stringify(validatedFontStyle)}`);
|
|
553
554
|
const injectedProperties = [`_vinext: { font: { ${internalFontProperties.join(", ")} } }`];
|
|
554
555
|
const closingBrace = optionsStr.lastIndexOf("}");
|
|
555
|
-
const
|
|
556
|
-
const separator =
|
|
556
|
+
const lastChar = lastSignificantChar(optionsStr.slice(0, closingBrace));
|
|
557
|
+
const separator = lastChar === "{" || lastChar === "," ? "" : ", ";
|
|
557
558
|
const replacement = `${calleeSource}(${optionsStr.slice(0, closingBrace) + separator + injectedProperties.join(", ") + optionsStr.slice(closingBrace)})`;
|
|
558
559
|
s.overwrite(callStart, callEnd, replacement);
|
|
559
560
|
overwrittenRanges.push([callStart, callEnd]);
|
|
@@ -688,8 +689,8 @@ function createLocalFontsPlugin(shimsDir) {
|
|
|
688
689
|
if (familyPayloadInsertions.has(insertAt)) continue;
|
|
689
690
|
const optionsStr = code.slice(objRange[0], objRange[1]);
|
|
690
691
|
if (/(?:^|[,{])\s*_vinext\s*:/.test(optionsStr)) continue;
|
|
691
|
-
const
|
|
692
|
-
const separator =
|
|
692
|
+
const lastChar = lastSignificantChar(optionsStr.slice(0, -1));
|
|
693
|
+
const separator = lastChar === "{" || lastChar === "," ? "" : ", ";
|
|
693
694
|
s.appendLeft(insertAt, `${separator}_vinext: { font: { family: ${JSON.stringify(bindingName)} } }`);
|
|
694
695
|
familyPayloadInsertions.add(insertAt);
|
|
695
696
|
hasChanges = true;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
//#region src/plugins/strip-server-exports.d.ts
|
|
2
|
+
declare function hasServerExportCandidate(code: string): boolean;
|
|
3
|
+
declare function hasExportAllCandidate(code: string): boolean;
|
|
4
|
+
declare function validatePageExports(code: string): void;
|
|
2
5
|
/**
|
|
3
|
-
* Strip server-only data-fetching exports
|
|
4
|
-
*
|
|
5
|
-
* bundle. Uses Vite's parseAst (Rollup/acorn) for correct handling
|
|
6
|
-
* of all export patterns including function expressions, arrow
|
|
7
|
-
* functions with TS return types, and re-exports.
|
|
6
|
+
* Strip server-only Pages Router data-fetching exports and their unique
|
|
7
|
+
* dependency graph from browser bundles.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* Ported from Next.js:
|
|
10
|
+
* - test/unit/babel-plugin-next-ssg-transform.test.ts
|
|
11
|
+
* - crates/next-custom-transforms/src/transforms/strip_page_exports.rs
|
|
10
12
|
*/
|
|
11
13
|
declare function stripServerExports(code: string): string | null;
|
|
12
14
|
//#endregion
|
|
13
|
-
export { stripServerExports };
|
|
15
|
+
export { hasExportAllCandidate, hasServerExportCandidate, stripServerExports, validatePageExports };
|