next
Version:
The React Framework
98 lines (97 loc) • 4.31 kB
JavaScript
import { webpack } from 'next/dist/compiled/webpack/webpack';
import createDebug from 'next/dist/compiled/debug';
const debug = createDebug('next:deferred-entries-plugin');
const PLUGIN_NAME = 'DeferredEntriesPlugin';
/**
* A webpack plugin that handles deferred entries by:
* 1. Accepting deferred entrypoints separately from the main config
* 2. After non-deferred entries are compiled, calling the onBeforeDeferredEntries callback
* 3. Then adding and compiling the deferred entries within the same compilation
*
* This approach avoids module ID conflicts that would occur with separate compilations.
*/ export class DeferredEntriesPlugin {
constructor(options){
this.callbackCalled = false;
this.onBeforeDeferredEntries = options.config.experimental.onBeforeDeferredEntries;
this.deferredEntrypoints = options.deferredEntrypoints;
}
apply(compiler) {
// Skip if no deferred entrypoints to process
if (!this.deferredEntrypoints || Object.keys(this.deferredEntrypoints).length === 0) {
return;
}
// Use finishMake hook to add deferred entries after all initial entries are processed
// This is the same pattern used by FlightClientEntryPlugin
compiler.hooks.finishMake.tapPromise(PLUGIN_NAME, async (compilation)=>{
// Only process if we haven't called callback yet
if (this.callbackCalled) {
return;
}
this.callbackCalled = true;
// Call the onBeforeDeferredEntries callback
if (this.onBeforeDeferredEntries) {
debug('calling onBeforeDeferredEntries callback');
await this.onBeforeDeferredEntries();
debug('onBeforeDeferredEntries callback completed');
}
// Add deferred entries to compilation
const addEntryPromises = [];
const bundler = webpack;
debug('adding deferred entries:', Object.keys(this.deferredEntrypoints));
for (const [name, entryData] of Object.entries(this.deferredEntrypoints)){
debug('processing deferred entry:', name, entryData);
// Normalize entry data structure
let entry;
if (typeof entryData === 'string') {
entry = {
import: [
entryData
]
};
} else if (Array.isArray(entryData)) {
entry = {
import: entryData
};
} else {
entry = entryData;
}
// Get imports array
const imports = entry.import ? Array.isArray(entry.import) ? entry.import : [
entry.import
] : [];
if (imports.length === 0) {
continue;
}
// Normalize dependOn to always be an array
const dependOn = entry.dependOn ? Array.isArray(entry.dependOn) ? entry.dependOn : [
entry.dependOn
] : undefined;
// Create dependencies for all imports
for (const importPath of imports){
if (typeof importPath !== 'string') {
continue;
}
const dep = bundler.EntryPlugin.createDependency(importPath, {
name
});
addEntryPromises.push(new Promise((resolve, reject)=>{
compilation.addEntry(compiler.context, dep, {
name,
layer: entry.layer,
runtime: entry.runtime,
dependOn
}, (err)=>{
if (err) {
reject(err);
} else {
resolve();
}
});
}));
}
}
await Promise.all(addEntryPromises);
});
}
}
//# sourceMappingURL=deferred-entries-plugin.js.map