next
Version:
The React Framework
148 lines (147 loc) • 7.86 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.ssrEntries = void 0;
var _webpack = require("next/dist/compiled/webpack/webpack");
var _utils = require("../../../shared/lib/router/utils");
var _constants = require("../../../shared/lib/constants");
var _constants1 = require("../../../lib/constants");
var _nonNullable = require("../../../lib/non-nullable");
const PLUGIN_NAME = 'MiddlewarePlugin';
const MIDDLEWARE_FULL_ROUTE_REGEX = /^pages[/\\]?(.*)\/_middleware$/;
const ssrEntries = new Map();
exports.ssrEntries = ssrEntries;
class MiddlewarePlugin {
constructor({ dev }){
this.dev = dev;
}
createAssets(compilation, assets, envPerRoute) {
const entrypoints = compilation.entrypoints;
const middlewareManifest = {
sortedMiddleware: [],
clientInfo: [],
middleware: {
},
version: 1
};
for (const entrypoint of entrypoints.values()){
const result = MIDDLEWARE_FULL_ROUTE_REGEX.exec(entrypoint.name);
const ssrEntryInfo = ssrEntries.get(entrypoint.name);
const location = result ? `/${result[1]}` : ssrEntryInfo ? entrypoint.name.slice('pages'.length).replace(/\/index$/, '') || '/' : null;
if (!location) {
continue;
}
const files = ssrEntryInfo ? [
`server/${_constants.MIDDLEWARE_SSR_RUNTIME_WEBPACK}.js`,
ssrEntryInfo.requireFlightManifest ? `server/${_constants.MIDDLEWARE_FLIGHT_MANIFEST}.js` : null,
`server/${_constants.MIDDLEWARE_BUILD_MANIFEST}.js`,
`server/${_constants.MIDDLEWARE_REACT_LOADABLE_MANIFEST}.js`,
`server/${entrypoint.name}.js`,
].filter(_nonNullable.nonNullable) : entrypoint.getFiles().filter((file)=>!file.endsWith('.hot-update.js')
).map((file)=>// we need to use the unminified version of the webpack runtime,
// remove if we do start minifying middleware chunks
file.startsWith('static/chunks/webpack-') ? file.replace('webpack-', 'webpack-middleware-') : file
);
middlewareManifest.middleware[location] = {
env: envPerRoute.get(entrypoint.name) || [],
files,
name: entrypoint.name,
page: location,
regexp: (0, _utils).getMiddlewareRegex(location, !ssrEntryInfo).namedRegex
};
}
middlewareManifest.sortedMiddleware = (0, _utils).getSortedRoutes(Object.keys(middlewareManifest.middleware));
middlewareManifest.clientInfo = middlewareManifest.sortedMiddleware.map((key)=>{
const ssrEntryInfo = ssrEntries.get(middlewareManifest.middleware[key].name);
return [
key,
!!ssrEntryInfo
];
});
assets[`server/${_constants.MIDDLEWARE_MANIFEST}`] = new _webpack.sources.RawSource(JSON.stringify(middlewareManifest, null, 2));
}
apply(compiler) {
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation, { normalModuleFactory })=>{
const envPerRoute = new Map();
compilation.hooks.finishModules.tap(PLUGIN_NAME, ()=>{
const { moduleGraph } = compilation;
envPerRoute.clear();
for (const [name, info] of compilation.entries){
if (name.match(_constants1.MIDDLEWARE_ROUTE)) {
const middlewareEntries = new Set();
const env = new Set();
const addEntriesFromDependency = (dep)=>{
const module = moduleGraph.getModule(dep);
if (module) {
middlewareEntries.add(module);
}
};
info.dependencies.forEach(addEntriesFromDependency);
info.includeDependencies.forEach(addEntriesFromDependency);
const queue = new Set(middlewareEntries);
for (const module of queue){
const { buildInfo } = module;
if (buildInfo === null || buildInfo === void 0 ? void 0 : buildInfo.usingIndirectEval) {
// @ts-ignore TODO: Remove ignore when webpack 5 is stable
const error = new _webpack.webpack.WebpackError(`\`eval\` not allowed in Middleware ${name}`);
error.module = module;
compilation.warnings.push(error);
}
if ((buildInfo === null || buildInfo === void 0 ? void 0 : buildInfo.nextUsedEnvVars) !== undefined) {
for (const envName of buildInfo.nextUsedEnvVars){
env.add(envName);
}
}
const connections = moduleGraph.getOutgoingConnections(module);
for (const connection of connections){
if (connection.module) {
queue.add(connection.module);
}
}
}
envPerRoute.set(name, Array.from(env));
}
}
});
const handler = (parser)=>{
const flagModule = ()=>{
parser.state.module.buildInfo.usingIndirectEval = true;
};
parser.hooks.expression.for('eval').tap(PLUGIN_NAME, flagModule);
parser.hooks.expression.for('Function').tap(PLUGIN_NAME, flagModule);
parser.hooks.expression.for('global.eval').tap(PLUGIN_NAME, flagModule);
parser.hooks.expression.for('global.Function').tap(PLUGIN_NAME, flagModule);
const memberChainHandler = (_expr, members)=>{
if (!parser.state.module || parser.state.module.layer !== 'middleware') {
return;
}
if (members.length >= 2 && members[0] === 'env') {
const envName = members[1];
const { buildInfo } = parser.state.module;
if (buildInfo.nextUsedEnvVars === undefined) {
buildInfo.nextUsedEnvVars = new Set();
}
buildInfo.nextUsedEnvVars.add(envName);
return true;
}
};
parser.hooks.callMemberChain.for('process').tap(PLUGIN_NAME, memberChainHandler);
parser.hooks.expressionMemberChain.for('process').tap(PLUGIN_NAME, memberChainHandler);
};
normalModuleFactory.hooks.parser.for('javascript/auto').tap(PLUGIN_NAME, handler);
normalModuleFactory.hooks.parser.for('javascript/dynamic').tap(PLUGIN_NAME, handler);
normalModuleFactory.hooks.parser.for('javascript/esm').tap(PLUGIN_NAME, handler);
// @ts-ignore TODO: Remove ignore when webpack 5 is stable
compilation.hooks.processAssets.tap({
name: 'NextJsMiddlewareManifest',
// @ts-ignore TODO: Remove ignore when webpack 5 is stable
stage: _webpack.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
}, (assets)=>{
this.createAssets(compilation, assets, envPerRoute);
});
});
}
}
exports.default = MiddlewarePlugin;
//# sourceMappingURL=middleware-plugin.js.map
;