UNPKG

next

Version:

The React Framework

330 lines (329 loc) • 15.2 kB
"use strict"; 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