123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.injectedClientEntries = void 0;
- var _querystring = require("querystring");
- var _path = _interopRequireDefault(require("path"));
- var _webpack = require("next/dist/compiled/webpack/webpack");
- var _onDemandEntryHandler = require("../../../server/dev/on-demand-entry-handler");
- var _constants = require("../../../lib/constants");
- var _constants1 = require("../../../shared/lib/constants");
- var _utils = require("../loaders/utils");
- function _interopRequireDefault(obj) {
- return obj && obj.__esModule ? obj : {
- default: obj
- };
- }
- const PLUGIN_NAME = "ClientEntryPlugin";
- const injectedClientEntries = new Map();
- exports.injectedClientEntries = injectedClientEntries;
- // TODO-APP: ensure .scss / .sass also works.
- const regexCSS = /\.css$/;
- // TODO-APP: move CSS manifest generation to the flight manifest plugin.
- const flightCSSManifest = {};
- class FlightClientEntryPlugin {
- constructor(options){
- this.dev = options.dev;
- 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.createClientEndpoints(compiler, compilation);
- });
- }
- async createClientEndpoints(compiler, compilation) {
- const promises = [];
- // For each SC server compilation entry, we need to create its corresponding
- // client component entry.
- for (const [name, entry] of compilation.entries.entries()){
- var ref;
- // 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);
- }
- });
- }
- const internalClientComponentEntryImports = new Set();
- for (const connection of compilation.moduleGraph.getOutgoingConnections(entryModule)){
- const layoutOrPageDependency = connection.dependency;
- const layoutOrPageRequest = connection.dependency.request;
- const [clientComponentImports, cssImports] = this.collectClientComponentsAndCSSForDependency({
- layoutOrPageRequest,
- compilation,
- dependency: layoutOrPageDependency
- });
- Object.assign(flightCSSManifest, cssImports);
- const isAbsoluteRequest = layoutOrPageRequest[0] === "/";
- // 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, layoutOrPageRequest) : layoutOrPageRequest;
- // Replace file suffix as `.js` will be added.
- const bundlePath = relativeRequest.replace(/\.(js|ts)x?$/, "");
- promises.push(this.injectClientEntryAndSSRModules({
- compiler,
- compilation,
- entryName: name,
- clientComponentImports,
- bundlePath
- }));
- }
- // Create internal app
- promises.push(this.injectClientEntryAndSSRModules({
- compiler,
- compilation,
- entryName: name,
- clientComponentImports: [
- ...internalClientComponentEntryImports
- ],
- bundlePath: "app-internals"
- }));
- }
- 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(flightCSSManifest);
- 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({ layoutOrPageRequest , compilation , dependency }) {
- /**
- * Keep track of checked modules to avoid infinite loops with recursive imports.
- */ const visitedBySegment = {};
- const clientComponentImports = [];
- const serverCSSImports = {};
- const filterClientComponents = (dependencyToFilter, inClientComponentBoundary)=>{
- var ref;
- const mod = compilation.moduleGraph.getResolvedModule(dependencyToFilter);
- if (!mod) return;
- // Keep client imports as simple
- // native or installed js module: -> raw request, e.g. next/head
- // client js or css: -> user request
- const rawRequest = mod.rawRequest;
- // Request could be undefined or ''
- if (!rawRequest) return;
- const modRequest = !rawRequest.endsWith(".css") && !rawRequest.startsWith(".") && !rawRequest.startsWith("/") && !rawRequest.startsWith(_constants.APP_DIR_ALIAS) ? rawRequest : (ref = mod.resourceResolveData) == null ? void 0 : ref.path;
- // Ensure module is not walked again if it's already been visited
- if (!visitedBySegment[layoutOrPageRequest]) {
- visitedBySegment[layoutOrPageRequest] = new Set();
- }
- if (!modRequest || visitedBySegment[layoutOrPageRequest].has(modRequest)) {
- return;
- }
- visitedBySegment[layoutOrPageRequest].add(modRequest);
- const isCSS = regexCSS.test(modRequest);
- const isClientComponent = (0, _utils).isClientComponentModule(mod);
- if (isCSS) {
- serverCSSImports[layoutOrPageRequest] = serverCSSImports[layoutOrPageRequest] || [];
- serverCSSImports[layoutOrPageRequest].push(modRequest);
- }
- // Check if request is for css file.
- if (!inClientComponentBoundary && isClientComponent || isCSS) {
- clientComponentImports.push(modRequest);
- 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
- };
- const clientLoader = `next-flight-client-entry-loader?${(0, _querystring).stringify(loaderOptions)}!`;
- 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 undefined for the SSR modules
- // This ensures the client components are
- layer: undefined
- });
- return shouldInvalidate;
- }
- // TODO-APP: make sure dependsOn is added for layouts/pages
- addEntry(compilation, context, entry /* Dependency */ , options /* EntryOptions */ ) /* Promise<module> */ {
- return new Promise((resolve, reject)=>{
- compilation.entries.get(options.name).includeDependencies.push(entry);
- compilation.hooks.addEntry.call(entry, options);
- compilation.addModuleTree({
- context,
- dependency: entry,
- contextInfo: {
- issuerLayer: options.layer
- }
- }, (err, module)=>{
- if (err) {
- compilation.hooks.failedEntry.call(entry, options, err);
- return reject(err);
- }
- compilation.hooks.succeedEntry.call(entry, options, module);
- return resolve(module);
- });
- });
- }
- }
- exports.FlightClientEntryPlugin = FlightClientEntryPlugin;
- //# sourceMappingURL=flight-client-entry-plugin.js.map
|