next
Version:
The React Framework
191 lines (190 loc) • 10 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
var _webpack = require("next/dist/compiled/webpack/webpack");
var _constants = require("../../../shared/lib/constants");
var _utils = require("../loaders/utils");
var _path = require("path");
const PLUGIN_NAME = "FlightManifestPlugin";
class FlightManifestPlugin {
dev = false;
appDir = false;
constructor(options){
this.dev = options.dev;
this.appDir = options.appDir;
this.pageExtensions = options.pageExtensions;
}
apply(compiler) {
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation, { normalModuleFactory })=>{
compilation.dependencyFactories.set(_webpack.webpack.dependencies.ModuleDependency, normalModuleFactory);
compilation.dependencyTemplates.set(_webpack.webpack.dependencies.ModuleDependency, new _webpack.webpack.dependencies.NullDependency.Template());
});
compiler.hooks.make.tap(PLUGIN_NAME, (compilation)=>{
compilation.hooks.processAssets.tap({
name: PLUGIN_NAME,
// Have to be in the optimize stage to run after updating the CSS
// asset hash via extract mini css plugin.
// @ts-ignore TODO: Remove ignore when webpack 5 is stable
stage: _webpack.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_HASH
}, (assets)=>this.createAsset(assets, compilation, compiler.context));
});
}
createAsset(assets, compilation, context) {
const manifest = {
__ssr_module_mapping__: {}
};
const appDir = this.appDir;
const dev = this.dev;
compilation.chunkGroups.forEach((chunkGroup)=>{
function recordModule(chunk, id, mod) {
var ref3, ref1;
// if appDir is enabled we shouldn't process chunks from
// the pages dir
if (((ref3 = chunk.name) == null ? void 0 : ref3.startsWith("pages/")) && appDir) {
return;
}
const isCSSModule = mod.type === "css/mini-extract" || mod.loaders && (dev ? mod.loaders.some((item)=>item.loader.includes("next-style-loader/index.js")) : mod.loaders.some((item)=>item.loader.includes("mini-css-extract-plugin/loader.js")));
const resource = mod.type === "css/mini-extract" ? mod._identifier.slice(mod._identifier.lastIndexOf("!") + 1) : mod.resource;
if (!resource) return;
const moduleExports = manifest[resource] || {};
const moduleIdMapping = manifest.__ssr_module_mapping__;
moduleIdMapping[id] = moduleIdMapping[id] || {};
// Note that this isn't that reliable as webpack is still possible to assign
// additional queries to make sure there's no conflict even using the `named`
// module ID strategy.
let ssrNamedModuleId = (0, _path).relative(context, ((ref1 = mod.resourceResolveData) == null ? void 0 : ref1.path) || resource);
if (!ssrNamedModuleId.startsWith(".")) ssrNamedModuleId = `./${ssrNamedModuleId}`;
if (isCSSModule) {
if (!manifest[resource]) {
const chunks = [
...chunk.files
].filter((f)=>f.endsWith(".css"));
manifest[resource] = {
default: {
id,
name: "default",
chunks
}
};
moduleIdMapping[id]["default"] = {
id: ssrNamedModuleId,
name: "default",
chunks
};
manifest.__ssr_module_mapping__ = moduleIdMapping;
}
return;
}
// TODO: Hook into deps instead of the target module.
// That way we know by the type of dep whether to include.
// It also resolves conflicts when the same module is in multiple chunks.
if (!_utils.clientComponentRegex.test(resource)) {
return;
}
const exportsInfo = compilation.moduleGraph.getExportsInfo(mod);
const cjsExports = [
...new Set([
...mod.dependencies.map((dep)=>{
// Match CommonJsSelfReferenceDependency
if (dep.type === "cjs self exports reference") {
// `module.exports = ...`
// @ts-expect-error: TODO: Fix Dependency type
if (dep.base === "module.exports") {
return "default";
}
// `exports.foo = ...`, `exports.default = ...`
// @ts-expect-error: TODO: Fix Dependency type
if (dep.base === "exports") {
// @ts-expect-error: TODO: Fix Dependency type
return dep.names.filter((name)=>name !== "__esModule");
}
}
return null;
}),
]),
];
const moduleExportedKeys = [
"",
"*"
].concat([
...exportsInfo.exports
].filter((exportInfo)=>exportInfo.provided).map((exportInfo)=>exportInfo.name), ...cjsExports).filter((name)=>name !== null);
// Get all CSS files imported from the module's dependencies.
const visitedModule = new Set();
const cssChunks = new Set();
function collectClientImportedCss(module) {
if (!module) return;
const modRequest = module.userRequest;
if (visitedModule.has(modRequest)) return;
visitedModule.add(modRequest);
if (/\.css$/.test(modRequest)) {
// collect relative imported css chunks
compilation.chunkGraph.getModuleChunks(module).forEach((c)=>{
[
...c.files
].filter((file)=>file.endsWith(".css")).forEach((file)=>cssChunks.add(file));
});
}
const connections = Array.from(compilation.moduleGraph.getOutgoingConnections(module));
connections.forEach((connection)=>{
collectClientImportedCss(compilation.moduleGraph.getResolvedModule(connection.dependency));
});
}
collectClientImportedCss(mod);
moduleExportedKeys.forEach((name)=>{
let requiredChunks = [];
if (!moduleExports[name]) {
const isRelatedChunk = (c)=>{
var // If current chunk is a page, it should require the related page chunk;
// If current chunk is a component, it should filter out the related page chunk;
ref, ref2;
return ((ref = chunk.name) == null ? void 0 : ref.startsWith("pages/")) || !((ref2 = c.name) == null ? void 0 : ref2.startsWith("pages/"));
};
if (appDir) {
requiredChunks = chunkGroup.chunks.filter(isRelatedChunk).map((requiredChunk)=>{
return requiredChunk.id + ":" + (requiredChunk.name || requiredChunk.id) + (dev ? "" : "-" + requiredChunk.hash);
});
}
moduleExports[name] = {
id,
name,
chunks: requiredChunks.concat([
...cssChunks
])
};
}
if (!moduleIdMapping[id][name]) {
moduleIdMapping[id][name] = {
...moduleExports[name],
id: ssrNamedModuleId
};
}
});
manifest[resource] = moduleExports;
manifest.__ssr_module_mapping__ = moduleIdMapping;
}
chunkGroup.chunks.forEach((chunk)=>{
const chunkModules = compilation.chunkGraph.getChunkModulesIterable(chunk);
for (const mod of chunkModules){
const modId = compilation.chunkGraph.getModuleId(mod);
recordModule(chunk, modId, mod);
// If this is a concatenation, register each child to the parent ID.
// TODO: remove any
const anyModule = mod;
if (anyModule.modules) {
anyModule.modules.forEach((concatenatedMod)=>{
recordModule(chunk, modId, concatenatedMod);
});
}
}
});
});
const file1 = "server/" + _constants.FLIGHT_MANIFEST;
const json = JSON.stringify(manifest);
assets[file1 + ".js"] = new _webpack.sources.RawSource("self.__RSC_MANIFEST=" + json);
assets[file1 + ".json"] = new _webpack.sources.RawSource(json);
}
}
exports.FlightManifestPlugin = FlightManifestPlugin;
//# sourceMappingURL=flight-manifest-plugin.js.map
;