@thomas.f/prnext 0.1.16-alpha → 0.1.18-alpha
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/AI.md +63 -0
- package/README.md +35 -503
- package/build/ADAPTERS.md +27 -2
- package/build/actions.mjs +6 -1
- package/build/analyze.mjs +340 -0
- package/build/app-config.mjs +20 -8
- package/build/app-static.mjs +41 -14
- package/build/app-styles.mjs +79 -0
- package/build/app.mjs +99 -31
- package/build/build-lock.mjs +6 -6
- package/build/bundle-runtime.mjs +39 -11
- package/build/cache-components.mjs +1 -1
- package/build/cache-handlers.mjs +1 -1
- package/build/check.mjs +56 -11
- package/build/compact-css.mjs +53 -0
- package/build/compilation-cache.mjs +269 -0
- package/build/compilation-store.mjs +142 -0
- package/build/compiler.mjs +51 -4
- package/build/concurrent.mjs +12 -0
- package/build/config.mjs +50 -13
- package/build/create.mjs +239 -0
- package/build/css-modules.mjs +65 -10
- package/build/deployment-assets.mjs +89 -0
- package/build/deployment-config.mjs +18 -0
- package/build/dev-compiler-health.mjs +11 -0
- package/build/dev-css-update.mjs +85 -0
- package/build/dev-dependencies.mjs +44 -0
- package/build/dev-discovery.mjs +28 -0
- package/build/dev-worker.mjs +14 -5
- package/build/dev.mjs +64 -6
- package/build/dynamic.mjs +1 -1
- package/build/edge.mjs +5 -4
- package/build/fonts.mjs +1 -1
- package/build/framework-imports.mjs +50 -0
- package/build/html-only-config.mjs +53 -0
- package/build/html-only-graph.mjs +67 -0
- package/build/incremental.mjs +8 -4
- package/build/index.mjs +140 -112
- package/build/inspect.mjs +3 -0
- package/build/inspection-summary.mjs +37 -4
- package/build/instrumentation.mjs +30 -0
- package/build/loader-cache.mjs +53 -26
- package/build/metadata-routes.mjs +3 -4
- package/build/migrate.mjs +60 -57
- package/build/migration-audit.mjs +1 -1
- package/build/native-type-config.mjs +37 -0
- package/build/npm-packages.mjs +3 -18
- package/build/package-manager.mjs +308 -0
- package/build/persistent-cache.mjs +112 -0
- package/build/precompress.mjs +62 -30
- package/build/prerender-cache.mjs +70 -0
- package/build/prerender-config.mjs +29 -0
- package/build/prerender-pages.mjs +100 -0
- package/build/prerender-pool.mjs +165 -0
- package/build/prerender-process-worker.mjs +58 -0
- package/build/prerender-worker.mjs +10 -0
- package/build/production-builder.mjs +129 -0
- package/build/react-compiler-report.mjs +225 -0
- package/build/react-compiler.mjs +139 -0
- package/build/runtime-contract.mjs +2 -2
- package/build/scan.mjs +4 -4
- package/build/source-analysis.mjs +42 -0
- package/build/static-adapter.mjs +13 -5
- package/build/static-export.mjs +4 -4
- package/build/static-input.mjs +48 -0
- package/build/styles.mjs +17 -3
- package/build/transform-cache.mjs +37 -4
- package/build/transform.mjs +1 -1
- package/build/type-command.mjs +41 -0
- package/build/typed-routes.mjs +95 -0
- package/build/typescript-dev-worker.mjs +18 -0
- package/build/typescript-dev.mjs +49 -0
- package/build/typescript-native-worker.mjs +55 -0
- package/build/typescript-native.mjs +18 -0
- package/build/typescript-toolchain.mjs +19 -0
- package/build/typescript-watch.mjs +22 -0
- package/build/typescript.mjs +11 -8
- package/build/webpack-graph.mjs +170 -30
- package/build/worker-memory.mjs +9 -0
- package/build/worker-preload.mjs +9 -0
- package/cli.mjs +162 -122
- package/compat/activity-cache.cjs +26 -0
- package/compat/after.cjs +6 -4
- package/compat/app-layout-context.cjs +52 -2
- package/compat/base64.cjs +10 -0
- package/compat/cache-handlers.cjs +12 -2
- package/compat/cache-wire.cjs +28 -0
- package/compat/cache.cjs +2 -1
- package/compat/cache.d.cts +4 -0
- package/compat/cookies.cjs +21 -5
- package/compat/data-cache.cjs +12 -8
- package/compat/flight-delta.cjs +150 -0
- package/compat/headers.cjs +4 -2
- package/compat/incremental-cache.cjs +20 -7
- package/compat/index.d.ts +89 -10
- package/compat/link.cjs +12 -9
- package/compat/link.d.cts +4 -3
- package/compat/navigation-authorization.cjs +9 -0
- package/compat/navigation-stages.cjs +19 -0
- package/compat/navigation.d.cts +4 -3
- package/compat/offline-store.cjs +11 -0
- package/compat/offline.cjs +5 -0
- package/compat/offline.d.cts +2 -0
- package/compat/redis-cache.cjs +201 -0
- package/compat/redis-cache.d.cts +37 -0
- package/compat/router.d.cts +4 -3
- package/compat/server-primitives.cjs +31 -11
- package/compat/server.d.cts +15 -2
- package/compat/static-generation.cjs +7 -0
- package/compat/typed-route.d.cts +17 -0
- package/compat/use-cache.cjs +3 -0
- package/docs/ai/compatibility.md +275 -0
- package/docs/ai/data.md +288 -0
- package/docs/ai/deployment.md +269 -0
- package/docs/ai/manifest.json +11 -0
- package/docs/ai/quickstart.md +171 -0
- package/docs/ai/routing.md +214 -0
- package/docs/ai/troubleshooting.md +155 -0
- package/index.mjs +2 -0
- package/native/diagnostics.mjs +34 -0
- package/native/resolve.mjs +7 -2
- package/package.json +44 -7
- package/release/ai-docs.mjs +48 -0
- package/release/verify.mjs +2 -0
- package/runtime/action-client.mjs +10 -4
- package/runtime/action-server.mjs +2 -0
- package/runtime/ai-docs.mjs +202 -0
- package/runtime/app-client.mjs +226 -68
- package/runtime/app-content.mjs +4 -3
- package/runtime/app-partial-client.mjs +3 -0
- package/runtime/app-partial.mjs +1 -1
- package/runtime/app-prefetch-constants.mjs +4 -0
- package/runtime/app-prefetch.mjs +2 -3
- package/runtime/app-render-key.mjs +5 -0
- package/runtime/app-render.mjs +100 -28
- package/runtime/app-routing.mjs +22 -9
- package/runtime/app-static.mjs +18 -8
- package/runtime/app-stream-html.mjs +10 -53
- package/runtime/app-style-selection.mjs +34 -0
- package/runtime/app-styles.mjs +154 -0
- package/runtime/cache-components-rsc.mjs +4 -1
- package/runtime/cache-request.mjs +2 -1
- package/runtime/cloud/archive.mjs +5 -6
- package/runtime/compile-cache.mjs +8 -0
- package/runtime/deployment-client.mjs +19 -0
- package/runtime/dev-ai-brands.mjs +26 -0
- package/runtime/dev-ai-style.mjs +99 -0
- package/runtime/dev-build-reasons.mjs +25 -0
- package/runtime/dev-cache-control.mjs +53 -0
- package/runtime/dev-client.mjs +245 -46
- package/runtime/dev-compiler-broker.mjs +42 -0
- package/runtime/dev-console-copy.mjs +19 -0
- package/runtime/dev-console.mjs +106 -0
- package/runtime/dev-dependency-graph.mjs +40 -0
- package/runtime/dev-element-picker-style.mjs +27 -0
- package/runtime/dev-element-picker.mjs +213 -0
- package/runtime/dev-error-overlay-style.mjs +41 -0
- package/runtime/dev-error-overlay.mjs +167 -0
- package/runtime/dev-error-report.mjs +121 -0
- package/runtime/dev-file-changes.mjs +1 -1
- package/runtime/dev-gateway.mjs +44 -0
- package/runtime/dev-host-relay.mjs +66 -0
- package/runtime/dev-indicator.mjs +191 -0
- package/runtime/dev-issue-motion.mjs +214 -0
- package/runtime/dev-lazy-tool.mjs +34 -0
- package/runtime/dev-logo.mjs +2 -0
- package/runtime/dev-notification.mjs +81 -0
- package/runtime/dev-popout.mjs +34 -0
- package/runtime/dev-position.mjs +107 -0
- package/runtime/dev-preview-touch.mjs +122 -0
- package/runtime/dev-runtime-pool.mjs +45 -0
- package/runtime/dev-runtime-spare.mjs +57 -0
- package/runtime/dev-tools-client.mjs +155 -0
- package/runtime/dev-tools-mcp.mjs +126 -0
- package/runtime/dev-tools-metrics.mjs +31 -0
- package/runtime/dev-tools-model.mjs +42 -0
- package/runtime/dev-tools-panel.mjs +341 -0
- package/runtime/dev-tools-result.mjs +37 -0
- package/runtime/dev-tools-server.mjs +256 -0
- package/runtime/dev-tools-source.mjs +104 -0
- package/runtime/dev-tooltip.mjs +94 -0
- package/runtime/dev-ui-icons.mjs +8 -0
- package/runtime/dev-workbench-style.mjs +106 -0
- package/runtime/dev-workbench.mjs +428 -0
- package/runtime/dev-worker-logs.mjs +31 -0
- package/runtime/development.mjs +324 -0
- package/runtime/document.mjs +1 -1
- package/runtime/edge.mjs +6 -5
- package/runtime/env.mjs +2 -1
- package/runtime/fetch-cache.mjs +10 -8
- package/runtime/flight-delta.mjs +50 -0
- package/runtime/flight-tap.mjs +28 -0
- package/runtime/html-only.mjs +27 -0
- package/runtime/http.mjs +2 -0
- package/runtime/incremental-cache.mjs +25 -4
- package/runtime/instrumentation.mjs +49 -0
- package/runtime/navigation-recovery.mjs +36 -0
- package/runtime/navigation.mjs +7 -0
- package/runtime/node-html-stream.mjs +47 -0
- package/runtime/pages-client.mjs +24 -8
- package/runtime/pages-navigation.mjs +54 -64
- package/runtime/persistent/client.mjs +6 -5
- package/runtime/persistent/daemon.mjs +66 -56
- package/runtime/persistent/native-proxy.mjs +63 -0
- package/runtime/prefetch-scheduler.mjs +110 -0
- package/runtime/preload.mjs +12 -0
- package/runtime/profile.mjs +14 -0
- package/runtime/profiles.json +2 -2
- package/runtime/render.mjs +3 -0
- package/runtime/route-pattern.mjs +44 -0
- package/runtime/rsc-worker.mjs +41 -12
- package/runtime/trace.mjs +78 -0
- package/runtime/typed-route.mjs +19 -0
- package/runtime/watch-project.mjs +29 -18
- package/runtime/worker.mjs +102 -24
package/build/webpack-graph.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {build as esbuild, transform} from 'esbuild';
|
|
2
|
-
import {mkdir, mkdtemp, readFile, writeFile, rm, realpath} from 'node:fs/promises';
|
|
2
|
+
import {mkdir, mkdtemp, readFile, writeFile, rm, rmdir, realpath} from 'node:fs/promises';
|
|
3
3
|
import {createHash, randomUUID} from 'node:crypto';
|
|
4
4
|
import {createRequire} from 'node:module';
|
|
5
5
|
import {fileURLToPath} from 'node:url';
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
import { cachedAsyncTransform } from './transform-cache.mjs';
|
|
8
8
|
import {inlineSourceMap} from './source-maps.mjs';
|
|
9
|
+
import {buildCacheIdentity} from './persistent-cache.mjs';
|
|
9
10
|
|
|
10
11
|
const require = createRequire(import.meta.url);
|
|
11
12
|
const {active} = require('./webpack-bridge.cjs');
|
|
@@ -13,6 +14,107 @@ const loaderPath = fileURLToPath(new URL('./webpack-loader.cjs', import.meta.url
|
|
|
13
14
|
const hash = value => createHash('sha256').update(value).digest('hex').slice(0, 20);
|
|
14
15
|
const slash = value => value.replaceAll(path.sep, '/');
|
|
15
16
|
const safeAsset = name => { if (path.isAbsolute(name) || /[\\\0?#]/.test(name) || name.split('/').some(part => !part || part === '.' || part === '..')) throw new Error(`Unsafe webpack asset path: ${name}`); };
|
|
17
|
+
async function discardPrivateFile(file,boundary){
|
|
18
|
+
await rm(file,{force:true});
|
|
19
|
+
for(let directory=path.dirname(file);directory!==boundary&&directory.startsWith(boundary+path.sep);directory=path.dirname(directory)){
|
|
20
|
+
try{await rmdir(directory);}catch(error){if(['ENOTEMPTY','EEXIST'].includes(error.code))break;if(error.code!=='ENOENT')throw error;}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const sessions=new Map(),sessionLimit=6,sessionBuildLimit=64,objectIds=new WeakMap();
|
|
24
|
+
let nextId=0,created=0,reused=0,graphQueue=Promise.resolve();
|
|
25
|
+
const objectId=value=>{if(!objectIds.has(value))objectIds.set(value,++nextId);return objectIds.get(value);};
|
|
26
|
+
// Arbitrary plugin closures are not interchangeable just because their source
|
|
27
|
+
// text matches. Only known webpack constructors with the same options may be
|
|
28
|
+
// recreated; other plugins must retain their actual instance identity.
|
|
29
|
+
function fingerprint(value,seen=new Set()){
|
|
30
|
+
if(typeof value==='function')return ['function',objectId(value)];
|
|
31
|
+
if(value instanceof RegExp)return ['regexp',value.source,value.flags];
|
|
32
|
+
if(value===undefined)return ['undefined'];
|
|
33
|
+
if(typeof value==='symbol')throw new Error('Opaque symbol in webpack configuration');
|
|
34
|
+
if(typeof value==='bigint')return ['bigint',String(value)];
|
|
35
|
+
if(typeof value==='number'&&(!Number.isFinite(value)||Object.is(value,-0)))return ['number',String(value),Object.is(value,-0)];
|
|
36
|
+
if(!value||typeof value!=='object')return value;
|
|
37
|
+
if(seen.has(value))return ['object',objectId(value)];
|
|
38
|
+
seen.add(value);
|
|
39
|
+
const properties=(skipIndices=false)=>{
|
|
40
|
+
const keys=Reflect.ownKeys(value);
|
|
41
|
+
if(keys.length>10000||keys.some(key=>typeof key==='symbol'))throw new Error('Opaque or excessive webpack configuration');
|
|
42
|
+
return keys.filter(key=>!skipIndices||!/^(?:0|[1-9]\d*)$/.test(key)).sort().map(key=>{
|
|
43
|
+
const descriptor=Object.getOwnPropertyDescriptor(value,key);if(descriptor.get||descriptor.set)throw new Error('Accessor in webpack configuration');
|
|
44
|
+
return[key,descriptor.enumerable,descriptor.configurable,descriptor.writable,fingerprint(descriptor.value,seen)];
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
const prototype=Object.getPrototypeOf(value);let result;
|
|
48
|
+
if(Array.isArray(value))result=['array',properties()];
|
|
49
|
+
else if(prototype===Map.prototype){
|
|
50
|
+
const extras=properties();
|
|
51
|
+
if(value.size>10000)throw new Error('Excessive webpack Map configuration');
|
|
52
|
+
const key=item=>item&&(typeof item==='object'||typeof item==='function')?['identity',objectId(item),fingerprint(item,seen)]:fingerprint(item,seen);
|
|
53
|
+
result=['map',[...Map.prototype.entries.call(value)].map(([name,item])=>[key(name),fingerprint(item,seen)]),extras];
|
|
54
|
+
}else if(prototype===Set.prototype){
|
|
55
|
+
const extras=properties();
|
|
56
|
+
if(value.size>10000)throw new Error('Excessive webpack Set configuration');
|
|
57
|
+
result=['set',[...Set.prototype.values.call(value)].map(item=>item&&(typeof item==='object'||typeof item==='function')?['identity',objectId(item),fingerprint(item,seen)]:fingerprint(item,seen)),extras];
|
|
58
|
+
}else if(prototype===Date.prototype)result=['date',String(Date.prototype.getTime.call(value)),properties()];
|
|
59
|
+
else if(prototype===ArrayBuffer.prototype){
|
|
60
|
+
if(value.byteLength>1024*1024)throw new Error('Excessive webpack binary configuration');
|
|
61
|
+
result=['array-buffer',Buffer.from(value).toString('base64'),value.resizable,value.maxByteLength,properties()];
|
|
62
|
+
}else if(ArrayBuffer.isView(value)){
|
|
63
|
+
if(value.byteLength>10000)throw new Error('Excessive webpack binary view configuration');
|
|
64
|
+
const types=[Buffer,Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,BigInt64Array,BigUint64Array,DataView];
|
|
65
|
+
const type=types.find(type=>prototype===type.prototype);
|
|
66
|
+
if(!type)throw new Error('Opaque webpack binary configuration');
|
|
67
|
+
result=[type.name,fingerprint(value.buffer,seen),value.byteOffset,value.byteLength,properties(true)];
|
|
68
|
+
}else if(prototype===Object.prototype||prototype===null)result=['record',prototype===null,properties()];
|
|
69
|
+
else throw new Error('Opaque webpack configuration instance');
|
|
70
|
+
seen.delete(value);return result;
|
|
71
|
+
}
|
|
72
|
+
function pluginIdentity(plugin,webpack){
|
|
73
|
+
const fields={NormalModuleReplacementPlugin:['resourceRegExp','newResource'],IgnorePlugin:['options'],ProvidePlugin:['definitions'],DefinePlugin:['definitions'],BannerPlugin:['options']};
|
|
74
|
+
for(const[name,keys]of Object.entries(fields))if(plugin.constructor===webpack[name])return[name,fingerprint(Object.fromEntries(keys.map(key=>[key,plugin[key]])))];
|
|
75
|
+
return ['instance',objectId(plugin),fingerprint(plugin)];
|
|
76
|
+
}
|
|
77
|
+
export const webpackCompilerStats=()=>({contexts:sessions.size,created,reused,limit:sessionLimit,buildLimit:sessionBuildLimit});
|
|
78
|
+
function queued(callback){const task=graphQueue.then(callback);graphQueue=task.catch(()=>{});return task;}
|
|
79
|
+
export function closeWebpackCompiler(root){return queued(async()=>{
|
|
80
|
+
const closing=[];for(const[key,session]of sessions)if(root===undefined||session.root===root){sessions.delete(key);closing.push(session.dispose());}
|
|
81
|
+
const results=await Promise.allSettled(closing),errors=results.filter(result=>result.status==='rejected').map(result=>result.reason);
|
|
82
|
+
if(errors.length)throw new AggregateError(errors,'Unable to dispose webpack compiler sessions');
|
|
83
|
+
});}
|
|
84
|
+
|
|
85
|
+
async function compileGraph(resolver,loads,options,{state,config,target}){
|
|
86
|
+
return queued(async()=>{
|
|
87
|
+
const webpack=(await import('webpack')).default;
|
|
88
|
+
let reusable=state.dev&&state.incremental,identity;
|
|
89
|
+
if(reusable){try{identity=await buildCacheIdentity(state.root);}catch{}if(!identity)reusable=false;}
|
|
90
|
+
let base,key;
|
|
91
|
+
if(reusable)try{
|
|
92
|
+
const normalize=value=>typeof value==='string'?value.replaceAll(state.stage,'<stage>'):Array.isArray(value)?value.map(normalize):value&&typeof value==='object'&&[Object.prototype,null].includes(Object.getPrototypeOf(value))?Object.fromEntries(Object.entries(value).map(([key,item])=>[key,normalize(item)])):value;
|
|
93
|
+
const normalized=normalize({...options,plugins:(options.plugins||[]).map(plugin=>plugin.name),stdin:options.stdin&&{...options.stdin,contents:undefined}});
|
|
94
|
+
base=hash(JSON.stringify(fingerprint([state.root,target,normalized])));
|
|
95
|
+
key=hash(JSON.stringify([base,identity,fingerprint({...config,graphPlugins:undefined}),config.graphPlugins.map(plugin=>pluginIdentity(plugin,webpack))]));
|
|
96
|
+
}catch{reusable=false;}
|
|
97
|
+
// Unknown data structures, safe mode and unavailable identities all keep
|
|
98
|
+
// compilation correct through a one-shot compiler. Hidden mutable closure
|
|
99
|
+
// state cannot be fingerprinted: replace the plugin instance when it changes.
|
|
100
|
+
if(state.dev&&!reusable)for(const[key,session]of sessions)if(session.root===state.root){sessions.delete(key);await session.dispose();}
|
|
101
|
+
let session=reusable&&sessions.get(key);
|
|
102
|
+
if(session&&session.builds>=sessionBuildLimit){sessions.delete(key);await session.dispose();session=undefined;}
|
|
103
|
+
if(reusable){
|
|
104
|
+
for(const[old,previous]of sessions)if(previous.root===state.root&&(previous.identity!==identity||previous.base===base&&old!==key)){sessions.delete(old);await previous.dispose();}
|
|
105
|
+
}
|
|
106
|
+
if(session){sessions.delete(key);reused++;}
|
|
107
|
+
else{
|
|
108
|
+
if(reusable)while(sessions.size>=sessionLimit){const[old,previous]=sessions.entries().next().value;sessions.delete(old);await previous.dispose();}
|
|
109
|
+
session=await createGraphSession(state.root,{webpack,reusable,stage:state.stage});created++;
|
|
110
|
+
Object.assign(session,{root:state.root,base,identity,builds:0});
|
|
111
|
+
}
|
|
112
|
+
if(reusable)sessions.set(key,session);
|
|
113
|
+
try{session.builds++;return await session.run(resolver,loads,options,{state,config,target});}
|
|
114
|
+
catch(error){if(reusable)sessions.delete(key);await session.dispose();throw error;}
|
|
115
|
+
finally{if(!reusable)await session.dispose();}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
16
118
|
|
|
17
119
|
/** Webpack owns the actual module/chunk graph. PRNext's resolve/load transforms
|
|
18
120
|
* remain authoritative for React boundaries and the Node/Edge/browser targets.
|
|
@@ -37,27 +139,41 @@ export async function webpackGraph(options, {state, config, target}) {
|
|
|
37
139
|
finally { for (const dispose of disposes) await dispose(); }
|
|
38
140
|
}
|
|
39
141
|
|
|
40
|
-
async function
|
|
41
|
-
const webpack = (await import('webpack')).default;
|
|
142
|
+
async function createGraphSession(root,{webpack,reusable,stage}) {
|
|
42
143
|
const bridgeId = randomUUID();
|
|
43
|
-
await mkdir(path.join(
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
144
|
+
await mkdir(path.join(stage,'.entries'),{recursive:true});
|
|
145
|
+
const home=await realpath(await mkdtemp(path.join(reusable?root:path.join(stage,'.entries'),'.prnext-webpack-')));
|
|
146
|
+
const virtualDirectory=path.join(home,'modules'),virtualStage=path.join(home,'stage'),scratchOut=path.join(home,'output');
|
|
147
|
+
await mkdir(virtualDirectory,{recursive:true});
|
|
148
|
+
const projectRequire = createRequire(path.join(root,'package.json'));
|
|
149
|
+
let compiler,resolver,loads,options,state,config,target,outdir,actualOut,extension,modules,entries,runtime,disposed=false;
|
|
150
|
+
const virtualFiles=new Set(),loaderFiles=new Set(),previousOutputs=new Set();let usedVirtualFiles;
|
|
151
|
+
const fromVirtual=value=>typeof value==='string'&&(value===virtualStage||value.startsWith(virtualStage+path.sep))?state.stage+value.slice(virtualStage.length):value;
|
|
152
|
+
const toVirtual=value=>reusable&&typeof value==='string'&&(value===state.stage||value.startsWith(state.stage+path.sep))?virtualStage+value.slice(state.stage.length):value;
|
|
153
|
+
const stageFile=async file=>{
|
|
154
|
+
const mapped=toVirtual(file);if(mapped===file)return file;
|
|
155
|
+
virtualFiles.add(mapped);usedVirtualFiles.add(mapped);
|
|
156
|
+
const contents=await readFile(file);await mkdir(path.dirname(mapped),{recursive:true});
|
|
157
|
+
let previous;try{previous=await readFile(mapped);}catch(error){if(error.code!=='ENOENT')throw error;}
|
|
158
|
+
if(!previous?.equals(contents))await writeFile(mapped,contents);return mapped;
|
|
159
|
+
};
|
|
160
|
+
const run=async(nextResolver,nextLoads,nextOptions,next)=>{
|
|
161
|
+
resolver=nextResolver;loads=nextLoads;options=nextOptions;({state,config,target}=next);
|
|
162
|
+
usedVirtualFiles=new Set();
|
|
163
|
+
outdir=options.outdir||(options.outfile?path.dirname(options.outfile):scratchOut);actualOut=reusable||options.write===false?scratchOut:outdir;extension=options.outExtension?.['.js']||'.js';modules=new Map();
|
|
164
|
+
// Webpack may retain SizeOnlySource for unchanged assets and assume the last
|
|
165
|
+
// emitted file still exists. Keep current outputs until the next run finishes.
|
|
166
|
+
await mkdir(actualOut,{recursive:true});
|
|
167
|
+
entries=options.stdin?{entry:path.join(virtualDirectory,'entry.js')}:Array.isArray(options.entryPoints)?Object.fromEntries(options.entryPoints.map(file=>[path.basename(file,path.extname(file)),toVirtual(file)])):Object.fromEntries(Object.entries(options.entryPoints).map(([name,file])=>[name,toVirtual(file)]));
|
|
168
|
+
for(const file of Object.values(entries))if(file.startsWith(virtualStage+path.sep))await stageFile(fromVirtual(file));
|
|
54
169
|
if (options.stdin) {
|
|
55
170
|
const file = entries.entry;
|
|
56
171
|
await writeFile(file,options.stdin.contents);
|
|
172
|
+
virtualFiles.add(file);usedVirtualFiles.add(file);
|
|
57
173
|
modules.set(file,{path:file,namespace:'file',resolveDir:options.stdin.resolveDir || state.root,stdin:true});
|
|
58
174
|
}
|
|
59
175
|
const identify = record => record.namespace === 'file' ? slash(path.relative(state.root,record.path)) : record.namespace+':'+slash(path.relative(state.root,record.path));
|
|
60
|
-
const lookup = resource => modules.get(resource) || modules.get(resource?.split('?')[0]) || {path:resource?.split('?')[0],namespace:'file',suffix:resource?.includes('?')?'?'+resource.split('?').slice(1).join('?'):''};
|
|
176
|
+
const lookup = resource => modules.get(resource) || modules.get(resource?.split('?')[0]) || {path:fromVirtual(resource?.split('?')[0]),namespace:'file',suffix:resource?.includes('?')?'?'+resource.split('?').slice(1).join('?'):''};
|
|
61
177
|
const load = async(record,source,webpackContext,sourceMap) => {
|
|
62
178
|
if (record.stdin) return {contents:source,loader:options.stdin.loader || 'js',resolveDir:record.resolveDir};
|
|
63
179
|
for (const {settings,callback,framework,configuredLoaders} of loads) {
|
|
@@ -106,18 +222,18 @@ async function compileGraph(resolver, loads, options, {state,config,target}) {
|
|
|
106
222
|
// A changed synchronous chunk may leave webpack's runtime bytes unchanged.
|
|
107
223
|
// Give each published build its own module cache; React's dev singletons
|
|
108
224
|
// still retain their identities across the new runtime instance.
|
|
109
|
-
|
|
225
|
+
runtime = 'webpack-runtime-'+hash(JSON.stringify([state.stage,Object.keys(entries),options.conditions,target]));
|
|
110
226
|
try {
|
|
111
|
-
compiler = webpack({name:target,context:state.root,mode:state.dev?'development':'production',
|
|
227
|
+
if(!compiler)compiler = webpack({name:target,context:state.root,mode:state.dev?'development':'production',
|
|
112
228
|
...(config.watchOptions ? {watchOptions:config.watchOptions} : {}),
|
|
113
|
-
target:target==='node'?'node22':['web','es2022'],entry:entries,cache:false,devtool:options.sourcemap?'source-map':false,
|
|
229
|
+
target:target==='node'?'node22':['web','es2022'],entry:entries,cache:reusable?{type:'memory',maxGenerations:1}:false,devtool:options.sourcemap?'source-map':false,
|
|
114
230
|
experiments:{outputModule:true,css:true},externalsType:'module',
|
|
115
231
|
output:{path:actualOut,filename:options.outfile?path.basename(options.outfile):naming(options.entryNames)+extension,
|
|
116
232
|
chunkFilename:naming(options.chunkNames || 'chunk-[hash]')+extension,cssFilename:naming(options.entryNames)+'.css',
|
|
117
233
|
cssChunkFilename:'style-[contenthash:16].css',module:true,library:{type:'module'},chunkFormat:'module',chunkLoading:'import',
|
|
118
|
-
publicPath:target==='node'?'./':state.assetBase+'/',environment:{module:true,dynamicImport:true},clean:false},
|
|
234
|
+
publicPath:target==='node'?'./':state.assetBase+'/',environment:{module:true,dynamicImport:true},compareBeforeEmit:false,clean:false},
|
|
119
235
|
performance:false,
|
|
120
|
-
optimization:{minimize:!!options.minify,minimizer:[{apply(compiler){
|
|
236
|
+
optimization:{minimize:!!options.minify,mangleExports:options.minify?'size':false,minimizer:[{apply(compiler){
|
|
121
237
|
compiler.hooks.compilation.tap('PRNextMinify',compilation=>{
|
|
122
238
|
compilation.hooks.processAssets.tapPromise({name:'PRNextMinify',stage:webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE},async()=>{
|
|
123
239
|
// Sequential native esbuild transforms avoid a Terser worker pool.
|
|
@@ -130,10 +246,10 @@ async function compileGraph(resolver, loads, options, {state,config,target}) {
|
|
|
130
246
|
}
|
|
131
247
|
});
|
|
132
248
|
});
|
|
133
|
-
}}],runtimeChunk:options.splitting?{name:runtime}:false,
|
|
134
|
-
splitChunks:options.splitting?{chunks:'all',minSize:0,cacheGroups:{default:false,defaultVendors:false,shared:{minChunks:2,test:module=>!module.type.startsWith('css'),name:false}}}:false},
|
|
249
|
+
}}],runtimeChunk:options.splitting?{name:()=>runtime}:false,
|
|
250
|
+
splitChunks:options.splitting?{chunks:'all',minSize:0,cacheGroups:{default:false,defaultVendors:false,shared:{minChunks:2,reuseExistingChunk:true,test:module=>!module.type.startsWith('css'),name:false}}}:false},
|
|
135
251
|
resolve:{alias:config.resolution.resolveAlias || {},conditionNames:[...(options.conditions || []),'...'],extensions:config.resolution.resolveExtensions || ['.tsx','.ts','.jsx','.js','.mjs','.json'],fullySpecified:false},
|
|
136
|
-
module:{rules:[{test:/./,type:'javascript/auto',enforce:'post',use:[{loader:loaderPath,options:{bridge:bridgeId}}]},
|
|
252
|
+
module:{unsafeCache:false,rules:[{test:/./,type:'javascript/auto',enforce:'post',use:[{loader:loaderPath,options:{bridge:bridgeId}}]},
|
|
137
253
|
{test:/\.json$/,type:'json'},{test:/\.(?:css|scss|sass)$/,type:'css'},
|
|
138
254
|
{dependency:'url',type:'asset/resource'}]},
|
|
139
255
|
plugins:[...config.graphPlugins,
|
|
@@ -143,7 +259,7 @@ async function compileGraph(resolver, loads, options, {state,config,target}) {
|
|
|
143
259
|
{apply(compiler) {
|
|
144
260
|
if (state.devInputs && config.graphPlugins.some(plugin=>plugin.constructor?.name==='ContentlayerWebpackPlugin')) {
|
|
145
261
|
compiler.hooks.beforeCompile.tapPromise({name:'PRNextGeneratedInputs',stage:Number.MAX_SAFE_INTEGER},()=>
|
|
146
|
-
state.generatedInputs ||= state.devInputs.captureDirectory('.contentlayer/generated'));
|
|
262
|
+
state.devInputs&&(state.generatedInputs ||= state.devInputs.captureDirectory('.contentlayer/generated')));
|
|
147
263
|
}
|
|
148
264
|
compiler.hooks.normalModuleFactory.tap('PRNextFramework',factory=>{
|
|
149
265
|
factory.hooks.beforeResolve.tapPromise({name:'PRNextFramework',stage:10000},async data=>{
|
|
@@ -151,12 +267,12 @@ async function compileGraph(resolver, loads, options, {state,config,target}) {
|
|
|
151
267
|
const importer = lookup(data.contextInfo.issuer);
|
|
152
268
|
const dependency = data.dependencies[0];
|
|
153
269
|
const kind = dependency?.type?.includes('url') ? 'url-token' : dependency?.type==='css @import'?'import-rule':data.dependencyType==='commonjs'?'require-call':dependency?.type==='import()'?'dynamic-import':data.contextInfo.issuer?'import-statement':'entry-point';
|
|
154
|
-
const settings={resolveDir:importer.resolveDir || data.context || state.root,importer:importer.path || '',namespace:importer.namespace || 'file',kind};
|
|
270
|
+
const settings={resolveDir:fromVirtual(importer.resolveDir || data.context || state.root),importer:importer.path || '',namespace:importer.namespace || 'file',kind};
|
|
155
271
|
// Let webpack resolve/execute the inline loader chain itself. Only
|
|
156
272
|
// its resource passes through framework resolution.
|
|
157
273
|
const bang=data.request.lastIndexOf('!');
|
|
158
274
|
const inline=bang<0?'':data.request.slice(0,bang+1);
|
|
159
|
-
const request=bang<0?data.request:data.request.slice(bang+1);
|
|
275
|
+
const request=fromVirtual(bang<0?data.request:data.request.slice(bang+1));
|
|
160
276
|
const resolved = await resolver.resolve(request,settings);
|
|
161
277
|
if (resolved.errors.length) throw new Error(resolved.errors.map(error=>error.text).join('\n'));
|
|
162
278
|
if (resolved.external) {
|
|
@@ -174,6 +290,9 @@ async function compileGraph(resolver, loads, options, {state,config,target}) {
|
|
|
174
290
|
if(record.namespace!=='file'){
|
|
175
291
|
resource=path.join(virtualDirectory,hash(JSON.stringify([record.namespace,record.path,record.suffix]))+(/css$/.test(record.namespace)?'.css':'.js'));
|
|
176
292
|
if(!modules.has(resource))await writeFile(resource,'');
|
|
293
|
+
virtualFiles.add(resource);usedVirtualFiles.add(resource);
|
|
294
|
+
}else if(toVirtual(record.path)!==record.path){
|
|
295
|
+
resource=await stageFile(record.path)+(record.suffix||'');
|
|
177
296
|
}
|
|
178
297
|
data.request=inline+resource;
|
|
179
298
|
modules.set(data.request,record);
|
|
@@ -206,6 +325,11 @@ async function compileGraph(resolver, loads, options, {state,config,target}) {
|
|
|
206
325
|
});
|
|
207
326
|
}},
|
|
208
327
|
]});
|
|
328
|
+
// Native loader modules live outside webpack's graph cache. Reload tracked
|
|
329
|
+
// implementations so editing a loader cannot retain its require() closure.
|
|
330
|
+
const clearLoader=file=>{const loaded=require.cache[file];delete require.cache[file];for(const child of loaded?.children||[])if(child.filename!==loaderPath)clearLoader(child.filename);};
|
|
331
|
+
for(const file of loaderFiles)clearLoader(file);
|
|
332
|
+
compiler.inputFileSystem.purge?.();
|
|
209
333
|
const stats=await new Promise((resolve,reject)=>compiler.run((error,stats)=>error?reject(error):resolve(stats)));
|
|
210
334
|
if(stats.hasErrors())throw new Error(stats.toString({all:false,errors:true,errorDetails:true}));
|
|
211
335
|
for(const warning of stats.compilation.warnings){
|
|
@@ -218,10 +342,11 @@ async function compileGraph(resolver, loads, options, {state,config,target}) {
|
|
|
218
342
|
for(const chunk of compilation.chunks)for(const file of chunk.files)chunkFiles.add(file);
|
|
219
343
|
for(const [name,entry] of compilation.entrypoints){
|
|
220
344
|
const file=[...entry.getEntrypointChunk().files].find(file=>file.endsWith(extension));
|
|
221
|
-
if(file)entryFiles.set(file,entries[name]);
|
|
345
|
+
if(file)entryFiles.set(file,fromVirtual(entries[name]));
|
|
222
346
|
const css=entry.getFiles().find(file=>file.endsWith('.css'));if(file&&css)styles.set(file,css);
|
|
223
347
|
}
|
|
224
348
|
for(const module of compilation.modules){
|
|
349
|
+
for(const loader of module.loaders||[])if(loader.loader!==loaderPath)loaderFiles.add(loader.loader);
|
|
225
350
|
if(!module.resource)continue;
|
|
226
351
|
const record=lookup(module.resource), imports=[];
|
|
227
352
|
for(const connection of compilation.moduleGraph.getOutgoingConnections(module)){
|
|
@@ -234,6 +359,7 @@ async function compileGraph(resolver, loads, options, {state,config,target}) {
|
|
|
234
359
|
safeAsset(asset.name);
|
|
235
360
|
const contents=await readFile(path.join(actualOut,asset.name));
|
|
236
361
|
const file=path.join(outdir,asset.name), key=slash(path.relative(state.root,file));
|
|
362
|
+
if(options.write!==false&&file!==path.join(actualOut,asset.name)){await mkdir(path.dirname(file),{recursive:true});await writeFile(file,contents);}
|
|
237
363
|
outputs[key]={bytes:contents.length,imports:[],exports:[],inputs:inputSizes,
|
|
238
364
|
...(entryFiles.has(asset.name)?{entryPoint:slash(path.relative(state.root,entryFiles.get(asset.name)))}:{}),
|
|
239
365
|
...(styles.has(asset.name)?{cssBundle:slash(path.relative(state.root,path.join(outdir,styles.get(asset.name))))}:{})};
|
|
@@ -248,9 +374,23 @@ async function compileGraph(resolver, loads, options, {state,config,target}) {
|
|
|
248
374
|
}
|
|
249
375
|
const rank = file => entryFiles.has(slash(path.relative(outdir,file.path))) ? 0 : file.path.endsWith(extension) ? 1 : 2;
|
|
250
376
|
outputFiles.sort((a,b)=>rank(a)-rank(b));
|
|
251
|
-
|
|
377
|
+
if(reusable){
|
|
378
|
+
const currentOutputs=new Set(compilation.getAssets().map(asset=>asset.name));
|
|
379
|
+
for(const name of previousOutputs)if(!currentOutputs.has(name))await discardPrivateFile(path.join(actualOut,name),actualOut);
|
|
380
|
+
previousOutputs.clear();for(const name of currentOutputs)previousOutputs.add(name);
|
|
381
|
+
}
|
|
382
|
+
// This compatibility metafile does not yet encode webpack's runtime and
|
|
383
|
+
// async chunk-group edges. Consumers must not mistake empty import lists
|
|
384
|
+
// for a complete initial browser graph.
|
|
385
|
+
return {errors:[],warnings:[],metafile:{inputs,outputs,initialGraphComplete:false},...(options.write===false?{outputFiles}:{})};
|
|
252
386
|
} finally {
|
|
253
|
-
|
|
254
|
-
|
|
387
|
+
active.delete(bridgeId);
|
|
388
|
+
for(const file of virtualFiles)if(!usedVirtualFiles.has(file)){virtualFiles.delete(file);await discardPrivateFile(file,home);}
|
|
255
389
|
}
|
|
390
|
+
};
|
|
391
|
+
return {run,async dispose(){
|
|
392
|
+
if(disposed)return;disposed=true;
|
|
393
|
+
try{if(compiler)await new Promise((resolve,reject)=>compiler.close(error=>error?reject(error):resolve()));}
|
|
394
|
+
finally{active.delete(bridgeId);await rm(home,{recursive:true,force:true});compiler=resolver=state=config=options=modules=undefined;loads=[];virtualFiles.clear();loaderFiles.clear();previousOutputs.clear();}
|
|
395
|
+
}};
|
|
256
396
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function validateWorkerMemory(value) {
|
|
2
|
+
if (value === undefined || value === false) return undefined;
|
|
3
|
+
if (!value || typeof value !== 'object' || Array.isArray(value) ||
|
|
4
|
+
Object.keys(value).some(key => key !== 'maxRssMb') ||
|
|
5
|
+
!Number.isSafeInteger(value.maxRssMb) || value.maxRssMb < 64 || value.maxRssMb > 65536) {
|
|
6
|
+
throw new TypeError('workerMemory must be false or { maxRssMb: 64..65536 }');
|
|
7
|
+
}
|
|
8
|
+
return { maxRssMb: value.maxRssMb };
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function validateWorkerPreload(value){
|
|
2
|
+
if(value===undefined||value===false)return undefined;
|
|
3
|
+
if(!value||typeof value!=='object'||Array.isArray(value))throw new TypeError('workerPreload must be false or an object');
|
|
4
|
+
for(const key of Object.keys(value))if(!['routes','maxRssMb','timeoutMs'].includes(key))throw new TypeError(`workerPreload.${key} is not supported`);
|
|
5
|
+
if(!Array.isArray(value.routes)||!value.routes.length||value.routes.length>16||value.routes.some(route=>typeof route!=='string'||!route.startsWith('/')||route.length>1024||/[?#\x00-\x1f]/.test(route))||new Set(value.routes).size!==value.routes.length)throw new TypeError('workerPreload.routes must contain 1 to 16 distinct route patterns');
|
|
6
|
+
const options={routes:value.routes,maxRssMb:value.maxRssMb??256,timeoutMs:value.timeoutMs??5000};
|
|
7
|
+
for(const [key,min,max] of [['maxRssMb',16,2048],['timeoutMs',100,30000]])if(!Number.isInteger(options[key])||options[key]<min||options[key]>max)throw new TypeError(`workerPreload.${key} must be between ${min} and ${max}`);
|
|
8
|
+
return options;
|
|
9
|
+
}
|