Files
old-kitabcitab-frontend/kitabcitab/node_modules/next/dist/build/webpack/plugins/flight-client-entry-plugin.js

400 lines
20 KiB
JavaScript
Raw Normal View History

2022-12-27 12:05:56 +01:00
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.edgeServerModuleIds = exports.serverModuleIds = exports.injectedClientEntries = void 0;
var _webpack = require("next/dist/compiled/webpack/webpack");
var _querystring = require("querystring");
var _path = _interopRequireDefault(require("path"));
var _onDemandEntryHandler = require("../../../server/dev/on-demand-entry-handler");
var _constants = require("../../../lib/constants");
var _constants1 = require("../../../shared/lib/constants");
var _flightManifestPlugin = require("./flight-manifest-plugin");
var _utils = require("../loaders/utils");
var _utils1 = require("../utils");
var _normalizePathSep = require("../../../shared/lib/page-path/normalize-path-sep");
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
const PLUGIN_NAME = "ClientEntryPlugin";
const injectedClientEntries = new Map();
exports.injectedClientEntries = injectedClientEntries;
const serverModuleIds = new Map();
exports.serverModuleIds = serverModuleIds;
const edgeServerModuleIds = new Map();
exports.edgeServerModuleIds = edgeServerModuleIds;
let serverCSSManifest = {};
let edgeServerCSSManifest = {};
class FlightClientEntryPlugin {
constructor(options){
this.dev = options.dev;
this.appDir = options.appDir;
this.isEdgeServer = options.isEdgeServer;
}
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.finishMake.tapPromise(PLUGIN_NAME, (compilation)=>{
return this.createClientEntries(compiler, compilation);
});
compiler.hooks.afterCompile.tap(PLUGIN_NAME, (compilation)=>{
(0, _utils1).traverseModules(compilation, (mod)=>{
// const modId = compilation.chunkGraph.getModuleId(mod) + ''
// The module must has request, and resource so it's not a new entry created with loader.
// Using the client layer module, which doesn't have `rsc` tag in buildInfo.
if (mod.request && mod.resource && !mod.buildInfo.rsc) {
if (compilation.moduleGraph.isAsync(mod)) {
_flightManifestPlugin.ASYNC_CLIENT_MODULES.add(mod.resource);
}
}
});
const recordModule = (modId, mod)=>{
var ref;
const modResource = ((ref = mod.resourceResolveData) == null ? void 0 : ref.path) || mod.resource;
if (mod.layer !== _constants.WEBPACK_LAYERS.client) {
return;
}
// Check mod resource to exclude the empty resource module like virtual module created by next-flight-client-entry-loader
if (typeof modId !== "undefined" && modResource) {
// 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 = _path.default.relative(compiler.context, modResource);
if (!ssrNamedModuleId.startsWith(".")) {
// TODO use getModuleId instead
ssrNamedModuleId = `./${(0, _normalizePathSep).normalizePathSep(ssrNamedModuleId)}`;
}
if (this.isEdgeServer) {
edgeServerModuleIds.set(ssrNamedModuleId.replace(/\/next\/dist\/esm\//, "/next/dist/"), modId);
} else {
serverModuleIds.set(ssrNamedModuleId, modId);
}
}
};
(0, _utils1).traverseModules(compilation, (mod, _chunk, _chunkGroup, modId)=>{
recordModule(String(modId), mod);
});
});
}
async createClientEntries(compiler, compilation) {
const promises = [];
// Loop over all the entry modules.
function forEachEntryModule(callback) {
for (const [name, entry] of compilation.entries.entries()){
var ref;
// Skip for entries under pages/
if (name.startsWith("pages/")) continue;
// Check if the page entry is a server component or not.
const entryDependency = (ref = entry.dependencies) == null ? void 0 : ref[0];
// Ensure only next-app-loader entries are handled.
if (!entryDependency || !entryDependency.request) continue;
const request = entryDependency.request;
if (!request.startsWith("next-edge-ssr-loader?") && !request.startsWith("next-app-loader?")) continue;
let entryModule = compilation.moduleGraph.getResolvedModule(entryDependency);
if (request.startsWith("next-edge-ssr-loader?")) {
entryModule.dependencies.forEach((dependency)=>{
const modRequest = dependency.request;
if (modRequest == null ? void 0 : modRequest.includes("next-app-loader")) {
entryModule = compilation.moduleGraph.getResolvedModule(dependency);
}
});
}
callback({
name,
entryModule
});
}
}
// For each SC server compilation entry, we need to create its corresponding
// client component entry.
forEachEntryModule(({ name , entryModule })=>{
const internalClientComponentEntryImports = new Set();
for (const connection of compilation.moduleGraph.getOutgoingConnections(entryModule)){
// Entry can be any user defined entry files such as layout, page, error, loading, etc.
const entryDependency = connection.dependency;
const entryRequest = connection.dependency.request;
const [clientComponentImports] = this.collectClientComponentsAndCSSForDependency({
entryRequest,
compilation,
dependency: entryDependency
});
const isAbsoluteRequest = _path.default.isAbsolute(entryRequest);
// Next.js internals are put into a separate entry.
if (!isAbsoluteRequest) {
clientComponentImports.forEach((value)=>internalClientComponentEntryImports.add(value));
continue;
}
const relativeRequest = isAbsoluteRequest ? _path.default.relative(compilation.options.context, entryRequest) : entryRequest;
// Replace file suffix as `.js` will be added.
const bundlePath = (0, _normalizePathSep).normalizePathSep(relativeRequest.replace(/\.(js|ts)x?$/, "").replace(/^src[\\/]/, ""));
promises.push(this.injectClientEntryAndSSRModules({
compiler,
compilation,
entryName: name,
clientComponentImports,
bundlePath
}));
}
// Create internal app
promises.push(this.injectClientEntryAndSSRModules({
compiler,
compilation,
entryName: name,
clientComponentImports: [
...internalClientComponentEntryImports
],
bundlePath: _constants1.APP_CLIENT_INTERNALS
}));
});
// After optimizing all the modules, we collect the CSS that are still used
// by the certain chunk.
compilation.hooks.afterOptimizeModules.tap(PLUGIN_NAME, ()=>{
const cssImportsForChunk = {};
if (this.isEdgeServer) {
edgeServerCSSManifest = {};
} else {
serverCSSManifest = {};
}
let cssManifest = this.isEdgeServer ? edgeServerCSSManifest : serverCSSManifest;
function collectModule(entryName, mod) {
const resource = mod.resource;
const modId = resource;
if (modId) {
if (_utils.regexCSS.test(modId)) {
cssImportsForChunk[entryName].push(modId);
}
}
}
compilation.chunkGroups.forEach((chunkGroup)=>{
chunkGroup.chunks.forEach((chunk)=>{
// Here we only track page chunks.
if (!chunk.name) return;
if (!chunk.name.endsWith("/page")) return;
const entryName = _path.default.join(this.appDir, "..", chunk.name);
if (!cssImportsForChunk[entryName]) {
cssImportsForChunk[entryName] = [];
}
const chunkModules = compilation.chunkGraph.getChunkModulesIterable(chunk);
for (const mod of chunkModules){
collectModule(entryName, mod);
const anyModule = mod;
if (anyModule.modules) {
anyModule.modules.forEach((concatenatedMod)=>{
collectModule(entryName, concatenatedMod);
});
}
}
const entryCSSInfo = cssManifest.__entry_css_mods__ || {};
entryCSSInfo[entryName] = cssImportsForChunk[entryName];
Object.assign(cssManifest, {
__entry_css_mods__: entryCSSInfo
});
});
});
forEachEntryModule(({ name , entryModule })=>{
// To collect all CSS imports for a specific entry including the ones
// that are in the client graph, we need to store a map for client boundary
// dependencies.
const clientEntryDependencyMap = {};
const entry = compilation.entries.get(name);
entry.includeDependencies.forEach((dep)=>{
if (dep.request && dep.request.startsWith("next-flight-client-entry-loader?")) {
const mod = compilation.moduleGraph.getResolvedModule(dep);
compilation.moduleGraph.getOutgoingConnections(mod).forEach((connection)=>{
if (connection.dependency) {
clientEntryDependencyMap[connection.dependency.request] = connection.dependency;
}
});
}
});
for (const connection1 of compilation.moduleGraph.getOutgoingConnections(entryModule)){
const entryDependency = connection1.dependency;
const entryRequest = connection1.dependency.request;
const [, cssImports] = this.collectClientComponentsAndCSSForDependency({
entryRequest,
compilation,
dependency: entryDependency,
clientEntryDependencyMap
});
Object.assign(cssManifest, cssImports);
}
});
});
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.
stage: _webpack.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_HASH
}, (assets)=>{
const manifest = JSON.stringify({
...serverCSSManifest,
...edgeServerCSSManifest,
__entry_css_mods__: {
...serverCSSManifest.__entry_css_mods__,
...edgeServerCSSManifest.__entry_css_mods__
}
}, null, this.dev ? 2 : undefined);
assets[_constants1.FLIGHT_SERVER_CSS_MANIFEST + ".json"] = new _webpack.sources.RawSource(manifest);
assets[_constants1.FLIGHT_SERVER_CSS_MANIFEST + ".js"] = new _webpack.sources.RawSource("self.__RSC_CSS_MANIFEST=" + manifest);
});
const res = await Promise.all(promises);
// Invalidate in development to trigger recompilation
const invalidator = (0, _onDemandEntryHandler).getInvalidator();
// Check if any of the entry injections need an invalidation
if (invalidator && res.includes(true)) {
invalidator.invalidate([
_constants1.COMPILER_NAMES.client
]);
}
}
collectClientComponentsAndCSSForDependency({ entryRequest , compilation , dependency , clientEntryDependencyMap }) {
/**
* Keep track of checked modules to avoid infinite loops with recursive imports.
*/ const visitedBySegment = {};
const clientComponentImports = [];
const serverCSSImports = {};
const filterClientComponents = (dependencyToFilter, inClientComponentBoundary)=>{
var ref, ref1;
const mod = compilation.moduleGraph.getResolvedModule(dependencyToFilter);
if (!mod) return;
const rawRequest = mod.rawRequest;
const isCSS = _utils.regexCSS.test(rawRequest);
// We have to always use the resolved request here to make sure the
// server and client are using the same module path (required by RSC), as
// the server compiler and client compiler have different resolve configs.
const modRequest = ((ref = mod.resourceResolveData) == null ? void 0 : ref.path) + ((ref1 = mod.resourceResolveData) == null ? void 0 : ref1.query);
// Ensure module is not walked again if it's already been visited
if (!visitedBySegment[entryRequest]) {
visitedBySegment[entryRequest] = new Set();
}
const storeKey = (inClientComponentBoundary ? "0" : "1") + ":" + modRequest;
if (!modRequest || visitedBySegment[entryRequest].has(storeKey)) {
return;
}
visitedBySegment[entryRequest].add(storeKey);
const isClientComponent = (0, _utils).isClientComponentModule(mod);
if (isCSS) {
const sideEffectFree = mod.factoryMeta && mod.factoryMeta.sideEffectFree;
if (sideEffectFree) {
const unused = !compilation.moduleGraph.getExportsInfo(mod).isModuleUsed(this.isEdgeServer ? _constants1.EDGE_RUNTIME_WEBPACK : "webpack-runtime");
if (unused) {
return;
}
}
serverCSSImports[entryRequest] = serverCSSImports[entryRequest] || [];
serverCSSImports[entryRequest].push(modRequest);
}
// Check if request is for css file.
if (!inClientComponentBoundary && isClientComponent || isCSS) {
clientComponentImports.push(modRequest);
// Here we are entering a client boundary, and we need to collect dependencies
// in the client graph too.
if (isClientComponent && clientEntryDependencyMap) {
if (clientEntryDependencyMap[modRequest]) {
filterClientComponents(clientEntryDependencyMap[modRequest], true);
}
}
return;
}
compilation.moduleGraph.getOutgoingConnections(mod).forEach((connection)=>{
filterClientComponents(connection.dependency, inClientComponentBoundary || isClientComponent);
});
};
// Traverse the module graph to find all client components.
filterClientComponents(dependency, false);
return [
clientComponentImports,
serverCSSImports
];
}
async injectClientEntryAndSSRModules({ compiler , compilation , entryName , clientComponentImports , bundlePath }) {
let shouldInvalidate = false;
const loaderOptions = {
modules: clientComponentImports,
server: false
};
// For the client entry, we always use the CJS build of Next.js. If the
// server is using the ESM build (when using the Edge runtime), we need to
// replace them.
const clientLoader = `next-flight-client-entry-loader?${(0, _querystring).stringify({
modules: this.isEdgeServer ? clientComponentImports.map((importPath)=>importPath.replace("next/dist/esm/", "next/dist/")) : clientComponentImports,
server: false
})}!`;
const clientSSRLoader = `next-flight-client-entry-loader?${(0, _querystring).stringify({
...loaderOptions,
server: true
})}!`;
// Add for the client compilation
// Inject the entry to the client compiler.
if (this.dev) {
const pageKey = _constants1.COMPILER_NAMES.client + bundlePath;
if (!_onDemandEntryHandler.entries[pageKey]) {
_onDemandEntryHandler.entries[pageKey] = {
type: _onDemandEntryHandler.EntryTypes.CHILD_ENTRY,
parentEntries: new Set([
entryName
]),
bundlePath,
request: clientLoader,
dispose: false,
lastActiveTime: Date.now()
};
shouldInvalidate = true;
} else {
const entryData = _onDemandEntryHandler.entries[pageKey];
// New version of the client loader
if (entryData.request !== clientLoader) {
entryData.request = clientLoader;
shouldInvalidate = true;
}
if (entryData.type === _onDemandEntryHandler.EntryTypes.CHILD_ENTRY) {
entryData.parentEntries.add(entryName);
}
}
} else {
injectedClientEntries.set(bundlePath, clientLoader);
}
// Inject the entry to the server compiler (__sc_client__).
const clientComponentEntryDep = _webpack.webpack.EntryPlugin.createDependency(clientSSRLoader, {
name: bundlePath
});
// Add the dependency to the server compiler.
await this.addEntry(compilation, // Reuse compilation context.
compiler.context, clientComponentEntryDep, {
// By using the same entry name
name: entryName,
// Layer should be client for the SSR modules
// This ensures the client components are bundled on client layer
layer: _constants.WEBPACK_LAYERS.client
});
return shouldInvalidate;
}
addEntry(compilation, context, dependency, options) /* Promise<module> */ {
return new Promise((resolve, reject)=>{
const entry = compilation.entries.get(options.name);
entry.includeDependencies.push(dependency);
compilation.hooks.addEntry.call(entry, options);
compilation.addModuleTree({
context,
dependency,
contextInfo: {
issuerLayer: options.layer
}
}, (err, module)=>{
if (err) {
compilation.hooks.failedEntry.call(dependency, options, err);
return reject(err);
}
compilation.hooks.succeedEntry.call(dependency, options, module);
return resolve(module);
});
});
}
}
exports.FlightClientEntryPlugin = FlightClientEntryPlugin;
//# sourceMappingURL=flight-client-entry-plugin.js.map