diff --git a/docs/api-reference/create-next-app.md b/docs/api-reference/create-next-app.md index 1b96f94179d20..24f4255df576c 100644 --- a/docs/api-reference/create-next-app.md +++ b/docs/api-reference/create-next-app.md @@ -18,7 +18,7 @@ yarn create next-app - **-e, --example [name]|[github-url]** - An example to bootstrap the app with. You can use an example name from the [Next.js repo](https://github.com/vercel/next.js/tree/master/examples) or a GitHub URL. The URL can use any branch and/or subdirectory. - **--example-path [path-to-example]** - In a rare case, your GitHub URL might contain a branch name with a slash (e.g. bug/fix-1) and the path to the example (e.g. foo/bar). In this case, you must specify the path to the example separately: `--example-path foo/bar` -- **--use-npm** - Explicitly tell the CLI to bootstrap the app using npm. Yarn will be used by default if it's installed +- **--use-npm** - Explicitly tell the CLI to bootstrap the app using npm. To bootstrap using yarn we recommend to run `yarn create next-app` ### Why use Create Next App? diff --git a/errors/no-sync-scripts.md b/errors/no-sync-scripts.md index 4af7ef58b5211..1788236d85df1 100644 --- a/errors/no-sync-scripts.md +++ b/errors/no-sync-scripts.md @@ -16,7 +16,7 @@ import Script from 'next/experimental-script' const Home = () => { return (
- +
Home Page
) diff --git a/packages/create-next-app/README.md b/packages/create-next-app/README.md index deeb80d655671..8e629058467a3 100644 --- a/packages/create-next-app/README.md +++ b/packages/create-next-app/README.md @@ -19,7 +19,7 @@ npx create-next-app blog-app - **--ts, --typescript** - Initialize as a TypeScript project. - **-e, --example [name]|[github-url]** - An example to bootstrap the app with. You can use an example name from the [Next.js repo](https://github.com/vercel/next.js/tree/master/examples) or a GitHub URL. The URL can use any branch and/or subdirectory. - **--example-path <path-to-example>** - In a rare case, your GitHub URL might contain a branch name with a slash (e.g. bug/fix-1) and the path to the example (e.g. foo/bar). In this case, you must specify the path to the example separately: `--example-path foo/bar` -- **--use-npm** - Explicitly tell the CLI to bootstrap the app using npm. Yarn will be used by default if it's installed +- **--use-npm** - Explicitly tell the CLI to bootstrap the app using npm. To bootstrap using yarn we recommend to run `yarn create next-app` ## Why use Create Next App? diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 9f3c72a177d24..438796298254a 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -1260,6 +1260,7 @@ export default async function getBaseWebpackConfig( pageEnv: config.experimental.pageEnv, excludeDefaultMomentLocales: config.future.excludeDefaultMomentLocales, assetPrefix: config.assetPrefix, + disableOptimizedLoading: config.experimental.disableOptimizedLoading, target, reactProductionProfiling, webpack: !!config.webpack, diff --git a/packages/next/build/webpack/loaders/next-serverless-loader/utils.ts b/packages/next/build/webpack/loaders/next-serverless-loader/utils.ts index de8e14e420d84..2619b5a4f1142 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader/utils.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader/utils.ts @@ -289,7 +289,13 @@ export function getUtils({ // on the parsed params, this is used to signal if we need // to parse x-now-route-matches or not const isDefaultValue = Array.isArray(value) - ? value.every((val, idx) => val === defaultRouteMatches![key][idx]) + ? value.some((val) => { + const defaultValue = defaultRouteMatches![key] + + return Array.isArray(defaultValue) + ? defaultValue.includes(val) + : defaultValue === val + }) : value === defaultRouteMatches![key] if (isDefaultValue || typeof value === 'undefined') { diff --git a/packages/next/export/index.ts b/packages/next/export/index.ts index 7d8cc3fca1034..bdc3ad525c003 100644 --- a/packages/next/export/index.ts +++ b/packages/next/export/index.ts @@ -369,6 +369,7 @@ export default async function exportApp( defaultLocale: i18n?.defaultLocale, domainLocales: i18n?.domains, trailingSlash: nextConfig.trailingSlash, + disableOptimizedLoading: nextConfig.experimental.disableOptimizedLoading, } const { serverRuntimeConfig, publicRuntimeConfig } = nextConfig @@ -541,6 +542,8 @@ export default async function exportApp( optimizeFonts: nextConfig.optimizeFonts, optimizeImages: nextConfig.experimental.optimizeImages, optimizeCss: nextConfig.experimental.optimizeCss, + disableOptimizedLoading: + nextConfig.experimental.disableOptimizedLoading, parentSpanId: pageExportSpan.id, }) diff --git a/packages/next/export/worker.ts b/packages/next/export/worker.ts index 68f03b80f4ba6..057c4c5f1ebd5 100644 --- a/packages/next/export/worker.ts +++ b/packages/next/export/worker.ts @@ -52,6 +52,7 @@ interface ExportPageInput { optimizeFonts: boolean optimizeImages?: boolean optimizeCss: any + disableOptimizedLoading: any parentSpanId: any } @@ -70,6 +71,7 @@ interface RenderOpts { ampSkipValidation?: boolean optimizeFonts?: boolean optimizeImages?: boolean + disableOptimizedLoading?: boolean optimizeCss?: any fontManifest?: FontManifest locales?: string[] @@ -98,6 +100,7 @@ export default async function exportPage({ optimizeFonts, optimizeImages, optimizeCss, + disableOptimizedLoading, }: ExportPageInput): Promise { const exportPageSpan = trace('export-page-worker', parentSpanId) @@ -284,6 +287,7 @@ export default async function exportPage({ optimizeImages, /// @ts-ignore optimizeCss, + disableOptimizedLoading, distDir, fontManifest: optimizeFonts ? requireFontManifest(distDir, serverless) @@ -357,6 +361,7 @@ export default async function exportPage({ optimizeFonts, optimizeImages, optimizeCss, + disableOptimizedLoading, fontManifest: optimizeFonts ? requireFontManifest(distDir, serverless) : null, diff --git a/packages/next/next-server/lib/utils.ts b/packages/next/next-server/lib/utils.ts index eaaa30b2c806c..6af8e33dbdb7f 100644 --- a/packages/next/next-server/lib/utils.ts +++ b/packages/next/next-server/lib/utils.ts @@ -193,6 +193,7 @@ export type DocumentProps = DocumentInitialProps & { devOnlyCacheBusterQueryString: string scriptLoader: { afterInteractive?: string[]; beforeInteractive?: any[] } locale?: string + disableOptimizedLoading?: boolean } /** diff --git a/packages/next/next-server/server/config-shared.ts b/packages/next/next-server/server/config-shared.ts index fb45863f3269e..f64f09bef497d 100644 --- a/packages/next/next-server/server/config-shared.ts +++ b/packages/next/next-server/server/config-shared.ts @@ -61,6 +61,7 @@ export type NextConfig = { [key: string]: any } & { eslint?: boolean reactRoot: boolean enableBlurryPlaceholder: boolean + disableOptimizedLoading: boolean } } @@ -118,6 +119,7 @@ export const defaultConfig: NextConfig = { eslint: false, reactRoot: Number(process.env.NEXT_PRIVATE_REACT_ROOT) > 0, enableBlurryPlaceholder: false, + disableOptimizedLoading: true, }, future: { strictPostcssConfiguration: false, diff --git a/packages/next/next-server/server/next-server.ts b/packages/next/next-server/server/next-server.ts index 0b367f43a1a4e..edb480402608a 100644 --- a/packages/next/next-server/server/next-server.ts +++ b/packages/next/next-server/server/next-server.ts @@ -157,6 +157,7 @@ export default class Server { images: string fontManifest: FontManifest optimizeImages: boolean + disableOptimizedLoading: boolean optimizeCss: any locale?: string locales?: string[] @@ -217,6 +218,8 @@ export default class Server { : null, optimizeImages: !!this.nextConfig.experimental.optimizeImages, optimizeCss: this.nextConfig.experimental.optimizeCss, + disableOptimizedLoading: this.nextConfig.experimental + .disableOptimizedLoading, domainLocales: this.nextConfig.i18n?.domains, distDir: this.distDir, } @@ -815,28 +818,30 @@ export default class Server { } // Headers come very first - const headers = this.customRoutes.headers.map((r) => { - const headerRoute = getCustomRoute(r, 'header') - return { - match: headerRoute.match, - has: headerRoute.has, - type: headerRoute.type, - name: `${headerRoute.type} ${headerRoute.source} header route`, - fn: async (_req, res, params, _parsedUrl) => { - const hasParams = Object.keys(params).length > 0 - - for (const header of (headerRoute as Header).headers) { - let { key, value } = header - if (hasParams) { - key = compileNonPath(key, params) - value = compileNonPath(value, params) - } - res.setHeader(key, value) - } - return { finished: false } - }, - } as Route - }) + const headers = this.minimalMode + ? [] + : this.customRoutes.headers.map((r) => { + const headerRoute = getCustomRoute(r, 'header') + return { + match: headerRoute.match, + has: headerRoute.has, + type: headerRoute.type, + name: `${headerRoute.type} ${headerRoute.source} header route`, + fn: async (_req, res, params, _parsedUrl) => { + const hasParams = Object.keys(params).length > 0 + + for (const header of (headerRoute as Header).headers) { + let { key, value } = header + if (hasParams) { + key = compileNonPath(key, params) + value = compileNonPath(value, params) + } + res.setHeader(key, value) + } + return { finished: false } + }, + } as Route + }) // since initial query values are decoded by querystring.parse // we need to re-encode them here but still allow passing through @@ -968,12 +973,14 @@ export default class Server { let afterFiles: Route[] = [] let fallback: Route[] = [] - if (Array.isArray(this.customRoutes.rewrites)) { - afterFiles = this.customRoutes.rewrites.map(buildRewrite) - } else { - beforeFiles = this.customRoutes.rewrites.beforeFiles.map(buildRewrite) - afterFiles = this.customRoutes.rewrites.afterFiles.map(buildRewrite) - fallback = this.customRoutes.rewrites.fallback.map(buildRewrite) + if (!this.minimalMode) { + if (Array.isArray(this.customRoutes.rewrites)) { + afterFiles = this.customRoutes.rewrites.map(buildRewrite) + } else { + beforeFiles = this.customRoutes.rewrites.beforeFiles.map(buildRewrite) + afterFiles = this.customRoutes.rewrites.afterFiles.map(buildRewrite) + fallback = this.customRoutes.rewrites.fallback.map(buildRewrite) + } } const catchAllRoute: Route = { diff --git a/packages/next/next-server/server/render.tsx b/packages/next/next-server/server/render.tsx index b00e19fb162d4..6508c887415a1 100644 --- a/packages/next/next-server/server/render.tsx +++ b/packages/next/next-server/server/render.tsx @@ -190,6 +190,7 @@ export type RenderOptsPartial = { locales?: string[] defaultLocale?: string domainLocales?: DomainLocales + disableOptimizedLoading?: boolean } export type RenderOpts = LoadComponentsReturnType & RenderOptsPartial @@ -234,6 +235,7 @@ function renderDocument( defaultLocale, domainLocales, isPreview, + disableOptimizedLoading, }: RenderOpts & { props: any docComponentsRendered: DocumentProps['docComponentsRendered'] @@ -305,6 +307,7 @@ function renderDocument( devOnlyCacheBusterQueryString, scriptLoader, locale, + disableOptimizedLoading, ...docProps, })} diff --git a/packages/next/pages/_document.tsx b/packages/next/pages/_document.tsx index 98d1d7e1907c0..d3a486a0e4de9 100644 --- a/packages/next/pages/_document.tsx +++ b/packages/next/pages/_document.tsx @@ -51,6 +51,115 @@ function getDocumentFiles( } } +function getPolyfillScripts(context: DocumentProps, props: OriginProps) { + // polyfills.js has to be rendered as nomodule without async + // It also has to be the first script to load + const { + assetPrefix, + buildManifest, + devOnlyCacheBusterQueryString, + disableOptimizedLoading, + } = context + + return buildManifest.polyfillFiles + .filter( + (polyfill) => polyfill.endsWith('.js') && !polyfill.endsWith('.module.js') + ) + .map((polyfill) => ( +