@thomas.f/prnext 0.1.0-alpha.1
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 +54 -0
- package/build/action-exports.mjs +107 -0
- package/build/actions.mjs +214 -0
- package/build/app-config.mjs +138 -0
- package/build/app-routing.mjs +119 -0
- package/build/app-static.mjs +158 -0
- package/build/app.mjs +536 -0
- package/build/cache-components.mjs +91 -0
- package/build/cache-handlers.mjs +54 -0
- package/build/check.mjs +40 -0
- package/build/compiler.mjs +222 -0
- package/build/config.mjs +193 -0
- package/build/css-modules.mjs +114 -0
- package/build/custom-routes.mjs +363 -0
- package/build/dev-worker.mjs +18 -0
- package/build/dev.mjs +76 -0
- package/build/directory-cache.mjs +29 -0
- package/build/dynamic.mjs +125 -0
- package/build/edge.mjs +141 -0
- package/build/font-data.LICENSE.txt +25 -0
- package/build/font-data.json +1 -0
- package/build/font-files.mjs +221 -0
- package/build/fonts.mjs +131 -0
- package/build/framework-imports.mjs +17 -0
- package/build/i18n.mjs +39 -0
- package/build/images-config.mjs +62 -0
- package/build/images.mjs +86 -0
- package/build/incremental.mjs +76 -0
- package/build/index.mjs +356 -0
- package/build/loader-cache.mjs +69 -0
- package/build/metadata-images.mjs +72 -0
- package/build/metadata-routes.mjs +77 -0
- package/build/middleware.mjs +231 -0
- package/build/migrate.mjs +289 -0
- package/build/module-resolution.mjs +78 -0
- package/build/native-discovery.mjs +134 -0
- package/build/native-packages.mjs +105 -0
- package/build/npm-packages.mjs +110 -0
- package/build/og.mjs +14 -0
- package/build/page-extensions.mjs +12 -0
- package/build/passthrough-loader.cjs +4 -0
- package/build/precompress.mjs +122 -0
- package/build/scan.mjs +178 -0
- package/build/script-workers.mjs +25 -0
- package/build/server-actions-config.mjs +27 -0
- package/build/source-maps.mjs +34 -0
- package/build/standalone-config.mjs +19 -0
- package/build/standalone-runner.mjs +21 -0
- package/build/standalone-worker.mjs +5 -0
- package/build/standalone.mjs +240 -0
- package/build/static-export.mjs +93 -0
- package/build/styles.mjs +174 -0
- package/build/transform-cache.mjs +50 -0
- package/build/transform.mjs +155 -0
- package/build/turbopack-conditions.mjs +59 -0
- package/build/webpack-bridge.cjs +3 -0
- package/build/webpack-graph.mjs +256 -0
- package/build/webpack-loader.cjs +9 -0
- package/cli.mjs +210 -0
- package/compat/app-client-page.cjs +32 -0
- package/compat/app-context.cjs +40 -0
- package/compat/app-context.d.cts +20 -0
- package/compat/app-dynamic.cjs +34 -0
- package/compat/app-error-boundary.cjs +53 -0
- package/compat/app-global-error-boundary.cjs +34 -0
- package/compat/app-layout-context.cjs +27 -0
- package/compat/app-navigation-boundary.cjs +47 -0
- package/compat/app.cjs +33 -0
- package/compat/app.d.cts +9 -0
- package/compat/cache-handlers.cjs +223 -0
- package/compat/cache-life.cjs +34 -0
- package/compat/cache.cjs +99 -0
- package/compat/cache.d.cts +36 -0
- package/compat/compat/router.d.cts +2 -0
- package/compat/compat-router.cjs +7 -0
- package/compat/constants.cjs +8 -0
- package/compat/constants.d.cts +7 -0
- package/compat/cookies.cjs +129 -0
- package/compat/data-cache.cjs +389 -0
- package/compat/dist/shared/lib/app-router-context.shared-runtime.d.cts +3 -0
- package/compat/dist/shared/lib/router-context.d.cts +1 -0
- package/compat/dist/shared/lib/router-context.shared-runtime.d.cts +3 -0
- package/compat/document.cjs +73 -0
- package/compat/document.d.cts +41 -0
- package/compat/draft.cjs +28 -0
- package/compat/dynamic-bailout.cjs +13 -0
- package/compat/dynamic.cjs +119 -0
- package/compat/dynamic.d.cts +32 -0
- package/compat/error.cjs +36 -0
- package/compat/error.d.cts +15 -0
- package/compat/fetch.d.cts +10 -0
- package/compat/font/google.d.cts +1 -0
- package/compat/font/local.d.cts +2 -0
- package/compat/font-google.cjs +2 -0
- package/compat/font-google.d.cts +1944 -0
- package/compat/font-local.cjs +5 -0
- package/compat/font-local.d.cts +3 -0
- package/compat/font-types.d.cts +25 -0
- package/compat/head.cjs +180 -0
- package/compat/head.d.cts +3 -0
- package/compat/headers.cjs +89 -0
- package/compat/headers.d.cts +26 -0
- package/compat/image-config.cjs +3 -0
- package/compat/image-imports.d.ts +12 -0
- package/compat/image-shared.cjs +62 -0
- package/compat/image.cjs +64 -0
- package/compat/image.d.cts +35 -0
- package/compat/incremental-cache.cjs +186 -0
- package/compat/index.d.ts +159 -0
- package/compat/instant-samples.cjs +39 -0
- package/compat/instant.cjs +13 -0
- package/compat/link.cjs +68 -0
- package/compat/link.d.cts +17 -0
- package/compat/locale.cjs +30 -0
- package/compat/metadata.d.cts +77 -0
- package/compat/navigation-controls.cjs +27 -0
- package/compat/navigation-server.cjs +25 -0
- package/compat/navigation.cjs +52 -0
- package/compat/navigation.d.cts +28 -0
- package/compat/next-app-router-context.cjs +6 -0
- package/compat/next-router-context.cjs +3 -0
- package/compat/og.cjs +32 -0
- package/compat/og.d.cts +1 -0
- package/compat/paths.cjs +33 -0
- package/compat/preview.cjs +41 -0
- package/compat/rewrite.cjs +41 -0
- package/compat/route-request.cjs +64 -0
- package/compat/router.cjs +137 -0
- package/compat/router.d.cts +58 -0
- package/compat/script-context.cjs +5 -0
- package/compat/script-loader.cjs +135 -0
- package/compat/script.cjs +69 -0
- package/compat/script.d.cts +17 -0
- package/compat/server-primitives.cjs +109 -0
- package/compat/server.cjs +13 -0
- package/compat/server.d.cts +37 -0
- package/compat/static-generation.cjs +108 -0
- package/compat/use-cache.cjs +129 -0
- package/index.mjs +1 -0
- package/native/platforms.json +6 -0
- package/native/resolve.mjs +81 -0
- package/package.json +127 -0
- package/release/verify.mjs +59 -0
- package/runtime/action-client.mjs +19 -0
- package/runtime/action-crypto.mjs +138 -0
- package/runtime/action-reference.mjs +2 -0
- package/runtime/action-server.mjs +161 -0
- package/runtime/action-ssr.mjs +5 -0
- package/runtime/api.mjs +326 -0
- package/runtime/app-client.mjs +539 -0
- package/runtime/app-content.mjs +8 -0
- package/runtime/app-errors.mjs +12 -0
- package/runtime/app-instant.mjs +30 -0
- package/runtime/app-metadata.mjs +410 -0
- package/runtime/app-partial-model.mjs +228 -0
- package/runtime/app-partial.mjs +130 -0
- package/runtime/app-prefetch.mjs +34 -0
- package/runtime/app-recovery.mjs +87 -0
- package/runtime/app-render.mjs +544 -0
- package/runtime/app-routing-access.mjs +143 -0
- package/runtime/app-routing-context.mjs +35 -0
- package/runtime/app-routing-state.mjs +61 -0
- package/runtime/app-routing.mjs +323 -0
- package/runtime/app-segments.mjs +22 -0
- package/runtime/app-static-params.mjs +120 -0
- package/runtime/app-static.mjs +86 -0
- package/runtime/app-stream-channel.mjs +92 -0
- package/runtime/app-stream-html.mjs +279 -0
- package/runtime/build-directory.mjs +48 -0
- package/runtime/cache-arguments.mjs +33 -0
- package/runtime/cache-components-rsc.mjs +64 -0
- package/runtime/cache-request.mjs +23 -0
- package/runtime/client-navigation.mjs +40 -0
- package/runtime/dev-client.mjs +129 -0
- package/runtime/dev-file-changes.mjs +110 -0
- package/runtime/document.mjs +96 -0
- package/runtime/edge.mjs +105 -0
- package/runtime/env.mjs +68 -0
- package/runtime/fetch-cache.mjs +379 -0
- package/runtime/font-preload.mjs +4 -0
- package/runtime/http.mjs +190 -0
- package/runtime/incremental-cache.mjs +83 -0
- package/runtime/metadata-route.mjs +83 -0
- package/runtime/middleware.mjs +186 -0
- package/runtime/module-loader.mjs +21 -0
- package/runtime/navigation.mjs +16 -0
- package/runtime/og-loader.mjs +17 -0
- package/runtime/pages-client.mjs +197 -0
- package/runtime/pages-error-props.mjs +6 -0
- package/runtime/pages-errors.mjs +85 -0
- package/runtime/pages-initial-props.mjs +43 -0
- package/runtime/pages-navigation.mjs +565 -0
- package/runtime/pages-paths.mjs +80 -0
- package/runtime/pages-revalidate.mjs +33 -0
- package/runtime/partial-artifact-cache.mjs +37 -0
- package/runtime/partial-template.mjs +174 -0
- package/runtime/profile.mjs +9 -0
- package/runtime/profiles.json +47 -0
- package/runtime/render.mjs +304 -0
- package/runtime/request-transport.mjs +41 -0
- package/runtime/request-work.mjs +7 -0
- package/runtime/route-static.mjs +117 -0
- package/runtime/rsc-worker.mjs +426 -0
- package/runtime/script-html.mjs +61 -0
- package/runtime/stream-select.mjs +25 -0
- package/runtime/stream-utils.mjs +127 -0
- package/runtime/transport.mjs +108 -0
- package/runtime/watch-project.mjs +130 -0
- package/runtime/worker-artifacts.mjs +22 -0
- package/runtime/worker-metadata.mjs +31 -0
- package/runtime/worker.mjs +197 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {generateMapped} from './source-maps.mjs';
|
|
2
|
+
import { parse } from '@babel/parser';
|
|
3
|
+
import traverseModule from '@babel/traverse';
|
|
4
|
+
import generateModule from '@babel/generator';
|
|
5
|
+
import * as t from '@babel/types';
|
|
6
|
+
import { createHash } from 'node:crypto';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { cachedTransform } from './transform-cache.mjs';
|
|
9
|
+
import {frameworkPackages} from './framework-imports.mjs';
|
|
10
|
+
|
|
11
|
+
const traverse = traverseModule.default || traverseModule;
|
|
12
|
+
const generate = generateModule.default || generateModule;
|
|
13
|
+
const sources = new Set(frameworkPackages.flatMap(name => [`${name}/dynamic`, `${name}/dynamic.js`]));
|
|
14
|
+
|
|
15
|
+
function importedDynamic(binding) {
|
|
16
|
+
if (!binding) return false;
|
|
17
|
+
const declaration = binding.path;
|
|
18
|
+
if (declaration.isImportDefaultSpecifier() || declaration.isImportNamespaceSpecifier() ||
|
|
19
|
+
declaration.isImportSpecifier() && (declaration.node.imported.name ?? declaration.node.imported.value) === 'default') {
|
|
20
|
+
return sources.has(declaration.parentPath.node.source.value);
|
|
21
|
+
}
|
|
22
|
+
if (!declaration.isVariableDeclarator()) return false;
|
|
23
|
+
let value = declaration.node.init;
|
|
24
|
+
if (t.isMemberExpression(value) && propertyName(value) === 'default') value = value.object;
|
|
25
|
+
return t.isCallExpression(value) && t.isIdentifier(value.callee, { name: 'require' }) &&
|
|
26
|
+
!declaration.scope.getBinding('require') && value.arguments.length === 1 &&
|
|
27
|
+
t.isStringLiteral(value.arguments[0]) && sources.has(value.arguments[0].value);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function propertyName(node) {
|
|
31
|
+
return !node.computed && t.isIdentifier(node.key ?? node.property)
|
|
32
|
+
? (node.key ?? node.property).name : t.isStringLiteral(node.key ?? node.property) ? (node.key ?? node.property).value : undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// A spread after a property may replace it. Only erase a loader when the final
|
|
36
|
+
// ssr value is the literal false; runtime options retain their normal semantics.
|
|
37
|
+
function option(object, name) {
|
|
38
|
+
if (!object?.isObjectExpression()) return undefined;
|
|
39
|
+
for (const property of [...object.get('properties')].reverse()) {
|
|
40
|
+
if (property.isSpreadElement() || propertyName(property.node) === undefined) return undefined;
|
|
41
|
+
if (propertyName(property.node) !== name) continue;
|
|
42
|
+
return property.isObjectProperty() ? property.get('value') : name === 'loader' && property.isObjectMethod() ? property : undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function mayOverride(object, name) {
|
|
47
|
+
if (!object?.node) return false;
|
|
48
|
+
if (!object.isObjectExpression()) return true;
|
|
49
|
+
return object.node.properties.some(property => t.isSpreadElement(property) || propertyName(property) === undefined || propertyName(property) === name);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function loaderBody(loader) {
|
|
53
|
+
if (!loader?.isIdentifier()) return loader;
|
|
54
|
+
const binding = loader.scope.getBinding(loader.node.name);
|
|
55
|
+
if (!binding?.constant) return loader;
|
|
56
|
+
if (binding.path.isFunctionDeclaration()) return binding.path;
|
|
57
|
+
const initial = binding.path.isVariableDeclarator() && binding.path.get('init');
|
|
58
|
+
return initial && (initial.isArrowFunctionExpression() || initial.isFunctionExpression()) ? initial : loader;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Add shared hydration IDs without resolving, evaluating or eagerly importing loaders. */
|
|
62
|
+
export function transformDynamicImports(source, filename, { projectRoot, mode = 'browser' } = {}) {
|
|
63
|
+
if (![...sources].some(name => source.includes(name))) return source;
|
|
64
|
+
projectRoot ||= process.cwd();
|
|
65
|
+
return cachedTransform('dynamic',source,[filename,projectRoot,mode],()=>transformDynamicImportsUncached(source,filename,{projectRoot,mode}));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function transformDynamicImportsUncached(source, filename, {projectRoot,mode}) {
|
|
69
|
+
const ast = parse(source, { sourceType: 'unambiguous', sourceFilename: filename,
|
|
70
|
+
plugins: ['jsx', ...(/\.tsx?$/.test(filename) ? ['typescript'] : [])] });
|
|
71
|
+
const relative = path.relative(projectRoot || process.cwd(), filename).replaceAll(path.sep, '/');
|
|
72
|
+
let changed = false;
|
|
73
|
+
traverse(ast, {
|
|
74
|
+
CallExpression(call) {
|
|
75
|
+
let callee = call.get('callee');
|
|
76
|
+
if (callee.isMemberExpression() && propertyName(callee.node) === 'default') callee = callee.get('object');
|
|
77
|
+
if (!callee.isIdentifier() || !importedDynamic(callee.scope.getBinding(callee.node.name))) return;
|
|
78
|
+
const args = call.get('arguments');
|
|
79
|
+
if (args.length > 2 || args.some(argument => argument.isSpreadElement())) throw new Error(`next/dynamic accepts a loader and optional options object (${filename}).`);
|
|
80
|
+
if (!args.length) return;
|
|
81
|
+
const objectFirst = args[0].isObjectExpression();
|
|
82
|
+
const firstOptions = objectFirst ? args[0] : undefined;
|
|
83
|
+
const secondOptions = args[1];
|
|
84
|
+
let loader = option(secondOptions, 'loader') || option(firstOptions, 'loader') || (!objectFirst ? args[0] : undefined);
|
|
85
|
+
if (!loader?.node) return;
|
|
86
|
+
const ssr = option(secondOptions, 'ssr') || (!mayOverride(secondOptions, 'ssr') ? option(firstOptions, 'ssr') : undefined);
|
|
87
|
+
const noSSR = ssr?.isBooleanLiteral({ value: false });
|
|
88
|
+
if (noSSR && mode === 'rsc') throw new Error(`ssr: false is not allowed with next/dynamic in an App Server Component (${filename}). Move this dynamic component into a module marked 'use client'.`);
|
|
89
|
+
|
|
90
|
+
const imports = new Set();
|
|
91
|
+
const inspect = node => {
|
|
92
|
+
const value = t.isImportExpression(node) ? node.source : t.isCallExpression(node) && t.isImport(node.callee) ? node.arguments[0] : undefined;
|
|
93
|
+
if (!value) return;
|
|
94
|
+
if (t.isStringLiteral(value)) imports.add(value.value);
|
|
95
|
+
else if (t.isTemplateLiteral(value) && !value.expressions.length) imports.add(value.quasis[0].value.cooked);
|
|
96
|
+
else throw new Error(`next/dynamic import paths must be string literals (${filename}).`);
|
|
97
|
+
};
|
|
98
|
+
const body = loaderBody(loader);
|
|
99
|
+
inspect(body.node);
|
|
100
|
+
body.traverse({ CallExpression(value) { inspect(value.node); }, ImportExpression(value) { inspect(value.node); } });
|
|
101
|
+
// Custom loaders can return an already available component. They still
|
|
102
|
+
// need a stable hydration identity even when no import() is present.
|
|
103
|
+
const keys = imports.size ? [...imports] : [`loader:${generate(body.node, { compact: true, comments: false }).code}`];
|
|
104
|
+
const ids = keys.map(specifier => 'dynamic-' + createHash('sha256').update(relative + '\0' + specifier).digest('hex').slice(0, 20));
|
|
105
|
+
const generated = t.objectProperty(t.identifier('loadableGenerated'), t.objectExpression([
|
|
106
|
+
t.objectProperty(t.identifier('modules'), t.arrayExpression(ids.map(id => t.stringLiteral(id)))),
|
|
107
|
+
]));
|
|
108
|
+
|
|
109
|
+
if (noSSR && mode !== 'browser') {
|
|
110
|
+
const empty = t.arrowFunctionExpression([], t.nullLiteral(), true);
|
|
111
|
+
loader.replaceWith(loader.isObjectMethod() ? t.objectProperty(loader.node.key, empty, loader.node.computed) : empty);
|
|
112
|
+
}
|
|
113
|
+
else if (loader.isCallExpression() && (t.isImport(loader.node.callee) || imports.size)) {
|
|
114
|
+
// The legacy direct import form must not execute at module evaluation.
|
|
115
|
+
loader.replaceWith(t.arrowFunctionExpression([], loader.node));
|
|
116
|
+
}
|
|
117
|
+
const target = secondOptions || firstOptions;
|
|
118
|
+
if (target?.isObjectExpression()) target.node.properties.push(generated);
|
|
119
|
+
else if (target?.node) target.replaceWith(t.objectExpression([t.spreadElement(target.node), generated]));
|
|
120
|
+
else call.node.arguments.push(t.objectExpression([generated]));
|
|
121
|
+
changed = true;
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
return changed ? generateMapped(generate, ast, { comments: true }, source, filename) : source;
|
|
125
|
+
}
|
package/build/edge.mjs
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir, access } from 'node:fs/promises';
|
|
2
|
+
import {frameworkImportName, frameworkSubpathPattern} from './framework-imports.mjs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { builtinModules, createRequire } from 'node:module';
|
|
6
|
+
import { build } from './compiler.mjs';
|
|
7
|
+
import { parse } from '@babel/parser';
|
|
8
|
+
import traversePackage from '@babel/traverse';
|
|
9
|
+
import { cachedTransform } from './transform-cache.mjs';
|
|
10
|
+
import generatePackage from '@babel/generator';
|
|
11
|
+
import {generateMapped,sourceMapsEnabled,inlineSourceMap,extractSourceMap} from './source-maps.mjs';
|
|
12
|
+
|
|
13
|
+
const traverse = traversePackage.default || traversePackage;
|
|
14
|
+
const compat = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../compat');
|
|
15
|
+
const builtin = new Set([...builtinModules, ...builtinModules.map(name => 'node:' + name)]);
|
|
16
|
+
const trusted = new Set(['server-primitives.cjs', 'cookies.cjs', 'paths.cjs', 'locale.cjs', 'constants.cjs'].map(name => path.join(compat, name)));
|
|
17
|
+
const names = {
|
|
18
|
+
headers: ['headers', 'cookies', 'draftMode'],
|
|
19
|
+
cache: ['revalidateTag', 'revalidatePath', 'unstable_noStore'],
|
|
20
|
+
navigation: ['redirect', 'permanentRedirect', 'notFound', 'RedirectType', 'unstable_rethrow'],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function validate(source, file, reactMode) {
|
|
24
|
+
return cachedTransform('edge-validation',source,[file,reactMode],()=>validateUncached(source,file,reactMode));
|
|
25
|
+
}
|
|
26
|
+
function validateUncached(source,file,reactMode) {
|
|
27
|
+
const ast = parse(source, { sourceType: 'unambiguous', sourceFilename: file, plugins: ['jsx', ...(/\.[cm]?tsx?$/.test(file) ? ['typescript'] : [])] });
|
|
28
|
+
const edits = [];
|
|
29
|
+
const fail = message => { throw new Error(`Edge Runtime ${file}: ${message}`); };
|
|
30
|
+
if (ast.program.directives.some(item => (reactMode === 'ssr' ? ['use server', 'use cache', 'use cache: private', 'use cache: remote'] : ['use client', 'use server', 'use cache', 'use cache: private', 'use cache: remote']).includes(item.value.value))) fail('This React boundary, Server Actions or Cache Components cannot run in the Edge graph.');
|
|
31
|
+
traverse(ast, {
|
|
32
|
+
Directive(nodePath) { if (nodePath.node.value.value === 'use server' || nodePath.node.value.value.startsWith('use cache')) fail('Server Actions and Cache Components are not implemented in the Edge graph.'); },
|
|
33
|
+
UnaryExpression(nodePath) {
|
|
34
|
+
const { node } = nodePath;
|
|
35
|
+
if (node.operator === 'typeof' && node.argument.type === 'Identifier' && node.argument.name === 'require' && !nodePath.scope.hasBinding('require')) {
|
|
36
|
+
edits.push({ start: node.start, end: node.end, text: 'typeof globalThis.require' });
|
|
37
|
+
node.argument={type:'MemberExpression',object:{type:'Identifier',name:'globalThis'},property:{type:'Identifier',name:'require'},computed:false};
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
'CallExpression|OptionalCallExpression|NewExpression'(nodePath) {
|
|
41
|
+
const node = nodePath.node, callee = node.callee;
|
|
42
|
+
if (callee.type === 'Identifier' && callee.name === 'require' && !nodePath.scope.hasBinding('require', true)) {
|
|
43
|
+
if (node.type !== 'CallExpression' || node.arguments.length !== 1 || node.arguments[0]?.type !== 'StringLiteral') fail('dynamic require() is not supported; dependencies must be statically bundled.');
|
|
44
|
+
} else if (callee.type === 'Identifier' && ['eval', 'Function'].includes(callee.name) && !nodePath.scope.hasBinding(callee.name, true)) fail(`${callee.name}() is not supported; use ESM imports and precompiled JavaScript.`);
|
|
45
|
+
if (callee.type === 'MemberExpression' && callee.object.type === 'Identifier' && ['globalThis', 'self'].includes(callee.object.name) && ['require', 'eval', 'Function'].includes(callee.computed ? callee.property.value : callee.property.name)) fail('Dynamic JavaScript compilation and require() are not supported.');
|
|
46
|
+
if (callee.type === 'Import' && node.arguments[0]?.type !== 'StringLiteral') fail('dynamic import paths must be string literals so they can be bundled.');
|
|
47
|
+
if (callee.type === 'MemberExpression' && callee.object.type === 'Identifier' && callee.object.name === 'WebAssembly' && ['compile', 'compileStreaming', 'Module'].includes(callee.computed ? callee.property.value : callee.property.name)) fail('dynamic WebAssembly compilation is not supported.');
|
|
48
|
+
},
|
|
49
|
+
ReferencedIdentifier(nodePath) {
|
|
50
|
+
const name = nodePath.node.name;
|
|
51
|
+
if (nodePath.scope.hasBinding(name, true)) return;
|
|
52
|
+
const parent = nodePath.parent;
|
|
53
|
+
if (name === 'module' && !(parent.type === 'MemberExpression' && parent.object === nodePath.node && (parent.computed ? parent.property.value : parent.property.name) === 'exports')) fail('Only statically bundled module.exports is supported in Edge; Node module APIs are unavailable.');
|
|
54
|
+
if (name === 'require' && !(parent.type === 'CallExpression' && parent.callee === nodePath.node && parent.arguments.length === 1 && parent.arguments[0]?.type === 'StringLiteral') && !(parent.type === 'UnaryExpression' && parent.operator === 'typeof')) fail('A runtime require reference is not supported in Edge.');
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
if(edits.length && sourceMapsEnabled())return generateMapped(generatePackage.default || generatePackage,ast,{comments:true},source,file);
|
|
58
|
+
for (const edit of edits.sort((a, b) => b.start - a.start)) source = source.slice(0, edit.start) + edit.text + source.slice(edit.end);
|
|
59
|
+
return source;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Bundle the entire application graph as Web ESM before entering the V8 realm. */
|
|
63
|
+
export async function compileEdge({ file, outfile, projectRoot, dev = false, defineEnvironment = {}, defaultExport = false, reactMode, plugins = [], transformSource }) {
|
|
64
|
+
const runtime = path.resolve(path.dirname(outfile), '../runtime');
|
|
65
|
+
await mkdir(runtime, { recursive: true });
|
|
66
|
+
try { await access(path.join(runtime, 'edge-vm.cjs')); }
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (error.code !== 'ENOENT') throw error;
|
|
69
|
+
await build({ stdin: { contents: "module.exports=require('@edge-runtime/vm')", resolveDir: compat },
|
|
70
|
+
outfile: path.join(runtime, 'edge-vm.cjs'), bundle: true, platform: 'node', format: 'cjs', target: 'node22', logLevel: 'silent' });
|
|
71
|
+
const source = await readFile(path.resolve(compat, '../runtime/edge.mjs'), 'utf8');
|
|
72
|
+
await writeFile(path.join(runtime, 'edge.mjs'), source.replace("import('@edge-runtime/vm')", "import('./edge-vm.cjs')"));
|
|
73
|
+
const require = createRequire(import.meta.url);
|
|
74
|
+
// primitives belongs to vm, not to the consumer or PRNext. Resolve it
|
|
75
|
+
// from its owner so nested npm/pnpm installations keep working.
|
|
76
|
+
const vmRequire = createRequire(require.resolve('@edge-runtime/vm/package.json'));
|
|
77
|
+
for (const name of ['vm', 'primitives']) {
|
|
78
|
+
const directory = path.dirname((name === 'vm' ? require : vmRequire).resolve(`@edge-runtime/${name}/package.json`));
|
|
79
|
+
await writeFile(path.join(runtime, `edge-${name}.LICENSE.txt`), await readFile(path.join(directory, 'LICENSE.md')));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const output = await build({ absWorkingDir: projectRoot,
|
|
83
|
+
stdin: { contents: `import {NextRequest} from 'prnext/server';export const __prnext_createRequest=(url,init)=>new NextRequest(url,init);export * from ${JSON.stringify(file)};${defaultExport ? `export {default} from ${JSON.stringify(file)};` : ''}`, resolveDir: projectRoot, sourcefile: 'prnext-edge-entry.mjs' },
|
|
84
|
+
write: false, bundle: true, platform: 'browser', format: 'esm', target: 'es2022', jsx: 'automatic', sourcemap:dev?'inline':false, conditions: [...(reactMode === 'rsc' ? ['react-server'] : []), 'edge-light', 'worker', 'browser'],
|
|
85
|
+
mainFields: ['browser', 'module', 'main'], logLevel: 'silent', metafile: true,
|
|
86
|
+
define: { 'process.env.NODE_ENV': JSON.stringify(dev ? 'development' : 'production'), ...defineEnvironment, 'process.env.NEXT_RUNTIME': '"edge"' },
|
|
87
|
+
plugins: [...plugins, { name: 'prnext-edge', setup(builder) {
|
|
88
|
+
builder.onResolve({ filter: /.*/ }, args => {
|
|
89
|
+
if (builtin.has(args.path) || args.path.startsWith('node:')) return { errors: [{ text: `Node.js module ${args.path} cannot run in the Edge Runtime (${args.importer}).` }] };
|
|
90
|
+
if (reactMode && ['react', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'react-dom', 'react-server-dom-webpack/server', 'react-server-dom-webpack/server.node'].includes(args.path)) return { path: args.path, namespace: 'prnext-edge-react' };
|
|
91
|
+
if (frameworkSubpathPattern.test(args.path)) {
|
|
92
|
+
const name = frameworkImportName(args.path);
|
|
93
|
+
if (name === 'server' || Object.hasOwn(names, name)) return { path: name, namespace: 'prnext-edge-compat' };
|
|
94
|
+
if (name === 'constants') return { path: path.join(compat, 'constants.cjs') };
|
|
95
|
+
return { errors: [{ text: `Edge Runtime does not support ${args.path}.` }] };
|
|
96
|
+
}
|
|
97
|
+
if (args.path === 'server-only') return { path: args.path, namespace: 'prnext-edge-empty' };
|
|
98
|
+
// The React graph collects styles for the browser. Its recursive resolver
|
|
99
|
+
// only locates the file; the caller replaces it with an empty/module map
|
|
100
|
+
// before Edge compilation. Route handlers still reject CSS imports.
|
|
101
|
+
if (reactMode && args.pluginData?.prnextResolvingCss && /\.(?:css|scss|sass)$/i.test(args.path)) return;
|
|
102
|
+
if (args.path === 'client-only' || /\.(?:node|css|scss|sass)$/.test(args.path)) return { errors: [{ text: `${args.path} cannot run in the Edge Runtime.` }] };
|
|
103
|
+
});
|
|
104
|
+
builder.onLoad({ filter: /.*/, namespace: 'prnext-edge-react' }, args => {
|
|
105
|
+
const exported = args.path.startsWith('react-server-dom-webpack/server') ? ['registerClientReference', 'registerServerReference'] : Object.keys(createRequire(import.meta.url)(args.path)).filter(name => name !== '__esModule' && name !== 'default');
|
|
106
|
+
return { loader: 'js', contents: `const module=globalThis.__PRNEXT_EDGE_REACT[${JSON.stringify(args.path === 'react-server-dom-webpack/server.node' ? 'react-server-dom-webpack/server' : args.path)}];export default module;\n` + exported.map(name => `export const ${name}=module[${JSON.stringify(name)}];`).join('\n') };
|
|
107
|
+
});
|
|
108
|
+
builder.onLoad({ filter: /.*/, namespace: 'prnext-edge-empty' }, () => ({ contents: '', loader: 'js' }));
|
|
109
|
+
builder.onLoad({ filter: /.*/, namespace: 'prnext-edge-compat' }, args => ({ loader: 'js', resolveDir: compat, contents: args.path === 'server'
|
|
110
|
+
? `import primitives from ${JSON.stringify(path.join(compat, 'server-primitives.cjs'))};export const {NextRequest,NextResponse,NextURL}=primitives;export const connection=globalThis.__PRNEXT_EDGE_HOST.server.connection;`
|
|
111
|
+
: names[args.path].map(name => `export const ${name}=globalThis.__PRNEXT_EDGE_HOST.${args.path}.${name};`).join('\n') }));
|
|
112
|
+
builder.onLoad({ filter: /\.[cm]?[jt]sx?$/, namespace: 'file' }, async args => {
|
|
113
|
+
let source = args.prnextSource ?? await readFile(args.path, 'utf8');
|
|
114
|
+
if (transformSource) source = await transformSource(source, args.path, builder);
|
|
115
|
+
if (!trusted.has(args.path)) source = validate(source, args.path, reactMode);
|
|
116
|
+
return { contents: source, loader: /\.[cm]?tsx?$/.test(args.path) ? 'tsx' : 'jsx', resolveDir: path.dirname(args.path) };
|
|
117
|
+
});
|
|
118
|
+
} }] });
|
|
119
|
+
const mapped=extractSourceMap(output.outputFiles[0].text);
|
|
120
|
+
const mapFile=output.outputFiles.find(file=>file.path===output.outputFiles[0].path+'.map');
|
|
121
|
+
let sourceMap=mapped.map || (mapFile?JSON.parse(mapFile.text):undefined);
|
|
122
|
+
// No outfile is supplied to the bundler: relative sources are rooted at the
|
|
123
|
+
// project, not at the final server/*.edge.js factory location.
|
|
124
|
+
if(sourceMap)sourceMap={...sourceMap,sourceRoot:'',sources:sourceMap.sources.map(source=>/^(?:[a-z][a-z+.-]*:|\/)/i.test(source)?source:path.resolve(projectRoot,sourceMap.sourceRoot || '',source))};
|
|
125
|
+
let code = mapped.code;
|
|
126
|
+
const ast = parse(code, { sourceType: 'module' }), exported = [];
|
|
127
|
+
for (const statement of ast.program.body) {
|
|
128
|
+
if (statement.type === 'ImportDeclaration' || statement.type === 'ExportAllDeclaration') throw new Error('Edge bundle still contains an external import');
|
|
129
|
+
if (statement.type !== 'ExportNamedDeclaration') continue;
|
|
130
|
+
if (statement.declaration || statement.source) throw new Error('Unexpected Edge bundle export');
|
|
131
|
+
for (const specifier of statement.specifiers) exported.push([specifier.exported.name ?? specifier.exported.value, specifier.local.name]);
|
|
132
|
+
}
|
|
133
|
+
// esbuild emits only final named exports. Removing them preserves top-level
|
|
134
|
+
// await inside an async factory without requiring Node's experimental modules.
|
|
135
|
+
for (const statement of [...ast.program.body].reverse()) if (statement.type === 'ExportNamedDeclaration') code = code.slice(0, statement.start) + code.slice(statement.start,statement.end).replace(/[^\r\n]/g,' ') + code.slice(statement.end);
|
|
136
|
+
const asset = outfile.replace(/\.mjs$/, '.edge.js');
|
|
137
|
+
await mkdir(path.dirname(outfile), { recursive: true });
|
|
138
|
+
await writeFile(asset, inlineSourceMap(`(async()=>{\n${code}\nreturn {${exported.map(([name, local]) => `${JSON.stringify(name)}:${local}`).join(',')}};})()`,sourceMap?{...sourceMap,mappings:';'+sourceMap.mappings}:undefined));
|
|
139
|
+
await writeFile(outfile, `import {readFile} from 'node:fs/promises';import {loadEdgeModule} from '../runtime/edge.mjs';const edge=await loadEdgeModule(await readFile(new URL(${JSON.stringify('./' + path.basename(asset))},import.meta.url),'utf8'),import.meta.url,${JSON.stringify(reactMode)});\n${exported.filter(([name]) => name !== '__prnext_createRequest').map(([name], index) => `const binding${index}=edge[${JSON.stringify(name)}];export {binding${index} as ${JSON.stringify(name)}};`).join('\n')}`);
|
|
140
|
+
return { exports: exported.map(([name]) => name), metafile: output.metafile };
|
|
141
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Google font metadata snapshot from Next.js 16.3.5
|
|
2
|
+
Source: next/dist/compiled/@next/font/dist/google/font-data.json
|
|
3
|
+
Only family names, supported variants, axes, and subsets are included; no font binaries.
|
|
4
|
+
|
|
5
|
+
The MIT License (MIT)
|
|
6
|
+
|
|
7
|
+
Copyright (c) 2025 Vercel, Inc.
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in all
|
|
17
|
+
copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
SOFTWARE.
|