From 89b2dfc502815cbbf660c86eea34c60e58a662d8 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 3 Feb 2020 16:34:23 -0600 Subject: [PATCH 01/26] =?UTF-8?q?Make=20sure=20runtime=20config=20works=20?= =?UTF-8?q?in=20dev=20mode=20for=20serverless=20targ=E2=80=A6=20(#10402)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/next-server/server/next-server.ts | 10 ++-- .../test/index.test.js | 59 +++++++++++++------ 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/packages/next/next-server/server/next-server.ts b/packages/next/next-server/server/next-server.ts index a67d149c04a3be..9f963061ada122 100644 --- a/packages/next/next-server/server/next-server.ts +++ b/packages/next/next-server/server/next-server.ts @@ -163,12 +163,10 @@ export default class Server { } // Initialize next/config with the environment configuration - if (this.nextConfig.target === 'server') { - envConfig.setConfig({ - serverRuntimeConfig, - publicRuntimeConfig, - }) - } + envConfig.setConfig({ + serverRuntimeConfig, + publicRuntimeConfig, + }) this.serverBuildDir = join( this.distDir, diff --git a/test/integration/serverless-runtime-configs/test/index.test.js b/test/integration/serverless-runtime-configs/test/index.test.js index b9776f2055ed23..648ff080b076ca 100644 --- a/test/integration/serverless-runtime-configs/test/index.test.js +++ b/test/integration/serverless-runtime-configs/test/index.test.js @@ -6,6 +6,7 @@ import { nextBuild, findPort, killApp, + launchApp, renderViaHTTP, initNextServerScript, } from 'next-test-utils' @@ -74,24 +75,7 @@ describe('Serverless runtime configs', () => { ) }) - it('should support runtime configs in serverless mode', async () => { - await fs.writeFile( - nextConfigPath, - `module.exports = { - target: 'serverless', - serverRuntimeConfig: { - hello: 'world' - }, - publicRuntimeConfig: { - another: 'thing' - } - }` - ) - - await nextBuild(appDir, [], { stderr: true, stdout: true }) - const appPort = await findPort() - const app = await nextStart(appDir, appPort) - + const testRuntimeConfig = async (app, appPort) => { const browser = await webdriver(appPort, '/config') const clientHTML = await browser.eval(`document.documentElement.innerHTML`) @@ -140,5 +124,44 @@ describe('Serverless runtime configs', () => { expect(JSON.parse(docClientConfig)).toEqual(expectedSsrConfig) expect(JSON.parse(apiJson)).toEqual(expectedSsrConfig) + } + + it('should support runtime configs in serverless mode (production)', async () => { + await fs.writeFile( + nextConfigPath, + `module.exports = { + target: 'serverless', + serverRuntimeConfig: { + hello: 'world' + }, + publicRuntimeConfig: { + another: 'thing' + } + }` + ) + + await nextBuild(appDir, [], { stderr: true, stdout: true }) + const appPort = await findPort() + const app = await nextStart(appDir, appPort) + await testRuntimeConfig(app, appPort) + }) + + it('should support runtime configs in serverless mode (dev)', async () => { + await fs.writeFile( + nextConfigPath, + `module.exports = { + target: 'serverless', + serverRuntimeConfig: { + hello: 'world' + }, + publicRuntimeConfig: { + another: 'thing' + } + }` + ) + + const appPort = await findPort() + const app = await launchApp(appDir, appPort) + await testRuntimeConfig(app, appPort) }) }) From 821b32554759041d428a1d4d26aa12b0aa301515 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Mon, 3 Feb 2020 16:38:10 -0600 Subject: [PATCH 02/26] v9.2.2-canary.10 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-google-analytics/package.json | 2 +- packages/next-plugin-material-ui/package.json | 2 +- packages/next-plugin-sentry/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next/package.json | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lerna.json b/lerna.json index b1028ed5beef44..4deca3e2040dde 100644 --- a/lerna.json +++ b/lerna.json @@ -12,5 +12,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "9.2.2-canary.9" + "version": "9.2.2-canary.10" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 875bc1f8fb9e04..c23ad7613e2ad2 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "9.2.2-canary.9", + "version": "9.2.2-canary.10", "keywords": [ "react", "next", diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 9af286a0fb7fc4..bb13e2c0e1b56a 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "9.2.2-canary.9", + "version": "9.2.2-canary.10", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 935d0731fd8e79..d5c5efea5e30e2 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "9.2.2-canary.9", + "version": "9.2.2-canary.10", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-google-analytics/package.json b/packages/next-plugin-google-analytics/package.json index 142c65d0c0879d..352c4c722be78f 100644 --- a/packages/next-plugin-google-analytics/package.json +++ b/packages/next-plugin-google-analytics/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-google-analytics", - "version": "9.2.2-canary.9", + "version": "9.2.2-canary.10", "nextjs": { "name": "Google Analytics", "required-env": [ diff --git a/packages/next-plugin-material-ui/package.json b/packages/next-plugin-material-ui/package.json index b2c0c5d0364bbc..b47f072b06c3b7 100644 --- a/packages/next-plugin-material-ui/package.json +++ b/packages/next-plugin-material-ui/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-material-ui", - "version": "9.2.2-canary.9", + "version": "9.2.2-canary.10", "nextjs": { "name": "Material UI", "required-env": [] diff --git a/packages/next-plugin-sentry/package.json b/packages/next-plugin-sentry/package.json index b5b6926eb02f75..050ced1a24dd9c 100644 --- a/packages/next-plugin-sentry/package.json +++ b/packages/next-plugin-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-sentry", - "version": "9.2.2-canary.9", + "version": "9.2.2-canary.10", "nextjs": { "name": "Sentry", "required-env": [ diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index efa3af0575bfce..28661f7600192b 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "9.2.2-canary.9", + "version": "9.2.2-canary.10", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next/package.json b/packages/next/package.json index 056f4226ebd4ef..ffc72443e88795 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "9.2.2-canary.9", + "version": "9.2.2-canary.10", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -73,7 +73,7 @@ "@babel/preset-typescript": "7.7.2", "@babel/runtime": "7.7.2", "@babel/runtime-corejs2": "7.7.2", - "@next/polyfill-nomodule": "9.2.2-canary.9", + "@next/polyfill-nomodule": "9.2.2-canary.10", "amphtml-validator": "1.0.23", "async-retry": "1.2.3", "async-sema": "3.0.0", From 909ab3b17927a7f8f045f3fdaff43ea36037b168 Mon Sep 17 00:00:00 2001 From: Luis Alvarez D Date: Tue, 4 Feb 2020 10:46:22 -0500 Subject: [PATCH 03/26] Check for invalid pages (#10403) * Updated event * adjust regex * adjust regexp more * Better test file regex * add tests * Update index.test.js * Rename test file Co-authored-by: Joe Haddad --- packages/next/build/index.ts | 3 +-- packages/next/telemetry/events/build.ts | 23 +++++++++++++++++-- .../telemetry/pages/__ytho__/lel.js | 3 +++ .../telemetry/pages/hello.test.skip | 1 + test/integration/telemetry/test/index.test.js | 20 ++++++++++++++++ 5 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 test/integration/telemetry/pages/__ytho__/lel.js create mode 100644 test/integration/telemetry/pages/hello.test.skip diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index f2ec3a9ce06e17..179ab522353869 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -770,9 +770,8 @@ export default async function build(dir: string, conf = null): Promise { const analysisEnd = process.hrtime(analysisBegin) telemetry.record( - eventBuildOptimize({ + eventBuildOptimize(pagePaths, { durationInSeconds: analysisEnd[0], - totalPageCount: pagePaths.length, staticPageCount: staticPages.size, ssrPageCount: pagePaths.length - staticPages.size, }) diff --git a/packages/next/telemetry/events/build.ts b/packages/next/telemetry/events/build.ts index b413f0b3b86a40..f3ba100bb721d3 100644 --- a/packages/next/telemetry/events/build.ts +++ b/packages/next/telemetry/events/build.ts @@ -19,13 +19,32 @@ type EventBuildOptimized = { totalPageCount: number staticPageCount: number ssrPageCount: number + hasDunderPages: boolean + hasTestPages: boolean } +const REGEXP_DIRECTORY_DUNDER = /[\\/]__[^\\/]+(? ): { eventName: string; payload: EventBuildOptimized } { return { eventName: EVENT_BUILD_OPTIMIZE, - payload: event, + payload: { + ...event, + totalPageCount: pagePaths.length, + hasDunderPages: pagePaths.some(path => + REGEXP_DIRECTORY_DUNDER.test(path) + ), + hasTestPages: pagePaths.some( + path => REGEXP_DIRECTORY_TESTS.test(path) || REGEXP_FILE_TEST.test(path) + ), + }, } } diff --git a/test/integration/telemetry/pages/__ytho__/lel.js b/test/integration/telemetry/pages/__ytho__/lel.js new file mode 100644 index 00000000000000..3cbd09bcbc5a09 --- /dev/null +++ b/test/integration/telemetry/pages/__ytho__/lel.js @@ -0,0 +1,3 @@ +export default () => { + return 'oops, I happen to look like a React component' +} diff --git a/test/integration/telemetry/pages/hello.test.skip b/test/integration/telemetry/pages/hello.test.skip new file mode 100644 index 00000000000000..9780095a4d7b43 --- /dev/null +++ b/test/integration/telemetry/pages/hello.test.skip @@ -0,0 +1 @@ +export default () => 'Hello Test' diff --git a/test/integration/telemetry/test/index.test.js b/test/integration/telemetry/test/index.test.js index da2fe430ecf4de..ea11bae5efc102 100644 --- a/test/integration/telemetry/test/index.test.js +++ b/test/integration/telemetry/test/index.test.js @@ -92,6 +92,26 @@ describe('Telemetry CLI', () => { expect(stderr2).toMatch(/isSrcDir.*?true/) }) + it('detects tests correctly for `next build`', async () => { + await fs.rename( + path.join(appDir, 'pages', 'hello.test.skip'), + path.join(appDir, 'pages', 'hello.test.js') + ) + const { stderr } = await runNextCommand(['build', appDir], { + stderr: true, + env: { + NEXT_TELEMETRY_DEBUG: 1, + }, + }) + await fs.rename( + path.join(appDir, 'pages', 'hello.test.js'), + path.join(appDir, 'pages', 'hello.test.skip') + ) + + expect(stderr).toMatch(/hasDunderPages.*?true/) + expect(stderr).toMatch(/hasTestPages.*?true/) + }) + it('detects isSrcDir dir correctly for `next dev`', async () => { let port = await findPort() let stderr = '' From 44e234e93422819033afb92a2363cbb7d007b1f8 Mon Sep 17 00:00:00 2001 From: Andy Date: Tue, 4 Feb 2020 18:52:42 +0100 Subject: [PATCH 04/26] Remove `builds` from examples (#10417) * Remove `builds` from examples * Fix with-zones example * Run prettier on now.json --- examples/blog-starter/now.json | 2 -- examples/with-now-env/now.json | 7 ------- examples/with-stencil/README.md | 2 ++ examples/with-stencil/now.json | 5 ----- examples/with-yarn-workspaces/README.md | 2 ++ examples/with-yarn-workspaces/now.json | 5 ----- examples/with-zones/blog/.gitignore | 2 ++ examples/with-zones/blog/now.json | 13 +++++++++++++ examples/with-zones/home/.gitignore | 2 ++ examples/with-zones/home/now.json | 8 ++++++++ examples/with-zones/now.json | 18 ------------------ examples/z-experimental-next-news/now.json | 3 --- 12 files changed, 29 insertions(+), 40 deletions(-) delete mode 100644 examples/with-stencil/now.json delete mode 100644 examples/with-yarn-workspaces/now.json create mode 100644 examples/with-zones/blog/now.json create mode 100644 examples/with-zones/home/now.json delete mode 100644 examples/with-zones/now.json delete mode 100644 examples/z-experimental-next-news/now.json diff --git a/examples/blog-starter/now.json b/examples/blog-starter/now.json index e9ab941a260121..e2a1eb024cd292 100644 --- a/examples/blog-starter/now.json +++ b/examples/blog-starter/now.json @@ -1,8 +1,6 @@ { - "version": 2, "name": "nextjs-blog-starter", "alias": ["nextjs-blog-starter.now.sh"], - "builds": [{ "src": "package.json", "use": "@now/next" }], "routes": [ { "src": "/feed.json", "dest": "/_next/static/feed.json" }, { "src": "/blog/(?[^/]+)$", "dest": "/blog?page=$page" } diff --git a/examples/with-now-env/now.json b/examples/with-now-env/now.json index f04eefdb3c0629..1305f0d9a0d26f 100644 --- a/examples/with-now-env/now.json +++ b/examples/with-now-env/now.json @@ -1,11 +1,4 @@ { - "version": 2, - "builds": [ - { - "src": "package.json", - "use": "@now/next" - } - ], "build": { "env": { "SECRET": "@my-secret-key", diff --git a/examples/with-stencil/README.md b/examples/with-stencil/README.md index ac2b873e51736b..ae0be530006721 100644 --- a/examples/with-stencil/README.md +++ b/examples/with-stencil/README.md @@ -47,6 +47,8 @@ Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit. now ``` +> Choose `packages/web-app` as root directory when deploying. + ## The idea behind the example Stencil is a compiler that generates Web Components (more specifically, Custom Elements). Stencil combines the best concepts of the most popular frameworks into a simple build-time tool. diff --git a/examples/with-stencil/now.json b/examples/with-stencil/now.json deleted file mode 100644 index 985a1b01d4007e..00000000000000 --- a/examples/with-stencil/now.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": 2, - "builds": [{ "src": "packages/web-app/package.json", "use": "@now/next" }], - "routes": [{ "src": "(.*)", "dest": "packages/web-app$1", "continue": true }] -} diff --git a/examples/with-yarn-workspaces/README.md b/examples/with-yarn-workspaces/README.md index 15e1d756fbb0cb..c77eba540103d7 100644 --- a/examples/with-yarn-workspaces/README.md +++ b/examples/with-yarn-workspaces/README.md @@ -48,6 +48,8 @@ Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit. now ``` +> Choose `packages/web-app` as root directory when deploying. + ## Useful Links - [Documentation](https://yarnpkg.com/en/docs/workspaces) diff --git a/examples/with-yarn-workspaces/now.json b/examples/with-yarn-workspaces/now.json deleted file mode 100644 index 985a1b01d4007e..00000000000000 --- a/examples/with-yarn-workspaces/now.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": 2, - "builds": [{ "src": "packages/web-app/package.json", "use": "@now/next" }], - "routes": [{ "src": "(.*)", "dest": "packages/web-app$1", "continue": true }] -} diff --git a/examples/with-zones/blog/.gitignore b/examples/with-zones/blog/.gitignore index f74c78183c9179..e54e38fa532b36 100644 --- a/examples/with-zones/blog/.gitignore +++ b/examples/with-zones/blog/.gitignore @@ -1,2 +1,4 @@ .next node_modules + +.now \ No newline at end of file diff --git a/examples/with-zones/blog/now.json b/examples/with-zones/blog/now.json new file mode 100644 index 00000000000000..9dcd887d881d87 --- /dev/null +++ b/examples/with-zones/blog/now.json @@ -0,0 +1,13 @@ +{ + "build": { + "env": { + "BUILDING_FOR_NOW": "true" + } + }, + "rewrites": [ + { + "source": "/blog/_next$1", + "destination": "/_next$1" + } + ] +} diff --git a/examples/with-zones/home/.gitignore b/examples/with-zones/home/.gitignore index f74c78183c9179..e54e38fa532b36 100644 --- a/examples/with-zones/home/.gitignore +++ b/examples/with-zones/home/.gitignore @@ -1,2 +1,4 @@ .next node_modules + +.now \ No newline at end of file diff --git a/examples/with-zones/home/now.json b/examples/with-zones/home/now.json new file mode 100644 index 00000000000000..7981357aa4e9b8 --- /dev/null +++ b/examples/with-zones/home/now.json @@ -0,0 +1,8 @@ +{ + "rewrites": [ + { + "source": "/blog(.*)", + "destination": "https://with-zones-blog.now.sh$1" + } + ] +} diff --git a/examples/with-zones/now.json b/examples/with-zones/now.json deleted file mode 100644 index 590167dd6c7ab6..00000000000000 --- a/examples/with-zones/now.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "with-zones", - "version": 2, - "builds": [ - { "src": "blog/next.config.js", "use": "@now/next" }, - { "src": "home/next.config.js", "use": "@now/next" } - ], - "routes": [ - { "src": "/blog/(_next|static)(.*)" }, - { "src": "/blog(.*)", "dest": "blog/blog$1", "continue": true }, - { "src": "(?!/?blog)(.*)", "dest": "home$1", "continue": true } - ], - "build": { - "env": { - "BUILDING_FOR_NOW": "true" - } - } -} diff --git a/examples/z-experimental-next-news/now.json b/examples/z-experimental-next-news/now.json deleted file mode 100644 index 404c3ff46d5d78..00000000000000 --- a/examples/z-experimental-next-news/now.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "builds": [{ "src": "package.json", "use": "@now/next@canary" }] -} From bc81379618c0a4de4bff9aff2d555d2232643d18 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Tue, 4 Feb 2020 13:55:43 -0500 Subject: [PATCH 05/26] Detect Invalid Pages Before Optimize (#10418) --- packages/next/build/index.ts | 15 +++++----- packages/next/telemetry/events/build.ts | 29 ++++++++++++++----- test/integration/telemetry/test/index.test.js | 9 ++++-- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index 179ab522353869..bf2053faeab2b8 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -1,5 +1,6 @@ import chalk from 'chalk' import ciEnvironment from 'ci-info' +import escapeStringRegexp from 'escape-string-regexp' import findUp from 'find-up' import fs from 'fs' import Worker from 'jest-worker' @@ -11,14 +12,14 @@ import { promisify } from 'util' import formatWebpackMessages from '../client/dev/error-overlay/format-webpack-messages' import checkCustomRoutes, { getRedirectStatus, - RouteType, + Header, Redirect, Rewrite, - Header, + RouteType, } from '../lib/check-custom-routes' import { - PUBLIC_DIR_MIDDLEWARE_CONFLICT, PAGES_404_GET_INITIAL_PROPS_ERROR, + PUBLIC_DIR_MIDDLEWARE_CONFLICT, } from '../lib/constants' import { findPagesDir } from '../lib/find-pages-dir' import { recursiveDelete } from '../lib/recursive-delete' @@ -44,7 +45,7 @@ import loadConfig, { isTargetLikeServerless, } from '../next-server/server/config' import { - eventBuildDuration, + eventBuildCompleted, eventBuildOptimize, eventNextPlugins, eventVersion, @@ -56,17 +57,16 @@ import { generateBuildId } from './generate-build-id' import { isWriteable } from './is-writeable' import createSpinner from './spinner' import { - isPageStatic, collectPages, getPageSizeInKb, hasCustomAppGetInitialProps, + isPageStatic, PageInfo, printCustomRoutes, printTreeView, } from './utils' import getBaseWebpackConfig from './webpack-config' import { writeBuildId } from './write-build-id' -import escapeStringRegexp from 'escape-string-regexp' const fsAccess = promisify(fs.access) const fsUnlink = promisify(fs.unlink) @@ -394,8 +394,7 @@ export default async function build(dir: string, conf = null): Promise { } else { console.log(chalk.green('Compiled successfully.\n')) telemetry.record( - eventBuildDuration({ - totalPageCount: pagePaths.length, + eventBuildCompleted(pagePaths, { durationInSeconds: webpackBuildEnd[0], }) ) diff --git a/packages/next/telemetry/events/build.ts b/packages/next/telemetry/events/build.ts index f3ba100bb721d3..7ea9f882a2e960 100644 --- a/packages/next/telemetry/events/build.ts +++ b/packages/next/telemetry/events/build.ts @@ -1,15 +1,34 @@ +const REGEXP_DIRECTORY_DUNDER = /[\\/]__[^\\/]+(? ): { eventName: string; payload: EventBuildCompleted } { return { eventName: EVENT_BUILD_DURATION, - payload: event, + payload: { + ...event, + totalPageCount: pagePaths.length, + hasDunderPages: pagePaths.some(path => + REGEXP_DIRECTORY_DUNDER.test(path) + ), + hasTestPages: pagePaths.some( + path => REGEXP_DIRECTORY_TESTS.test(path) || REGEXP_FILE_TEST.test(path) + ), + }, } } @@ -23,10 +42,6 @@ type EventBuildOptimized = { hasTestPages: boolean } -const REGEXP_DIRECTORY_DUNDER = /[\\/]__[^\\/]+(? { path.join(appDir, 'pages', 'hello.test.skip') ) - expect(stderr).toMatch(/hasDunderPages.*?true/) - expect(stderr).toMatch(/hasTestPages.*?true/) + const event1 = /NEXT_BUILD_COMPLETED[\s\S]+?{([\s\S]+?)}/.exec(stderr).pop() + expect(event1).toMatch(/hasDunderPages.*?true/) + expect(event1).toMatch(/hasTestPages.*?true/) + + const event2 = /NEXT_BUILD_OPTIMIZED[\s\S]+?{([\s\S]+?)}/.exec(stderr).pop() + expect(event2).toMatch(/hasDunderPages.*?true/) + expect(event2).toMatch(/hasTestPages.*?true/) }) it('detects isSrcDir dir correctly for `next dev`', async () => { From e3d298dc621c50db4a74ece68cebd0114d087daf Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 4 Feb 2020 13:08:03 -0600 Subject: [PATCH 06/26] Add support for rewriting to external resources (#10041) * Add support for rewriting to external resources * Update rewrite proxying test Co-authored-by: Tim Neutkens Co-authored-by: Joe Haddad --- package.json | 7 +-- packages/next/lib/check-custom-routes.ts | 9 +++- .../next/next-server/server/next-server.ts | 40 ++++++++++++---- packages/next/package.json | 1 + test/integration/custom-routes/next.config.js | 4 ++ .../custom-routes/test/index.test.js | 47 ++++++++++++++++++- .../invalid-custom-routes/test/index.test.js | 2 +- yarn.lock | 35 +++++++++++++- 8 files changed, 127 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 18a27400823189..f5bf15c7eb34c6 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@babel/preset-react": "7.7.0", "@fullhuman/postcss-purgecss": "1.3.0", "@mdx-js/loader": "0.18.0", + "@types/http-proxy": "1.17.3", "@types/jest": "24.0.13", "@types/string-hash": "1.1.1", "@typescript-eslint/eslint-plugin": "2.17.0", @@ -53,7 +54,9 @@ "babel-core": "7.0.0-bridge.0", "babel-eslint": "10.0.3", "babel-jest": "24.9.0", + "browserslist": "^4.8.3", "browserstack-local": "1.4.0", + "caniuse-lite": "^1.0.30001019", "cheerio": "0.22.0", "clone": "2.1.2", "coveralls": "3.0.3", @@ -100,9 +103,7 @@ "tree-kill": "1.2.1", "typescript": "3.7.3", "wait-port": "0.2.2", - "webpack-bundle-analyzer": "3.3.2", - "browserslist": "^4.8.3", - "caniuse-lite": "^1.0.30001019" + "webpack-bundle-analyzer": "3.3.2" }, "resolutions": { "browserslist": "^4.8.3", diff --git a/packages/next/lib/check-custom-routes.ts b/packages/next/lib/check-custom-routes.ts index 8d5f0f3a719973..b0dd787c271dba 100644 --- a/packages/next/lib/check-custom-routes.ts +++ b/packages/next/lib/check-custom-routes.ts @@ -127,8 +127,13 @@ export default function checkCustomRoutes( invalidParts.push('`destination` is missing') } else if (typeof _route.destination !== 'string') { invalidParts.push('`destination` is not a string') - } else if (type === 'rewrite' && !_route.destination.startsWith('/')) { - invalidParts.push('`destination` does not start with /') + } else if ( + type === 'rewrite' && + !_route.destination.match(/^(\/|https:\/\/|http:\/\/)/) + ) { + invalidParts.push( + '`destination` does not start with `/`, `http://`, or `https://`' + ) } } diff --git a/packages/next/next-server/server/next-server.ts b/packages/next/next-server/server/next-server.ts index 9f963061ada122..c817e6890e65ca 100644 --- a/packages/next/next-server/server/next-server.ts +++ b/packages/next/next-server/server/next-server.ts @@ -1,5 +1,6 @@ import compression from 'compression' import fs from 'fs' +import Proxy from 'http-proxy' import { IncomingMessage, ServerResponse } from 'http' import { join, resolve, sep } from 'path' import { compile as compilePathToRegex } from 'path-to-regexp' @@ -451,7 +452,7 @@ export default class Server { type: route.type, statusCode: (route as Redirect).statusCode, name: `${route.type} ${route.source} route`, - fn: async (_req, res, params, _parsedUrl) => { + fn: async (req, res, params, _parsedUrl) => { const parsedDestination = parseUrl(route.destination, true) const destQuery = parsedDestination.query let destinationCompiler = compilePathToRegex( @@ -485,15 +486,15 @@ export default class Server { throw err } - if (route.type === 'redirect') { - const parsedNewUrl = parseUrl(newUrl) - const updatedDestination = formatUrl({ - ...parsedDestination, - pathname: parsedNewUrl.pathname, - hash: parsedNewUrl.hash, - search: undefined, - }) + const parsedNewUrl = parseUrl(newUrl) + const updatedDestination = formatUrl({ + ...parsedDestination, + pathname: parsedNewUrl.pathname, + hash: parsedNewUrl.hash, + search: undefined, + }) + if (route.type === 'redirect') { res.setHeader('Location', updatedDestination) res.statusCode = getRedirectStatus(route as Redirect) @@ -508,7 +509,26 @@ export default class Server { finished: true, } } else { - ;(_req as any)._nextDidRewrite = true + // external rewrite, proxy it + if (parsedDestination.protocol) { + const proxy = new Proxy({ + target: updatedDestination, + changeOrigin: true, + ignorePath: true, + }) + proxy.web(req, res) + + proxy.on('error', (err: Error) => { + console.error( + `Error occurred proxying ${updatedDestination}`, + err + ) + }) + return { + finished: true, + } + } + ;(req as any)._nextDidRewrite = true } return { diff --git a/packages/next/package.json b/packages/next/package.json index ffc72443e88795..b802f3bbc99d5e 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -102,6 +102,7 @@ "fork-ts-checker-webpack-plugin": "3.1.1", "fresh": "0.5.2", "gzip-size": "5.1.1", + "http-proxy": "1.18.0", "ignore-loader": "0.1.2", "is-docker": "2.0.0", "is-wsl": "2.1.1", diff --git a/test/integration/custom-routes/next.config.js b/test/integration/custom-routes/next.config.js index 0459f37750cb93..db3512ce959678 100644 --- a/test/integration/custom-routes/next.config.js +++ b/test/integration/custom-routes/next.config.js @@ -55,6 +55,10 @@ module.exports = { source: '/hidden/_next/:path*', destination: '/_next/:path*', }, + { + source: '/proxy-me/:path*', + destination: 'http://localhost:__EXTERNAL_PORT__/:path*', + }, { source: '/api-hello', destination: '/api/hello', diff --git a/test/integration/custom-routes/test/index.test.js b/test/integration/custom-routes/test/index.test.js index f2c01f903adba0..b9da3fc566d9e5 100644 --- a/test/integration/custom-routes/test/index.test.js +++ b/test/integration/custom-routes/test/index.test.js @@ -1,5 +1,6 @@ /* eslint-env jest */ /* global jasmine */ +import http from 'http' import url from 'url' import stripAnsi from 'strip-ansi' import fs from 'fs-extra' @@ -24,9 +25,13 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 2 let appDir = join(__dirname, '..') const nextConfigPath = join(appDir, 'next.config.js') +let externalServerHits = new Set() +let nextConfigRestoreContent let nextConfigContent -let buildId +let externalServerPort +let externalServer let stdout = '' +let buildId let appPort let app @@ -228,6 +233,13 @@ const runTests = (isDev = false) => { expect(res.headers.get('x-second-header')).toBe('second') }) + it('should support proxying to external resource', async () => { + const res = await fetchViaHTTP(appPort, '/proxy-me/first') + expect(res.status).toBe(200) + expect([...externalServerHits]).toEqual(['/first']) + expect(await res.text()).toContain('hi from external') + }) + it('should support unnamed parameters correctly', async () => { const res = await fetchViaHTTP(appPort, '/unnamed/first/final', undefined, { redirect: 'manual', @@ -493,6 +505,13 @@ const runTests = (isDev = false) => { ), source: '/hidden/_next/:path*', }, + { + destination: `http://localhost:${externalServerPort}/:path*`, + regex: normalizeRegEx( + '^\\/proxy-me(?:\\/((?:[^\\/]+?)(?:\\/(?:[^\\/]+?))*))?$' + ), + source: '/proxy-me/:path*', + }, { destination: '/api/hello', regex: normalizeRegEx('^\\/api-hello$'), @@ -550,6 +569,32 @@ const runTests = (isDev = false) => { } describe('Custom routes', () => { + beforeEach(() => { + externalServerHits = new Set() + }) + beforeAll(async () => { + externalServerPort = await findPort() + externalServer = http.createServer((req, res) => { + externalServerHits.add(req.url) + res.end('hi from external') + }) + await new Promise((resolve, reject) => { + externalServer.listen(externalServerPort, error => { + if (error) return reject(error) + resolve() + }) + }) + nextConfigRestoreContent = await fs.readFile(nextConfigPath, 'utf8') + await fs.writeFile( + nextConfigPath, + nextConfigRestoreContent.replace(/__EXTERNAL_PORT__/, externalServerPort) + ) + }) + afterAll(async () => { + externalServer.close() + await fs.writeFile(nextConfigPath, nextConfigRestoreContent) + }) + describe('dev mode', () => { beforeAll(async () => { appPort = await findPort() diff --git a/test/integration/invalid-custom-routes/test/index.test.js b/test/integration/invalid-custom-routes/test/index.test.js index f72c40c0797111..e2c3d82c1968bc 100644 --- a/test/integration/invalid-custom-routes/test/index.test.js +++ b/test/integration/invalid-custom-routes/test/index.test.js @@ -167,7 +167,7 @@ const runTests = () => { ) expect(stderr).toContain( - `\`destination\` does not start with / for route {"source":"/hello","destination":"another"}` + `\`destination\` does not start with \`/\`, \`http://\`, or \`https://\` for route {"source":"/hello","destination":"another"}` ) expect(stderr).toContain( diff --git a/yarn.lock b/yarn.lock index 0bb7a8e63c65f7..87c2546129d42a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2583,6 +2583,13 @@ "@types/tough-cookie" "*" form-data "^2.5.0" +"@types/http-proxy@1.17.3": + version "1.17.3" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.3.tgz#348e1b808ff9585423cb909e9992d89ccdbf4c14" + integrity sha512-wIPqXANye5BbORbuh74exbwNzj+UWCwWyeEFJzUQ7Fq3W2NSAy+7x7nX1fgbEypr2/TdKqpeuxLnXWgzN533/Q== + dependencies: + "@types/node" "*" + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" @@ -5802,7 +5809,7 @@ debug@3.1.0: dependencies: ms "2.0.0" -debug@^3.1.0, debug@^3.2.6: +debug@^3.0.0, debug@^3.1.0, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -6578,6 +6585,11 @@ eventemitter3@^3.1.0: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== +eventemitter3@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" + integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== + events@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" @@ -7193,6 +7205,13 @@ fn-annotate@^1.1.3: resolved "https://registry.yarnpkg.com/fn-annotate/-/fn-annotate-1.2.0.tgz#28da000117dea61842fe61f353f41cf4c93a7a7e" integrity sha1-KNoAARfephhC/mHzU/Qc9Mk6en4= +follow-redirects@^1.0.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.9.0.tgz#8d5bcdc65b7108fe1508649c79c12d732dcedb4f" + integrity sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A== + dependencies: + debug "^3.0.0" + for-in@^0.1.3: version "0.1.8" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" @@ -8110,6 +8129,15 @@ http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" +http-proxy@1.18.0: + version "1.18.0" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a" + integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -14124,6 +14152,11 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + reserved-words@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/reserved-words/-/reserved-words-0.1.2.tgz#00a0940f98cd501aeaaac316411d9adc52b31ab1" From 21fea2ce619cd2702b0ceaee9f160a5f34ccbaf3 Mon Sep 17 00:00:00 2001 From: Alex Castle Date: Tue, 4 Feb 2020 11:22:26 -0800 Subject: [PATCH 07/26] Modify splitChunksPlugin to give shared CSS chunks different names (#10408) * Modify splitChunksPlugin to give shared CSS chunks different names * fix lint Co-authored-by: Joe Haddad --- packages/next/build/webpack-config.ts | 42 +++++++++++++++------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 1f251032242dd0..12aedaf210d435 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -311,6 +311,17 @@ export default async function getBaseWebpackConfig( const devtool = dev ? 'cheap-module-source-map' : false + const isModuleCSS = (module: { type: string }): boolean => { + return ( + // mini-css-extract-plugin + module.type === `css/mini-extract` || + // extract-css-chunks-webpack-plugin (old) + module.type === `css/extract-chunks` || + // extract-css-chunks-webpack-plugin (new) + module.type === `css/extract-css-chunks` + ) + } + // Contains various versions of the Webpack SplitChunksPlugin used in different build types const splitChunksConfigs: { [propName: string]: webpack.Options.SplitChunksOptions @@ -368,14 +379,7 @@ export default async function getBaseWebpackConfig( updateHash: (hash: crypto.Hash) => void }): string { const hash = crypto.createHash('sha1') - if ( - // mini-css-extract-plugin - module.type === `css/mini-extract` || - // extract-css-chunks-webpack-plugin (old) - module.type === `css/extract-chunks` || - // extract-css-chunks-webpack-plugin (new) - module.type === `css/extract-css-chunks` - ) { + if (isModuleCSS(module)) { module.updateHash(hash) } else { if (!module.libIdent) { @@ -400,17 +404,19 @@ export default async function getBaseWebpackConfig( }, shared: { name(module, chunks) { - return crypto - .createHash('sha1') - .update( - chunks.reduce( - (acc: string, chunk: webpack.compilation.Chunk) => { - return acc + chunk.name - }, - '' + return ( + crypto + .createHash('sha1') + .update( + chunks.reduce( + (acc: string, chunk: webpack.compilation.Chunk) => { + return acc + chunk.name + }, + '' + ) ) - ) - .digest('hex') + .digest('hex') + (isModuleCSS(module) ? '_CSS' : '') + ) }, priority: 10, minChunks: 2, From 4009f99234f6d4adc38d1421e4d360e2fd66307a Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Tue, 4 Feb 2020 14:23:46 -0500 Subject: [PATCH 08/26] v9.2.2-canary.11 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-google-analytics/package.json | 2 +- packages/next-plugin-material-ui/package.json | 2 +- packages/next-plugin-sentry/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next/package.json | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lerna.json b/lerna.json index 4deca3e2040dde..335e45abeee52b 100644 --- a/lerna.json +++ b/lerna.json @@ -12,5 +12,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "9.2.2-canary.10" + "version": "9.2.2-canary.11" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index c23ad7613e2ad2..5b0f26036bee65 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "9.2.2-canary.10", + "version": "9.2.2-canary.11", "keywords": [ "react", "next", diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index bb13e2c0e1b56a..8738a7c444eb15 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "9.2.2-canary.10", + "version": "9.2.2-canary.11", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index d5c5efea5e30e2..ce3ce36d8df5a9 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "9.2.2-canary.10", + "version": "9.2.2-canary.11", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-google-analytics/package.json b/packages/next-plugin-google-analytics/package.json index 352c4c722be78f..7e49cbbc4e24c0 100644 --- a/packages/next-plugin-google-analytics/package.json +++ b/packages/next-plugin-google-analytics/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-google-analytics", - "version": "9.2.2-canary.10", + "version": "9.2.2-canary.11", "nextjs": { "name": "Google Analytics", "required-env": [ diff --git a/packages/next-plugin-material-ui/package.json b/packages/next-plugin-material-ui/package.json index b47f072b06c3b7..52649c66c81853 100644 --- a/packages/next-plugin-material-ui/package.json +++ b/packages/next-plugin-material-ui/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-material-ui", - "version": "9.2.2-canary.10", + "version": "9.2.2-canary.11", "nextjs": { "name": "Material UI", "required-env": [] diff --git a/packages/next-plugin-sentry/package.json b/packages/next-plugin-sentry/package.json index 050ced1a24dd9c..47e638b87315dd 100644 --- a/packages/next-plugin-sentry/package.json +++ b/packages/next-plugin-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-sentry", - "version": "9.2.2-canary.10", + "version": "9.2.2-canary.11", "nextjs": { "name": "Sentry", "required-env": [ diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 28661f7600192b..2deb7a18b80ff7 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "9.2.2-canary.10", + "version": "9.2.2-canary.11", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next/package.json b/packages/next/package.json index b802f3bbc99d5e..713ef233fe55a0 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "9.2.2-canary.10", + "version": "9.2.2-canary.11", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -73,7 +73,7 @@ "@babel/preset-typescript": "7.7.2", "@babel/runtime": "7.7.2", "@babel/runtime-corejs2": "7.7.2", - "@next/polyfill-nomodule": "9.2.2-canary.10", + "@next/polyfill-nomodule": "9.2.2-canary.11", "amphtml-validator": "1.0.23", "async-retry": "1.2.3", "async-sema": "3.0.0", From ecd628b7e0619da7677b57138a7dd59c1b581b59 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Tue, 4 Feb 2020 14:58:22 -0500 Subject: [PATCH 09/26] Re-enable `native-url` (#10419) * Re-enable `native-url` * update sizes --- packages/next/build/webpack-config.ts | 2 +- packages/next/package.json | 1 + .../integration/size-limit/test/index.test.js | 4 +-- yarn.lock | 34 +++++++++++++++++-- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 12aedaf210d435..46b587c59f0572 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -107,7 +107,7 @@ function getOptimizedAliases( 'object.assign/shim': path.join(shimAssign, 'shim.js'), // Replace: full URL polyfill with platform-based polyfill - // url: require.resolve('native-url'), + url: require.resolve('native-url'), } ) } diff --git a/packages/next/package.json b/packages/next/package.json index 713ef233fe55a0..1dabed45b9fe61 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -114,6 +114,7 @@ "lru-cache": "5.1.1", "mini-css-extract-plugin": "0.8.0", "mkdirp": "0.5.1", + "native-url": "0.2.6", "node-fetch": "2.6.0", "object-assign": "4.1.1", "ora": "3.4.0", diff --git a/test/integration/size-limit/test/index.test.js b/test/integration/size-limit/test/index.test.js index a4e986d5265f2b..f1d7c0af660eb4 100644 --- a/test/integration/size-limit/test/index.test.js +++ b/test/integration/size-limit/test/index.test.js @@ -81,7 +81,7 @@ describe('Production response size', () => { ) // These numbers are without gzip compression! - const delta = responseSizeKilobytes - 234 + const delta = responseSizeKilobytes - 227 expect(delta).toBeLessThanOrEqual(0) // don't increase size expect(delta).toBeGreaterThanOrEqual(-1) // don't decrease size without updating target }) @@ -101,7 +101,7 @@ describe('Production response size', () => { ) // These numbers are without gzip compression! - const delta = responseSizeKilobytes - 202 + const delta = responseSizeKilobytes - 195 expect(delta).toBeLessThanOrEqual(0) // don't increase size expect(delta).toBeGreaterThanOrEqual(-1) // don't decrease size without updating target }) diff --git a/yarn.lock b/yarn.lock index 87c2546129d42a..344301d01b2c4d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4133,7 +4133,7 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@4.8.3, browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6, browserslist@^4.0.0, browserslist@^4.3.6, browserslist@^4.6.0, browserslist@^4.6.4, browserslist@^4.8.0, browserslist@^4.8.2, browserslist@^4.8.3: +browserslist@4.8.3, browserslist@^4.0.0, browserslist@^4.3.6, browserslist@^4.6.0, browserslist@^4.6.4, browserslist@^4.8.0, browserslist@^4.8.2, browserslist@^4.8.3: version "4.8.3" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.3.tgz#65802fcd77177c878e015f0e3189f2c4f627ba44" integrity sha512-iU43cMMknxG1ClEZ2MDKeonKE1CCrFVkQK2AqO2YWFmvIrx4JWrvQ4w4hQez6EpVI8rHTtqh/ruHHDHSOKxvUg== @@ -4142,6 +4142,14 @@ browserslist@4.8.3, browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7. electron-to-chromium "^1.3.322" node-releases "^1.1.44" +browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: + version "1.7.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" + integrity sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk= + dependencies: + caniuse-db "^1.0.30000639" + electron-to-chromium "^1.2.7" + browserstack-local@1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/browserstack-local/-/browserstack-local-1.4.0.tgz#d979cac056f57b9af159b3bcd7fdc09b4354537c" @@ -4440,11 +4448,21 @@ caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634: resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30001023.tgz#f856f71af16a5a44e81f1fcefc1673912a43da72" integrity sha512-EnlshvE6oAum+wWwKmJNVaoqJMjIc0bLUy4Dj77VVnz1o6bzSPr1Ze9iPy6g5ycg1xD6jGU6vBmo7pLEz2MbCQ== -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001012, caniuse-lite@^1.0.30001017, caniuse-lite@^1.0.30001019, caniuse-lite@^1.0.30001020: +caniuse-db@^1.0.30000639: + version "1.0.30001025" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30001025.tgz#33b6b126f3070a54fa8017bb5c4a0fd6b787d6f1" + integrity sha512-HtUBOYgagTFMOa8/OSVkXbDS/YiByZZoi4H+ksKgoDfNmMVoodxnH373bXleumM1kg1IXvLspLMKIS7guWEBhg== + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001012, caniuse-lite@^1.0.30001017, caniuse-lite@^1.0.30001019: version "1.0.30001019" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001019.tgz#857e3fccaad2b2feb3f1f6d8a8f62d747ea648e1" integrity sha512-6ljkLtF1KM5fQ+5ZN0wuyVvvebJxgJPTmScOMaFuQN2QuOzvRJnWSKfzQskQU5IOU4Gap3zasYPIinzwUjoj/g== +caniuse-lite@^1.0.30001020: + version "1.0.30001025" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001025.tgz#30336a8aca7f98618eb3cf38e35184e13d4e5fe6" + integrity sha512-SKyFdHYfXUZf5V85+PJgLYyit27q4wgvZuf8QTOk1osbypcROihMBlx9GRar2/pIcKH2r4OehdlBr9x6PXetAQ== + capitalize@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/capitalize/-/capitalize-1.0.0.tgz#dc802c580aee101929020d2ca14b4ca8a0ae44be" @@ -6202,6 +6220,11 @@ ejs@^2.6.1: resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== +electron-to-chromium@^1.2.7: + version "1.3.345" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.345.tgz#2569d0d54a64ef0f32a4b7e8c80afa5fe57c5d98" + integrity sha512-f8nx53+Z9Y+SPWGg3YdHrbYYfIJAtbUjpFfW4X1RwTZ94iUG7geg9tV8HqzAXX7XTNgyWgAFvce4yce8ZKxKmg== + electron-to-chromium@^1.3.322: version "1.3.327" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.327.tgz#516f28b4271727004362b4ac814494ae64d9dde7" @@ -10829,6 +10852,13 @@ native-or-bluebird@^1.2.0: resolved "https://registry.yarnpkg.com/native-or-bluebird/-/native-or-bluebird-1.2.0.tgz#39c47bfd7825d1fb9ffad32210ae25daadf101c9" integrity sha1-OcR7/Xgl0fuf+tMiEK4l2q3xAck= +native-url@0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/native-url/-/native-url-0.2.6.tgz#ca1258f5ace169c716ff44eccbddb674e10399ae" + integrity sha512-k4bDC87WtgrdD362gZz6zoiXQrl40kYlBmpfmSjwRO1VU0V5ccwJTlxuE72F6m3V0vc1xOf6n3UCP9QyerRqmA== + dependencies: + querystring "^0.2.0" + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" From ec39aa46dc40e4b2a86e6500fdf5b48d30c1fa0d Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 4 Feb 2020 14:10:40 -0600 Subject: [PATCH 10/26] Update optimize event with static 404 status (#10420) Co-authored-by: Joe Haddad --- packages/next/build/index.ts | 1 + packages/next/telemetry/events/build.ts | 1 + test/integration/telemetry/test/index.test.js | 11 +++++++++++ 3 files changed, 13 insertions(+) diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index bf2053faeab2b8..4d4307882bf0c2 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -773,6 +773,7 @@ export default async function build(dir: string, conf = null): Promise { durationInSeconds: analysisEnd[0], staticPageCount: staticPages.size, ssrPageCount: pagePaths.length - staticPages.size, + hasStatic404: useStatic404, }) ) diff --git a/packages/next/telemetry/events/build.ts b/packages/next/telemetry/events/build.ts index 7ea9f882a2e960..8ab16b812ae208 100644 --- a/packages/next/telemetry/events/build.ts +++ b/packages/next/telemetry/events/build.ts @@ -40,6 +40,7 @@ type EventBuildOptimized = { ssrPageCount: number hasDunderPages: boolean hasTestPages: boolean + hasStatic404: boolean } export function eventBuildOptimize( diff --git a/test/integration/telemetry/test/index.test.js b/test/integration/telemetry/test/index.test.js index 32b0979b71cd2c..51ccb25fa1c057 100644 --- a/test/integration/telemetry/test/index.test.js +++ b/test/integration/telemetry/test/index.test.js @@ -8,6 +8,7 @@ import { findPort, killApp, waitFor, + nextBuild, } from 'next-test-utils' jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 2 @@ -117,6 +118,16 @@ describe('Telemetry CLI', () => { expect(event2).toMatch(/hasTestPages.*?true/) }) + it('detect static 404 correctly for `next build`', async () => { + const { stderr } = await nextBuild(appDir, [], { + stderr: true, + env: { NEXT_TELEMETRY_DEBUG: 1 }, + }) + + const event1 = /NEXT_BUILD_OPTIMIZED[\s\S]+?{([\s\S]+?)}/.exec(stderr).pop() + expect(event1).toMatch(/hasStatic404.*?true/) + }) + it('detects isSrcDir dir correctly for `next dev`', async () => { let port = await findPort() let stderr = '' From 5ae7fe534e6e395266821b757e28da37bc68c9de Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 4 Feb 2020 20:55:11 -0600 Subject: [PATCH 11/26] De-dupe paths returned in getStaticPaths (#10423) * De-dupe paths returned in getStaticPaths * Remove warning --- packages/next/build/utils.ts | 10 +++---- .../prerender/pages/blog/[post]/index.js | 1 + yarn.lock | 27 ++----------------- 3 files changed, 8 insertions(+), 30 deletions(-) diff --git a/packages/next/build/utils.ts b/packages/next/build/utils.ts index 3c68b3d5485926..0ff3ee4a50db5f 100644 --- a/packages/next/build/utils.ts +++ b/packages/next/build/utils.ts @@ -531,9 +531,9 @@ export async function isPageStatic( ) } - let prerenderPaths: string[] | undefined + let prerenderPaths: Set | undefined if (hasStaticProps && hasStaticPaths) { - prerenderPaths = [] as string[] + prerenderPaths = new Set() const _routeRegex = getRouteRegex(page) const _routeMatcher = getRouteMatcher(_routeRegex) @@ -555,7 +555,7 @@ export async function isPageStatic( ) } - prerenderPaths!.push(entry) + prerenderPaths?.add(entry) } // For the object-provided path, we must make sure it specifies all // required keys. @@ -598,7 +598,7 @@ export async function isPageStatic( ) }) - prerenderPaths!.push(builtPage) + prerenderPaths?.add(builtPage) } }) } @@ -607,7 +607,7 @@ export async function isPageStatic( return { isStatic: !hasStaticProps && !hasGetInitialProps && !hasServerProps, isHybridAmp: config.amp === 'hybrid', - prerenderRoutes: prerenderPaths, + prerenderRoutes: prerenderPaths && [...prerenderPaths], hasStaticProps, hasServerProps, } diff --git a/test/integration/prerender/pages/blog/[post]/index.js b/test/integration/prerender/pages/blog/[post]/index.js index 7d44195d3bd8a3..89ed5a94c9d637 100644 --- a/test/integration/prerender/pages/blog/[post]/index.js +++ b/test/integration/prerender/pages/blog/[post]/index.js @@ -10,6 +10,7 @@ export async function unstable_getStaticPaths() { '/blog/[post3]', '/blog/post-4', '/blog/post.1', + '/blog/post.1', // handle duplicates ] } diff --git a/yarn.lock b/yarn.lock index 344301d01b2c4d..11c5f42701ef9f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4133,7 +4133,7 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@4.8.3, browserslist@^4.0.0, browserslist@^4.3.6, browserslist@^4.6.0, browserslist@^4.6.4, browserslist@^4.8.0, browserslist@^4.8.2, browserslist@^4.8.3: +browserslist@4.8.3, browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6, browserslist@^4.0.0, browserslist@^4.3.6, browserslist@^4.6.0, browserslist@^4.6.4, browserslist@^4.8.0, browserslist@^4.8.2, browserslist@^4.8.3: version "4.8.3" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.3.tgz#65802fcd77177c878e015f0e3189f2c4f627ba44" integrity sha512-iU43cMMknxG1ClEZ2MDKeonKE1CCrFVkQK2AqO2YWFmvIrx4JWrvQ4w4hQez6EpVI8rHTtqh/ruHHDHSOKxvUg== @@ -4142,14 +4142,6 @@ browserslist@4.8.3, browserslist@^4.0.0, browserslist@^4.3.6, browserslist@^4.6. electron-to-chromium "^1.3.322" node-releases "^1.1.44" -browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: - version "1.7.7" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" - integrity sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk= - dependencies: - caniuse-db "^1.0.30000639" - electron-to-chromium "^1.2.7" - browserstack-local@1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/browserstack-local/-/browserstack-local-1.4.0.tgz#d979cac056f57b9af159b3bcd7fdc09b4354537c" @@ -4448,21 +4440,11 @@ caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634: resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30001023.tgz#f856f71af16a5a44e81f1fcefc1673912a43da72" integrity sha512-EnlshvE6oAum+wWwKmJNVaoqJMjIc0bLUy4Dj77VVnz1o6bzSPr1Ze9iPy6g5ycg1xD6jGU6vBmo7pLEz2MbCQ== -caniuse-db@^1.0.30000639: - version "1.0.30001025" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30001025.tgz#33b6b126f3070a54fa8017bb5c4a0fd6b787d6f1" - integrity sha512-HtUBOYgagTFMOa8/OSVkXbDS/YiByZZoi4H+ksKgoDfNmMVoodxnH373bXleumM1kg1IXvLspLMKIS7guWEBhg== - -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001012, caniuse-lite@^1.0.30001017, caniuse-lite@^1.0.30001019: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001012, caniuse-lite@^1.0.30001017, caniuse-lite@^1.0.30001019, caniuse-lite@^1.0.30001020: version "1.0.30001019" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001019.tgz#857e3fccaad2b2feb3f1f6d8a8f62d747ea648e1" integrity sha512-6ljkLtF1KM5fQ+5ZN0wuyVvvebJxgJPTmScOMaFuQN2QuOzvRJnWSKfzQskQU5IOU4Gap3zasYPIinzwUjoj/g== -caniuse-lite@^1.0.30001020: - version "1.0.30001025" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001025.tgz#30336a8aca7f98618eb3cf38e35184e13d4e5fe6" - integrity sha512-SKyFdHYfXUZf5V85+PJgLYyit27q4wgvZuf8QTOk1osbypcROihMBlx9GRar2/pIcKH2r4OehdlBr9x6PXetAQ== - capitalize@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/capitalize/-/capitalize-1.0.0.tgz#dc802c580aee101929020d2ca14b4ca8a0ae44be" @@ -6220,11 +6202,6 @@ ejs@^2.6.1: resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== -electron-to-chromium@^1.2.7: - version "1.3.345" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.345.tgz#2569d0d54a64ef0f32a4b7e8c80afa5fe57c5d98" - integrity sha512-f8nx53+Z9Y+SPWGg3YdHrbYYfIJAtbUjpFfW4X1RwTZ94iUG7geg9tV8HqzAXX7XTNgyWgAFvce4yce8ZKxKmg== - electron-to-chromium@^1.3.322: version "1.3.327" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.327.tgz#516f28b4271727004362b4ac814494ae64d9dde7" From 4203d7fd52633bbf67e7aa6cd313236e82e3a4d7 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 4 Feb 2020 21:44:06 -0600 Subject: [PATCH 12/26] v9.2.2-canary.12 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-google-analytics/package.json | 2 +- packages/next-plugin-material-ui/package.json | 2 +- packages/next-plugin-sentry/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next/package.json | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lerna.json b/lerna.json index 335e45abeee52b..6987f62510d9aa 100644 --- a/lerna.json +++ b/lerna.json @@ -12,5 +12,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "9.2.2-canary.11" + "version": "9.2.2-canary.12" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 5b0f26036bee65..d7ae204f608bca 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "9.2.2-canary.11", + "version": "9.2.2-canary.12", "keywords": [ "react", "next", diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 8738a7c444eb15..caad0f5d68fff8 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "9.2.2-canary.11", + "version": "9.2.2-canary.12", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index ce3ce36d8df5a9..415e161699ff2c 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "9.2.2-canary.11", + "version": "9.2.2-canary.12", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-google-analytics/package.json b/packages/next-plugin-google-analytics/package.json index 7e49cbbc4e24c0..f9c08bc02b8b57 100644 --- a/packages/next-plugin-google-analytics/package.json +++ b/packages/next-plugin-google-analytics/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-google-analytics", - "version": "9.2.2-canary.11", + "version": "9.2.2-canary.12", "nextjs": { "name": "Google Analytics", "required-env": [ diff --git a/packages/next-plugin-material-ui/package.json b/packages/next-plugin-material-ui/package.json index 52649c66c81853..1c2d25edc627a0 100644 --- a/packages/next-plugin-material-ui/package.json +++ b/packages/next-plugin-material-ui/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-material-ui", - "version": "9.2.2-canary.11", + "version": "9.2.2-canary.12", "nextjs": { "name": "Material UI", "required-env": [] diff --git a/packages/next-plugin-sentry/package.json b/packages/next-plugin-sentry/package.json index 47e638b87315dd..ef164ca151db80 100644 --- a/packages/next-plugin-sentry/package.json +++ b/packages/next-plugin-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-sentry", - "version": "9.2.2-canary.11", + "version": "9.2.2-canary.12", "nextjs": { "name": "Sentry", "required-env": [ diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 2deb7a18b80ff7..ee8a42b7c74571 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "9.2.2-canary.11", + "version": "9.2.2-canary.12", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next/package.json b/packages/next/package.json index 1dabed45b9fe61..fcfd317e93fe46 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "9.2.2-canary.11", + "version": "9.2.2-canary.12", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -73,7 +73,7 @@ "@babel/preset-typescript": "7.7.2", "@babel/runtime": "7.7.2", "@babel/runtime-corejs2": "7.7.2", - "@next/polyfill-nomodule": "9.2.2-canary.11", + "@next/polyfill-nomodule": "9.2.2-canary.12", "amphtml-validator": "1.0.23", "async-retry": "1.2.3", "async-sema": "3.0.0", From c8e5f925a0bd441fd8a01d96bc757add5d3918f0 Mon Sep 17 00:00:00 2001 From: Roman Ernst Date: Wed, 5 Feb 2020 17:02:45 +0100 Subject: [PATCH 13/26] Make apollo HOC composable (#10422) * Wraps config in higher-order function --- examples/with-apollo/lib/apollo.js | 9 +++------ examples/with-apollo/pages/client-only.js | 6 ++---- examples/with-apollo/pages/index.js | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/examples/with-apollo/lib/apollo.js b/examples/with-apollo/lib/apollo.js index 54e4e3b8c8a4c2..2c96ca96f72d0a 100644 --- a/examples/with-apollo/lib/apollo.js +++ b/examples/with-apollo/lib/apollo.js @@ -12,11 +12,8 @@ let globalApolloClient = null * Creates and provides the apolloContext * to a next.js PageTree. Use it by wrapping * your PageComponent via HOC pattern. - * @param {Function|Class} PageComponent - * @param {Object} [config] - * @param {Boolean} [config.ssr=true] */ -export function withApollo(PageComponent, { ssr = true } = {}) { +export const withApollo = ({ ssr = true } = {}) => PageComponent => { const WithApollo = ({ apolloClient, apolloState, ...pageProps }) => { const client = apolloClient || initApolloClient(apolloState) return ( @@ -104,7 +101,7 @@ export function withApollo(PageComponent, { ssr = true } = {}) { * Creates or reuses apollo client in the browser. * @param {Object} initialState */ -function initApolloClient(initialState) { +const initApolloClient = initialState => { // Make sure to create a new client for every server-side request so that data // isn't shared between connections (which would be bad) if (typeof window === 'undefined') { @@ -123,7 +120,7 @@ function initApolloClient(initialState) { * Creates and configures the ApolloClient * @param {Object} [initialState={}] */ -function createApolloClient(initialState = {}) { +const createApolloClient = (initialState = {}) => { // Check out https://github.com/zeit/next.js/pull/4611 if you want to use the AWSAppSyncClient return new ApolloClient({ ssrMode: typeof window === 'undefined', // Disables forceFetch on the server (so queries are only run once) diff --git a/examples/with-apollo/pages/client-only.js b/examples/with-apollo/pages/client-only.js index 1866c0941bf525..7fa37e3ca22b52 100644 --- a/examples/with-apollo/pages/client-only.js +++ b/examples/with-apollo/pages/client-only.js @@ -26,7 +26,5 @@ const ClientOnlyPage = props => ( ) -export default withApollo(ClientOnlyPage, { - // Disable apollo ssr fetching in favour of automatic static optimization - ssr: false, -}) +// Disable apollo ssr fetching in favour of automatic static optimization +export default withApollo({ ssr: false })(ClientOnlyPage) diff --git a/examples/with-apollo/pages/index.js b/examples/with-apollo/pages/index.js index fd7361809593d7..d40059d1a4620c 100644 --- a/examples/with-apollo/pages/index.js +++ b/examples/with-apollo/pages/index.js @@ -26,4 +26,4 @@ const IndexPage = props => ( ) -export default withApollo(IndexPage) +export default withApollo()(IndexPage) From 0b1ef7cbf45ee23694b83b9efbf62eb9bd29f6c9 Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 5 Feb 2020 17:03:41 +0100 Subject: [PATCH 14/26] Adjust README of example (#10426) --- examples/with-zones/README.md | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/examples/with-zones/README.md b/examples/with-zones/README.md index 4eb263d57c88d5..a10e282471baa6 100644 --- a/examples/with-zones/README.md +++ b/examples/with-zones/README.md @@ -31,21 +31,15 @@ cd with-zones ## Notes -In this example, we have two apps: 'home' and 'blog'. We'll start both apps with [Now](https://zeit.co/now): - -```bash -now dev -``` - -Then, you can visit and develop for both apps as a single app. - -You can also start the apps separately, for example: +In this example, we have two apps: 'home' and 'blog'. You can start each app separately, for example: ```bash cd blog yarn dev ``` +Then, you can visit and develop your app. + ## Special Notes - All pages should be unique across zones. For example, the 'home' app should not have a `pages/blog/index.js` page. @@ -55,8 +49,11 @@ yarn dev ## Production Deployment -We only need to run `now`, the same `now.json` used for development will be used for the deployment: +We only need to run `now `, to deploy the app: ```bash -now +now blog +now home ``` + +> The rewrite destination in your `now.json` file in the `home` app must be adjusted to point to your deployment. From 924f8ae3b643b0ffba2fb9dbb5bdc3eb33642fdc Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 5 Feb 2020 10:52:34 -0600 Subject: [PATCH 15/26] Remove old ts-ignores and extra value in routeInfo (#10429) --- packages/next/next-server/lib/router/router.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/next/next-server/lib/router/router.ts b/packages/next/next-server/lib/router/router.ts index 4c5a30545b8399..954ed71636e404 100644 --- a/packages/next/next-server/lib/router/router.ts +++ b/packages/next/next-server/lib/router/router.ts @@ -150,7 +150,6 @@ export default class Router implements BaseRouter { // Backwards compat for Router.router.events // TODO: Should be remove the following major version as it was never documented - // @ts-ignore backwards compatibility this.events = Router.events this.pageLoader = pageLoader @@ -355,7 +354,6 @@ export default class Router implements BaseRouter { method = 'replaceState' } - // @ts-ignore pathname is always a string const route = toRoute(pathname) const { shallow = false } = options @@ -394,7 +392,6 @@ export default class Router implements BaseRouter { Router.events.emit('routeChangeStart', as) // If shallow is true and the route exists in the router cache we reuse the previous result - // @ts-ignore pathname is always a string this.getRouteInfo(route, pathname, query, as, shallow).then(routeInfo => { const { error } = routeInfo @@ -404,7 +401,6 @@ export default class Router implements BaseRouter { Router.events.emit('beforeHistoryChange', as) this.changeState(method, url, addBasePath(as), options) - const hash = window.location.hash.substring(1) if (process.env.NODE_ENV !== 'production') { const appComp: any = this.components['/_app'].Component @@ -413,8 +409,7 @@ export default class Router implements BaseRouter { !(routeInfo.Component as any).getInitialProps } - // @ts-ignore pathname is always defined - this.set(route, pathname, query, as, { ...routeInfo, hash }) + this.set(route, pathname, query, as, routeInfo) if (error) { Router.events.emit('routeChangeError', error, as) @@ -658,7 +653,6 @@ export default class Router implements BaseRouter { return } - // @ts-ignore pathname is always defined const route = toRoute(pathname) this.pageLoader.prefetch(route).then(resolve, reject) }) From a4c507d5b45988091df26d0a1bbbcc82daee1530 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 5 Feb 2020 15:10:39 -0600 Subject: [PATCH 16/26] Update to use existing util to de-dupe path check (#10431) * Update to use existing util to de-dupe path check * Update error message for requested/resolved mismatch * Use correct dataRoute value for prerender manifest * Fix pageUrl having double slash on Windows --- packages/next/build/entries.ts | 3 ++- packages/next/build/index.ts | 20 +++++++++---------- packages/next/export/index.ts | 3 ++- packages/next/export/worker.js | 3 ++- .../next/next-server/server/next-server.ts | 3 ++- .../next-server/server/normalize-page-path.ts | 4 +++- packages/next/next-server/server/require.ts | 1 - packages/next/next-server/server/spr-cache.ts | 4 ++-- .../next/server/on-demand-entry-handler.ts | 10 +++++++--- 9 files changed, 29 insertions(+), 22 deletions(-) diff --git a/packages/next/build/entries.ts b/packages/next/build/entries.ts index c8385cfa4d818e..b6049f2bc96a57 100644 --- a/packages/next/build/entries.ts +++ b/packages/next/build/entries.ts @@ -6,6 +6,7 @@ import { API_ROUTE, DOT_NEXT_ALIAS, PAGES_DIR_ALIAS } from '../lib/constants' import { isTargetLikeServerless } from '../next-server/server/config' import { warn } from './output/log' import { ServerlessLoaderQuery } from './webpack/loaders/next-serverless-loader' +import { normalizePagePath } from '../next-server/server/normalize-page-path' type PagesMapping = { [page: string]: string @@ -91,7 +92,7 @@ export function createEntrypoints( Object.keys(pages).forEach(page => { const absolutePagePath = pages[page] - const bundleFile = page === '/' ? '/index.js' : `${page}.js` + const bundleFile = `${normalizePagePath(page)}.js` const isApiRoute = page.match(API_ROUTE) const bundlePath = join('static', buildId, 'pages', bundleFile) diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index 4d4307882bf0c2..22e0d4d1ba2cc3 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -67,6 +67,7 @@ import { } from './utils' import getBaseWebpackConfig from './webpack-config' import { writeBuildId } from './write-build-id' +import { normalizePagePath } from '../next-server/server/normalize-page-path' const fsAccess = promisify(fs.access) const fsUnlink = promisify(fs.unlink) @@ -435,7 +436,7 @@ export default async function build(dir: string, conf = null): Promise { const analysisBegin = process.hrtime() await Promise.all( pageKeys.map(async page => { - const actualPage = page === '/' ? '/index' : page + const actualPage = normalizePagePath(page) const [selfSize, allSize] = await getPageSizeInKb( actualPage, distDir, @@ -554,10 +555,11 @@ export default async function build(dir: string, conf = null): Promise { routesManifest.serverPropsRoutes = {} for (const page of serverPropsPages) { + const pagePath = normalizePagePath(page) const dataRoute = path.posix.join( '/_next/data', buildId, - `${page === '/' ? '/index' : page}.json` + `${pagePath}.json` ) routesManifest.serverPropsRoutes[page] = { @@ -571,7 +573,7 @@ export default async function build(dir: string, conf = null): Promise { `^${path.posix.join( '/_next/data', escapeStringRegexp(buildId), - `${page === '/' ? '/index' : page}.json` + `${pagePath}.json` )}$` ).source, } @@ -709,7 +711,7 @@ export default async function build(dir: string, conf = null): Promise { for (const page of combinedPages) { const isSsg = ssgPages.has(page) const isDynamic = isDynamicRoute(page) - let file = page === '/' ? '/index' : page + const file = normalizePagePath(page) // The dynamic version of SSG pages are not prerendered. Below, we handle // the specific prerenders of these. if (!(isSsg && isDynamic)) { @@ -729,11 +731,7 @@ export default async function build(dir: string, conf = null): Promise { initialRevalidateSeconds: exportConfig.initialPageRevalidationMap[page], srcRoute: null, - dataRoute: path.posix.join( - '/_next/data', - buildId, - `${page === '/' ? '/index' : page}.json` - ), + dataRoute: path.posix.join('/_next/data', buildId, `${file}.json`), } } else { // For a dynamic SSG page, we did not copy its html nor data exports. @@ -750,7 +748,7 @@ export default async function build(dir: string, conf = null): Promise { dataRoute: path.posix.join( '/_next/data', buildId, - `${route === '/' ? '/index' : route}.json` + `${normalizePagePath(route)}.json` ), } } @@ -783,7 +781,7 @@ export default async function build(dir: string, conf = null): Promise { const dataRoute = path.posix.join( '/_next/data', buildId, - `${tbdRoute === '/' ? '/index' : tbdRoute}.json` + `${normalizePagePath(tbdRoute)}.json` ) finalDynamicRoutes[tbdRoute] = { diff --git a/packages/next/export/index.ts b/packages/next/export/index.ts index 40f0c33ca68852..386928105af992 100644 --- a/packages/next/export/index.ts +++ b/packages/next/export/index.ts @@ -33,6 +33,7 @@ import loadConfig, { } from '../next-server/server/config' import { eventVersion } from '../telemetry/events' import { Telemetry } from '../telemetry/storage' +import { normalizePagePath } from '../next-server/server/normalize-page-path' const mkdirp = promisify(mkdirpModule) const copyFile = promisify(copyFileOrig) @@ -352,7 +353,7 @@ export default async function( if (!options.buildExport && prerenderManifest) { await Promise.all( Object.keys(prerenderManifest.routes).map(async route => { - route = route === '/' ? '/index' : route + route = normalizePagePath(route) const orig = join(distPagesDir, route) const htmlDest = join( outDir, diff --git a/packages/next/export/worker.js b/packages/next/export/worker.js index 61a2a88e2517d6..2ca8fb688cb233 100644 --- a/packages/next/export/worker.js +++ b/packages/next/export/worker.js @@ -9,6 +9,7 @@ import { loadComponents } from '../next-server/server/load-components' import { isDynamicRoute } from '../next-server/lib/router/utils/is-dynamic' import { getRouteMatcher } from '../next-server/lib/router/utils/route-matcher' import { getRouteRegex } from '../next-server/lib/router/utils/route-regex' +import { normalizePagePath } from '../next-server/server/normalize-page-path' const envConfig = require('../next-server/lib/runtime-config') const writeFileP = promisify(writeFile) @@ -39,7 +40,7 @@ export default async function({ try { const { query: originalQuery = {} } = pathMap const { page } = pathMap - const filePath = path === '/' ? '/index' : path + const filePath = normalizePagePath(path) const ampPath = `${filePath}.amp` let query = { ...originalQuery } let params diff --git a/packages/next/next-server/server/next-server.ts b/packages/next/next-server/server/next-server.ts index c817e6890e65ca..a1b3a75bdce2e0 100644 --- a/packages/next/next-server/server/next-server.ts +++ b/packages/next/next-server/server/next-server.ts @@ -52,6 +52,7 @@ import { Header, getRedirectStatus, } from '../../lib/check-custom-routes' +import { normalizePagePath } from './normalize-page-path' const getCustomRouteMatcher = pathMatch(true) @@ -815,7 +816,7 @@ export default class Server { return await loadComponents( this.distDir, this.buildId, - (pathname === '/' ? '/index' : pathname) + '.amp', + normalizePagePath(pathname) + '.amp', serverless ) } catch (err) { diff --git a/packages/next/next-server/server/normalize-page-path.ts b/packages/next/next-server/server/normalize-page-path.ts index 1102a4ec91aa8a..13728d1d326dce 100644 --- a/packages/next/next-server/server/normalize-page-path.ts +++ b/packages/next/next-server/server/normalize-page-path.ts @@ -11,7 +11,9 @@ export function normalizePagePath(page: string): string { // Throw when using ../ etc in the pathname const resolvedPage = posix.normalize(page) if (page !== resolvedPage) { - throw new Error('Requested and resolved page mismatch') + throw new Error( + `Requested and resolved page mismatch: ${page} ${resolvedPage}` + ) } return page } diff --git a/packages/next/next-server/server/require.ts b/packages/next/next-server/server/require.ts index c846fedf5be52e..bd2251cc4c0c7e 100644 --- a/packages/next/next-server/server/require.ts +++ b/packages/next/next-server/server/require.ts @@ -30,7 +30,6 @@ export function getPagePath( try { page = normalizePagePath(page) - page = page === '/' ? '/index' : page } catch (err) { // tslint:disable-next-line console.error(err) diff --git a/packages/next/next-server/server/spr-cache.ts b/packages/next/next-server/server/spr-cache.ts index 4e7a9c1f9858c7..0de1a419e6049b 100644 --- a/packages/next/next-server/server/spr-cache.ts +++ b/packages/next/next-server/server/spr-cache.ts @@ -146,12 +146,12 @@ export async function setSprCache( ) { if (sprOptions.dev) return if (typeof revalidateSeconds !== 'undefined') { - // TODO: This is really bad. We shouldn't be mutating the manifest from the + // TODO: Update this to not mutate the manifest from the // build. prerenderManifest.routes[pathname] = { dataRoute: path.posix.join( '/_next/data', - `${pathname === '/' ? '/index' : pathname}.json` + `${normalizePagePath(pathname)}.json` ), srcRoute: null, // FIXME: provide actual source route, however, when dynamically appending it doesn't really matter initialRevalidateSeconds: revalidateSeconds, diff --git a/packages/next/server/on-demand-entry-handler.ts b/packages/next/server/on-demand-entry-handler.ts index fc10177df54e40..550fd09adb3f26 100644 --- a/packages/next/server/on-demand-entry-handler.ts +++ b/packages/next/server/on-demand-entry-handler.ts @@ -285,11 +285,15 @@ export default function onDemandEntryHandler( throw pageNotFoundError(normalizedPagePath) } - let pageUrl = `/${pagePath + let pageUrl = pagePath.replace(/\\/g, '/') + + pageUrl = `${pageUrl[0] !== '/' ? '/' : ''}${pageUrl .replace(new RegExp(`\\.+(?:${pageExtensions.join('|')})$`), '') - .replace(/\\/g, '/')}`.replace(/\/index$/, '') + .replace(/\/index$/, '')}` + pageUrl = pageUrl === '' ? '/' : pageUrl - const bundleFile = pageUrl === '/' ? '/index.js' : `${pageUrl}.js` + + const bundleFile = `${normalizePagePath(pageUrl)}.js` const name = join('static', buildId, 'pages', bundleFile) const absolutePagePath = pagePath.startsWith('next/dist/pages') ? require.resolve(pagePath) From 238202ec115c093574f263d0cf59e3e05f1baeb1 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 5 Feb 2020 15:27:22 -0600 Subject: [PATCH 17/26] Make missing param error message more specific (#10433) --- packages/next/build/utils.ts | 2 +- .../prerender-invalid-catchall-params/test/index.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next/build/utils.ts b/packages/next/build/utils.ts index 0ff3ee4a50db5f..d21c7be858a82a 100644 --- a/packages/next/build/utils.ts +++ b/packages/next/build/utils.ts @@ -586,7 +586,7 @@ export async function isPageStatic( throw new Error( `A required parameter (${validParamKey}) was not provided as ${ repeat ? 'an array' : 'a string' - }.` + } in unstable_getStaticPaths for ${page}` ) } diff --git a/test/integration/prerender-invalid-catchall-params/test/index.test.js b/test/integration/prerender-invalid-catchall-params/test/index.test.js index a213b919d7a356..d2b47c0c8b0978 100644 --- a/test/integration/prerender-invalid-catchall-params/test/index.test.js +++ b/test/integration/prerender-invalid-catchall-params/test/index.test.js @@ -11,7 +11,7 @@ describe('Invalid Prerender Catchall Params', () => { const out = await nextBuild(appDir, [], { stderr: true }) expect(out.stderr).toMatch(`Build error occurred`) expect(out.stderr).toMatch( - 'A required parameter (slug) was not provided as an array' + 'A required parameter (slug) was not provided as an array in unstable_getStaticPaths for /[...slug]' ) }) }) From 5dfc20dcc7d2503e54e8e96e1ff8c7ea5db31f55 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 5 Feb 2020 15:40:08 -0600 Subject: [PATCH 18/26] Update size-limit test to be more fine grained (#10434) * Update size-limit test to be more fine grained * Decrease default build expected size * Update failing diff amount to be 1kb --- .../integration/size-limit/test/index.test.js | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/test/integration/size-limit/test/index.test.js b/test/integration/size-limit/test/index.test.js index f1d7c0af660eb4..a156295d8ea011 100644 --- a/test/integration/size-limit/test/index.test.js +++ b/test/integration/size-limit/test/index.test.js @@ -5,7 +5,7 @@ import { join } from 'path' import cheerio from 'cheerio' import fetch from 'node-fetch' -jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5 +jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 2 let server let scriptsUrls @@ -23,12 +23,11 @@ function getResponseSizes(resourceUrls) { ) } -function getResponseSizesKB(responseSizes) { - const responseSizeBytes = responseSizes.reduce( +function getResponseSizesBytes(responseSizes) { + return responseSizes.reduce( (accumulator, responseSizeObj) => accumulator + responseSizeObj.bytes, 0 ) - return Math.ceil(responseSizeBytes / 1024) } describe('Production response size', () => { @@ -73,17 +72,17 @@ describe('Production response size', () => { scriptsUrls.filter(path => !path.endsWith('.module.js')) )), ] - const responseSizeKilobytes = getResponseSizesKB(responseSizes) + const responseSizesBytes = getResponseSizesBytes(responseSizes) console.log( `Response Sizes for default:\n${responseSizes .map(obj => ` ${obj.url}: ${obj.bytes} (bytes)`) - .join('\n')} \nOverall: ${responseSizeKilobytes} KB` + .join('\n')} \nOverall: ${responseSizesBytes} KB` ) // These numbers are without gzip compression! - const delta = responseSizeKilobytes - 227 - expect(delta).toBeLessThanOrEqual(0) // don't increase size - expect(delta).toBeGreaterThanOrEqual(-1) // don't decrease size without updating target + const delta = responseSizesBytes - 226 * 1024 + expect(delta).toBeLessThanOrEqual(1024) // don't increase size more than 1kb + expect(delta).toBeGreaterThanOrEqual(-1024) // don't decrease size more than 1kb without updating target }) it('should not increase the overall response size of modern build', async () => { @@ -93,16 +92,16 @@ describe('Production response size', () => { scriptsUrls.filter(path => path.endsWith('.module.js')) )), ] - const responseSizeKilobytes = getResponseSizesKB(responseSizes) + const responseSizesBytes = getResponseSizesBytes(responseSizes) console.log( `Response Sizes for modern:\n${responseSizes .map(obj => ` ${obj.url}: ${obj.bytes} (bytes)`) - .join('\n')} \nOverall: ${responseSizeKilobytes} KB` + .join('\n')} \nOverall: ${responseSizesBytes} bytes` ) // These numbers are without gzip compression! - const delta = responseSizeKilobytes - 195 - expect(delta).toBeLessThanOrEqual(0) // don't increase size - expect(delta).toBeGreaterThanOrEqual(-1) // don't decrease size without updating target + const delta = responseSizesBytes - 195 * 1024 + expect(delta).toBeLessThanOrEqual(1024) // don't increase size more than 1kb + expect(delta).toBeGreaterThanOrEqual(-1024) // don't decrease size more than 1kb without updating target }) }) From ea5c5164b2c8102743c1cc80c534871ef5a8800f Mon Sep 17 00:00:00 2001 From: Luis Alvarez D Date: Thu, 6 Feb 2020 18:03:51 -0500 Subject: [PATCH 19/26] Update utm links in create-next-app (#10442) * Updated links * Use default-example as the medium * Apply suggestion Co-authored-by: JJ Kasper --- packages/create-next-app/templates/default/README.md | 4 ++-- packages/create-next-app/templates/default/pages/index.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/create-next-app/templates/default/README.md b/packages/create-next-app/templates/default/README.md index bdfa3f51f0d208..007329cc4b829a 100644 --- a/packages/create-next-app/templates/default/README.md +++ b/packages/create-next-app/templates/default/README.md @@ -152,7 +152,7 @@ To configure the syntax highlighting in your favorite text editor, head to the [ ## Deploy to Now -[ZEIT Now](https://zeit.co/home?utm_source=create-next-app&utm_medium=referral&utm_campaign=Create%20Next%20App) offers a zero-configuration single-command deployment. +[ZEIT Now](https://zeit.co/home?utm_source=create-next-app&utm_medium=readme&utm_campaign=create-next-app) offers a zero-configuration single-command deployment. 1. Install the `now` command-line tool either via npm `npm install -g now` or Yarn `yarn global add now`. @@ -164,7 +164,7 @@ To configure the syntax highlighting in your favorite text editor, head to the [ Paste that URL into your browser when the build is complete, and you will see your deployed app. -You can find more details about [`ZEIT Now` here](https://zeit.co/home?utm_source=create-next-app&utm_medium=referral&utm_campaign=Create%20Next%20App). +You can find more details about [`ZEIT Now` here](https://zeit.co/home?utm_source=create-next-app&utm_medium=readme&utm_campaign=create-next-app). ## Something Missing? diff --git a/packages/create-next-app/templates/default/pages/index.js b/packages/create-next-app/templates/default/pages/index.js index 871b2b26f22b32..7310dd0dddf5d1 100644 --- a/packages/create-next-app/templates/default/pages/index.js +++ b/packages/create-next-app/templates/default/pages/index.js @@ -37,7 +37,7 @@ const Home = () => (

Deploy →

@@ -50,7 +50,7 @@ const Home = () => (