next
Version:
The React Framework
330 lines (329 loc) • 15.2 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getPageFromPath = getPageFromPath;
exports.createPagesMapping = createPagesMapping;
exports.getPageRuntime = getPageRuntime;
exports.invalidatePageRuntimeCache = invalidatePageRuntimeCache;
exports.createEntrypoints = createEntrypoints;
exports.finalizeEntrypoint = finalizeEntrypoint;
var _fs = _interopRequireDefault(require("fs"));
var _chalk = _interopRequireDefault(require("next/dist/compiled/chalk"));
var _path = require("path");
var _querystring = require("querystring");
var _constants = require("../lib/constants");
var _utils = require("../server/utils");
var _normalizePagePath = require("../server/normalize-page-path");
var _log = require("./output/log");
var _swc = require("../build/swc");
var _utils1 = require("./utils");
var _middlewarePlugin = require("./webpack/plugins/middleware-plugin");
var _constants1 = require("../shared/lib/constants");
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function getPageFromPath(pagePath, extensions) {
const rawExtensions = (0, _utils1).getRawPageExtensions(extensions);
const pickedExtensions = pagePath.includes('/_app.server.') ? rawExtensions : extensions;
let page = pagePath.replace(new RegExp(`\\.+(${pickedExtensions.join('|')})$`), '');
page = page.replace(/\\/g, '/').replace(/\/index$/, '');
return page === '' ? '/' : page;
}
function createPagesMapping(pagePaths, extensions, { isDev , hasServerComponents }) {
const previousPages = {};
// Do not process .d.ts files inside the `pages` folder
pagePaths = extensions.includes('ts') ? pagePaths.filter((pagePath)=>!pagePath.endsWith('.d.ts')
) : pagePaths;
const pages = pagePaths.reduce((result, pagePath)=>{
const pageKey = getPageFromPath(pagePath, extensions);
if (hasServerComponents && /\.client$/.test(pageKey)) {
// Assume that if there's a Client Component, that there is
// a matching Server Component that will map to the page.
return result;
}
if (pageKey in result) {
(0, _log).warn(`Duplicate page detected. ${_chalk.default.cyan((0, _path).join('pages', previousPages[pageKey]))} and ${_chalk.default.cyan((0, _path).join('pages', pagePath))} both resolve to ${_chalk.default.cyan(pageKey)}.`);
} else {
previousPages[pageKey] = pagePath;
}
result[pageKey] = (0, _path).join(_constants.PAGES_DIR_ALIAS, pagePath).replace(/\\/g, '/');
return result;
}, {});
// we alias these in development and allow webpack to
// allow falling back to the correct source file so
// that HMR can work properly when a file is added/removed
if (isDev) {
if (hasServerComponents) {
pages['/_app.server'] = `${_constants.PAGES_DIR_ALIAS}/_app.server`;
}
pages['/_app'] = `${_constants.PAGES_DIR_ALIAS}/_app`;
pages['/_error'] = `${_constants.PAGES_DIR_ALIAS}/_error`;
pages['/_document'] = `${_constants.PAGES_DIR_ALIAS}/_document`;
} else {
if (hasServerComponents) {
pages['/_app.server'] = pages['/_app.server'] || 'next/dist/pages/_app.server';
}
pages['/_app'] = pages['/_app'] || 'next/dist/pages/_app';
pages['/_error'] = pages['/_error'] || 'next/dist/pages/_error';
pages['/_document'] = pages['/_document'] || 'next/dist/pages/_document';
}
return pages;
}
const cachedPageRuntimeConfig = new Map();
async function getPageRuntime(pageFilePath, nextConfig, isDev) {
var ref, ref1;
if (!((ref = nextConfig.experimental) === null || ref === void 0 ? void 0 : ref.reactRoot)) return undefined;
const globalRuntime = (ref1 = nextConfig.experimental) === null || ref1 === void 0 ? void 0 : ref1.runtime;
const cached = cachedPageRuntimeConfig.get(pageFilePath);
if (cached) {
return cached[1];
}
let pageContent;
try {
pageContent = await _fs.default.promises.readFile(pageFilePath, {
encoding: 'utf8'
});
} catch (err) {
if (!isDev) throw err;
return undefined;
}
// When gSSP or gSP is used, this page requires an execution runtime. If the
// page config is not present, we fallback to the global runtime. Related
// discussion:
// https://github.com/vercel/next.js/discussions/34179
let isRuntimeRequired = false;
let pageRuntime = undefined;
// Since these configurations should always be static analyzable, we can
// skip these cases that "runtime" and "gSP", "gSSP" are not included in the
// source code.
if (/runtime|getStaticProps|getServerSideProps/.test(pageContent)) {
try {
const { body } = await (0, _swc).parse(pageContent, {
filename: pageFilePath,
isModule: 'unknown'
});
for (const node of body){
const { type , declaration } = node;
if (type === 'ExportDeclaration') {
var ref2, ref3;
// Match `export const config`
const valueNode = declaration === null || declaration === void 0 ? void 0 : (ref2 = declaration.declarations) === null || ref2 === void 0 ? void 0 : ref2[0];
if ((valueNode === null || valueNode === void 0 ? void 0 : (ref3 = valueNode.id) === null || ref3 === void 0 ? void 0 : ref3.value) === 'config') {
var ref4;
const props = valueNode.init.properties;
const runtimeKeyValue = props.find((prop)=>prop.key.value === 'runtime'
);
const runtime = runtimeKeyValue === null || runtimeKeyValue === void 0 ? void 0 : (ref4 = runtimeKeyValue.value) === null || ref4 === void 0 ? void 0 : ref4.value;
pageRuntime = runtime === 'edge' || runtime === 'nodejs' ? runtime : pageRuntime;
} else if ((declaration === null || declaration === void 0 ? void 0 : declaration.type) === 'FunctionDeclaration') {
var ref5;
// Match `export function getStaticProps | getServerSideProps`
const identifier = (ref5 = declaration.identifier) === null || ref5 === void 0 ? void 0 : ref5.value;
if (identifier === 'getStaticProps' || identifier === 'getServerSideProps') {
isRuntimeRequired = true;
}
}
} else if (type === 'ExportNamedDeclaration') {
// Match `export { getStaticProps | getServerSideProps } <from '../..'>`
const { specifiers } = node;
for (const specifier of specifiers){
const { orig } = specifier;
const hasDataFetchingExports = specifier.type === 'ExportSpecifier' && (orig === null || orig === void 0 ? void 0 : orig.type) === 'Identifier' && ((orig === null || orig === void 0 ? void 0 : orig.value) === 'getStaticProps' || (orig === null || orig === void 0 ? void 0 : orig.value) === 'getServerSideProps');
if (hasDataFetchingExports) {
isRuntimeRequired = true;
break;
}
}
}
}
} catch (err) {}
}
if (!pageRuntime) {
if (isRuntimeRequired) {
pageRuntime = globalRuntime;
}
}
cachedPageRuntimeConfig.set(pageFilePath, [
Date.now(),
pageRuntime
]);
return pageRuntime;
}
function invalidatePageRuntimeCache(pageFilePath, safeTime) {
const cached = cachedPageRuntimeConfig.get(pageFilePath);
if (cached && cached[0] < safeTime) {
cachedPageRuntimeConfig.delete(pageFilePath);
}
}
async function createEntrypoints(pages, target, buildId, previewMode, config, loadedEnvFiles, pagesDir, isDev) {
const client = {};
const server = {};
const edgeServer = {};
const hasRuntimeConfig = Object.keys(config.publicRuntimeConfig).length > 0 || Object.keys(config.serverRuntimeConfig).length > 0;
const hasReactRoot = !!config.experimental.reactRoot;
const defaultServerlessOptions = {
absoluteAppPath: pages['/_app'],
absoluteAppServerPath: pages['/_app.server'],
absoluteDocumentPath: pages['/_document'],
absoluteErrorPath: pages['/_error'],
absolute404Path: pages['/404'] || '',
distDir: _constants.DOT_NEXT_ALIAS,
buildId,
assetPrefix: config.assetPrefix,
generateEtags: config.generateEtags ? 'true' : '',
poweredByHeader: config.poweredByHeader ? 'true' : '',
canonicalBase: config.amp.canonicalBase || '',
basePath: config.basePath,
runtimeConfig: hasRuntimeConfig ? JSON.stringify({
publicRuntimeConfig: config.publicRuntimeConfig,
serverRuntimeConfig: config.serverRuntimeConfig
}) : '',
previewProps: JSON.stringify(previewMode),
// base64 encode to make sure contents don't break webpack URL loading
loadedEnvFiles: Buffer.from(JSON.stringify(loadedEnvFiles)).toString('base64'),
i18n: config.i18n ? JSON.stringify(config.i18n) : '',
reactRoot: hasReactRoot ? 'true' : ''
};
await Promise.all(Object.keys(pages).map(async (page)=>{
const absolutePagePath = pages[page];
const bundleFile = (0, _normalizePagePath).normalizePagePath(page);
const isApiRoute = page.match(_constants.API_ROUTE);
const clientBundlePath = _path.posix.join('pages', bundleFile);
const serverBundlePath = _path.posix.join('pages', bundleFile);
const isLikeServerless = (0, _utils).isTargetLikeServerless(target);
const isReserved = (0, _utils1).isReservedPage(page);
const isCustomError = (0, _utils1).isCustomErrorPage(page);
const isFlight = (0, _utils1).isFlightPage(config, absolutePagePath);
const isInternalPages = !absolutePagePath.startsWith(_constants.PAGES_DIR_ALIAS);
const pageFilePath = isInternalPages ? require.resolve(absolutePagePath) : (0, _path).join(pagesDir, absolutePagePath.replace(_constants.PAGES_DIR_ALIAS, ''));
const pageRuntime = await getPageRuntime(pageFilePath, config, isDev);
const isEdgeRuntime = pageRuntime === 'edge';
if (page.match(_constants.MIDDLEWARE_ROUTE)) {
const loaderOpts = {
absolutePagePath: pages[page],
page
};
client[clientBundlePath] = `next-middleware-loader?${(0, _querystring).stringify(loaderOpts)}!`;
return;
}
if (isEdgeRuntime && !isReserved && !isCustomError && !isApiRoute) {
_middlewarePlugin.ssrEntries.set(clientBundlePath, {
requireFlightManifest: isFlight
});
edgeServer[serverBundlePath] = finalizeEntrypoint({
name: '[name].js',
value: `next-middleware-ssr-loader?${(0, _querystring).stringify({
dev: false,
page,
stringifiedConfig: JSON.stringify(config),
absolute500Path: pages['/500'] || '',
absolutePagePath,
isServerComponent: isFlight,
...defaultServerlessOptions
})}!`,
isServer: false,
isEdgeServer: true
});
}
if (isApiRoute && isLikeServerless) {
const serverlessLoaderOptions = {
page,
absolutePagePath,
...defaultServerlessOptions
};
server[serverBundlePath] = `next-serverless-loader?${(0, _querystring).stringify(serverlessLoaderOptions)}!`;
} else if (isApiRoute || target === 'server') {
if (!isEdgeRuntime || isReserved || isCustomError) {
server[serverBundlePath] = [
absolutePagePath
];
}
} else if (isLikeServerless && page !== '/_app' && page !== '/_app.server' && page !== '/_document' && !isEdgeRuntime) {
const serverlessLoaderOptions = {
page,
absolutePagePath,
...defaultServerlessOptions
};
server[serverBundlePath] = `next-serverless-loader?${(0, _querystring).stringify(serverlessLoaderOptions)}!`;
}
if (page === '/_document' || page === '/_app.server') {
return;
}
if (!isApiRoute) {
const pageLoaderOpts = {
page,
absolutePagePath
};
const pageLoader = `next-client-pages-loader?${(0, _querystring).stringify(pageLoaderOpts)}!`;
// Make sure next/router is a dependency of _app or else chunk splitting
// might cause the router to not be able to load causing hydration
// to fail
client[clientBundlePath] = page === '/_app' ? [
pageLoader,
require.resolve('../client/router')
] : pageLoader;
}
}));
return {
client,
server,
edgeServer
};
}
function finalizeEntrypoint({ name , value , isServer , isMiddleware , isEdgeServer }) {
const entry = typeof value !== 'object' || Array.isArray(value) ? {
import: value
} : value;
if (isServer) {
const isApi = name.startsWith('pages/api/');
return {
publicPath: isApi ? '' : undefined,
runtime: isApi ? 'webpack-api-runtime' : 'webpack-runtime',
layer: isApi ? 'api' : undefined,
...entry
};
}
if (isEdgeServer) {
const ssrMiddlewareEntry = {
library: {
name: [
'_ENTRIES',
`middleware_[name]`
],
type: 'assign'
},
runtime: _constants1.MIDDLEWARE_SSR_RUNTIME_WEBPACK,
asyncChunks: false,
...entry
};
return ssrMiddlewareEntry;
}
if (isMiddleware) {
const middlewareEntry = {
filename: 'server/[name].js',
layer: 'middleware',
library: {
name: [
'_ENTRIES',
`middleware_[name]`
],
type: 'assign'
},
runtime: _constants1.MIDDLEWARE_RUNTIME_WEBPACK,
asyncChunks: false,
...entry
};
return middlewareEntry;
}
if (name !== 'polyfills' && name !== 'main' && name !== 'amp' && name !== 'react-refresh') {
return {
dependOn: name.startsWith('pages/') && name !== 'pages/_app' ? 'pages/_app' : 'main',
...entry
};
}
return entry;
}
//# sourceMappingURL=entries.js.map
;