UNPKG

next

Version:

The React Framework

191 lines (190 loc) • 10 kB
"use strict"; 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