flight-manifest-plugin.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. var _webpack = require("next/dist/compiled/webpack/webpack");
  6. var _constants = require("../../../shared/lib/constants");
  7. var _path = require("path");
  8. var _utils = require("../loaders/utils");
  9. const PLUGIN_NAME = "FlightManifestPlugin";
  10. class FlightManifestPlugin {
  11. dev = false;
  12. constructor(options){
  13. this.dev = options.dev;
  14. }
  15. apply(compiler) {
  16. compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation, { normalModuleFactory })=>{
  17. compilation.dependencyFactories.set(_webpack.webpack.dependencies.ModuleDependency, normalModuleFactory);
  18. compilation.dependencyTemplates.set(_webpack.webpack.dependencies.ModuleDependency, new _webpack.webpack.dependencies.NullDependency.Template());
  19. });
  20. compiler.hooks.make.tap(PLUGIN_NAME, (compilation)=>{
  21. compilation.hooks.processAssets.tap({
  22. name: PLUGIN_NAME,
  23. // Have to be in the optimize stage to run after updating the CSS
  24. // asset hash via extract mini css plugin.
  25. stage: _webpack.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_HASH
  26. }, (assets)=>this.createAsset(assets, compilation, compiler.context));
  27. });
  28. }
  29. createAsset(assets, compilation, context) {
  30. const manifest = {
  31. __ssr_module_mapping__: {}
  32. };
  33. const dev = this.dev;
  34. const clientRequestsSet = new Set();
  35. // Collect client requests
  36. function collectClientRequest(mod) {
  37. if (mod.resource === "" && mod.buildInfo.rsc) {
  38. const { requests =[] } = mod.buildInfo.rsc;
  39. requests.forEach((r)=>{
  40. clientRequestsSet.add(require.resolve(r));
  41. });
  42. }
  43. }
  44. compilation.chunkGroups.forEach((chunkGroup)=>{
  45. chunkGroup.chunks.forEach((chunk)=>{
  46. const chunkModules = compilation.chunkGraph.getChunkModulesIterable(chunk);
  47. for (const mod of chunkModules){
  48. collectClientRequest(mod);
  49. const anyModule = mod;
  50. if (anyModule.modules) {
  51. for (const subMod of anyModule.modules)collectClientRequest(subMod);
  52. }
  53. }
  54. });
  55. });
  56. compilation.chunkGroups.forEach((chunkGroup)=>{
  57. const cssResourcesInChunkGroup = new Set();
  58. let entryFilepath = "";
  59. function recordModule(chunk, id, mod) {
  60. var ref2, ref1;
  61. const isCSSModule = ((ref2 = mod.resource) == null ? void 0 : ref2.endsWith(".css")) || 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")));
  62. const resource = mod.type === "css/mini-extract" ? mod._identifier.slice(mod._identifier.lastIndexOf("!") + 1) : mod.resource;
  63. if (!resource) {
  64. return;
  65. }
  66. const moduleExports = manifest[resource] || {};
  67. const moduleIdMapping = manifest.__ssr_module_mapping__;
  68. // Note that this isn't that reliable as webpack is still possible to assign
  69. // additional queries to make sure there's no conflict even using the `named`
  70. // module ID strategy.
  71. let ssrNamedModuleId = (0, _path).relative(context, ((ref1 = mod.resourceResolveData) == null ? void 0 : ref1.path) || resource);
  72. if (!ssrNamedModuleId.startsWith(".")) // TODO use getModuleId instead
  73. ssrNamedModuleId = `./${ssrNamedModuleId.replace(/\\/g, "/")}`;
  74. if (isCSSModule) {
  75. if (!manifest[resource]) {
  76. const chunks = [
  77. ...chunk.files
  78. ].filter((f)=>f.endsWith(".css"));
  79. manifest[resource] = {
  80. default: {
  81. id,
  82. name: "default",
  83. chunks
  84. }
  85. };
  86. }
  87. if (chunkGroup.name) {
  88. cssResourcesInChunkGroup.add(resource);
  89. }
  90. return;
  91. }
  92. // Only apply following logic to client module requests from client entry,
  93. // or if the module is marked as client module.
  94. if (!clientRequestsSet.has(resource) && !(0, _utils).isClientComponentModule(mod)) {
  95. return;
  96. }
  97. if (/[\\/](page|layout)\.(ts|js)x?$/.test(resource)) {
  98. entryFilepath = resource;
  99. }
  100. const exportsInfo = compilation.moduleGraph.getExportsInfo(mod);
  101. const cjsExports = [
  102. ...new Set([
  103. ...mod.dependencies.map((dep)=>{
  104. // Match CommonJsSelfReferenceDependency
  105. if (dep.type === "cjs self exports reference") {
  106. // @ts-expect-error: TODO: Fix Dependency type
  107. if (dep.base === "module.exports") {
  108. return "default";
  109. }
  110. // `exports.foo = ...`, `exports.default = ...`
  111. // @ts-expect-error: TODO: Fix Dependency type
  112. if (dep.base === "exports") {
  113. // @ts-expect-error: TODO: Fix Dependency type
  114. return dep.names.filter((name)=>name !== "__esModule");
  115. }
  116. }
  117. return null;
  118. }),
  119. ]),
  120. ];
  121. function getAppPathRequiredChunks() {
  122. return chunkGroup.chunks.map((requiredChunk)=>{
  123. return requiredChunk.id + ":" + (requiredChunk.name || requiredChunk.id) + (dev ? "" : "-" + requiredChunk.hash);
  124. });
  125. }
  126. const moduleExportedKeys = [
  127. "",
  128. "*"
  129. ].concat([
  130. ...exportsInfo.exports
  131. ].filter((exportInfo)=>exportInfo.provided).map((exportInfo)=>exportInfo.name), ...cjsExports).filter((name)=>name !== null);
  132. moduleExportedKeys.forEach((name)=>{
  133. var ref;
  134. // If the chunk is from `app/` chunkGroup, use it first.
  135. // This make sure not to load the overlapped chunk from `pages/` chunkGroup
  136. if (!moduleExports[name] || ((ref = chunkGroup.name) == null ? void 0 : ref.startsWith("app/"))) {
  137. const requiredChunks = getAppPathRequiredChunks();
  138. moduleExports[name] = {
  139. id,
  140. name,
  141. chunks: requiredChunks
  142. };
  143. }
  144. moduleIdMapping[id] = moduleIdMapping[id] || {};
  145. moduleIdMapping[id][name] = {
  146. ...moduleExports[name],
  147. id: ssrNamedModuleId
  148. };
  149. });
  150. manifest[resource] = moduleExports;
  151. manifest.__ssr_module_mapping__ = moduleIdMapping;
  152. }
  153. chunkGroup.chunks.forEach((chunk)=>{
  154. const chunkModules = compilation.chunkGraph.getChunkModulesIterable(chunk);
  155. for (const mod of chunkModules){
  156. const modId = compilation.chunkGraph.getModuleId(mod);
  157. recordModule(chunk, modId, mod);
  158. // If this is a concatenation, register each child to the parent ID.
  159. // TODO: remove any
  160. const anyModule = mod;
  161. if (anyModule.modules) {
  162. anyModule.modules.forEach((concatenatedMod)=>{
  163. recordModule(chunk, modId, concatenatedMod);
  164. });
  165. }
  166. }
  167. });
  168. const clientCSSManifest = manifest.__client_css_manifest__ || {};
  169. if (entryFilepath) {
  170. clientCSSManifest[entryFilepath] = Array.from(cssResourcesInChunkGroup);
  171. }
  172. manifest.__client_css_manifest__ = clientCSSManifest;
  173. });
  174. const file = "server/" + _constants.FLIGHT_MANIFEST;
  175. const json = JSON.stringify(manifest);
  176. assets[file + ".js"] = new _webpack.sources.RawSource("self.__RSC_MANIFEST=" + json);
  177. assets[file + ".json"] = new _webpack.sources.RawSource(json);
  178. }
  179. }
  180. exports.FlightManifestPlugin = FlightManifestPlugin;
  181. //# sourceMappingURL=flight-manifest-plugin.js.map