From 11da014a6a801fdb6bbef6a13261b34ede57c360 Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Sat, 3 Oct 2020 17:29:28 +0200 Subject: [PATCH 01/16] Allow pages to be async modules --- packages/next/build/utils.ts | 2 +- packages/next/client/page-loader.ts | 4 ++-- packages/next/next-server/server/load-components.ts | 8 +++++--- packages/next/next-server/server/next-server.ts | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/next/build/utils.ts b/packages/next/build/utils.ts index 6c5e894c59a..995f4ec6586 100644 --- a/packages/next/build/utils.ts +++ b/packages/next/build/utils.ts @@ -679,7 +679,7 @@ export async function isPageStatic( }> { try { require('../next-server/lib/runtime-config').setConfig(runtimeEnvConfig) - const mod = require(serverBundle) + const mod = await require(serverBundle) const Comp = mod.default || mod if (!Comp || !isValidElementType(Comp) || typeof Comp === 'string') { diff --git a/packages/next/client/page-loader.ts b/packages/next/client/page-loader.ts index 96c1d7f1199..4a90f0e1e2f 100644 --- a/packages/next/client/page-loader.ts +++ b/packages/next/client/page-loader.ts @@ -339,9 +339,9 @@ export default class PageLoader { // This method if called by the route code. registerPage(route: string, regFn: () => any) { - const register = (styleSheets: StyleSheetTuple[]) => { + const register = async (styleSheets: StyleSheetTuple[]) => { try { - const mod = regFn() + const mod = await regFn() const pageData: PageCacheEntry = { page: mod.default || mod, mod, diff --git a/packages/next/next-server/server/load-components.ts b/packages/next/next-server/server/load-components.ts index c523f0a98ba..683864bf431 100644 --- a/packages/next/next-server/server/load-components.ts +++ b/packages/next/next-server/server/load-components.ts @@ -52,9 +52,11 @@ export async function loadComponents( } as LoadComponentsReturnType } - const DocumentMod = requirePage('/_document', distDir, serverless) - const AppMod = requirePage('/_app', distDir, serverless) - const ComponentMod = requirePage(pathname, distDir, serverless) + const [DocumentMod, AppMod, ComponentMod] = await Promise.all([ + requirePage('/_document', distDir, serverless), + requirePage('/_app', distDir, serverless), + requirePage(pathname, distDir, serverless), + ]) const [ buildManifest, diff --git a/packages/next/next-server/server/next-server.ts b/packages/next/next-server/server/next-server.ts index 0cae9e9040b..ad62f25183d 100644 --- a/packages/next/next-server/server/next-server.ts +++ b/packages/next/next-server/server/next-server.ts @@ -764,7 +764,7 @@ export default class Server { throw err } - const pageModule = require(builtPagePath) + const pageModule = await require(builtPagePath) query = { ...query, ...params } if (!this.renderOpts.dev && this._isLikeServerless) { From ef676f80ead35be93f3c08e79064c00901202b68 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Fri, 9 Oct 2020 16:52:34 -0500 Subject: [PATCH 02/16] v9.5.5 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-plugin-next/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-google-analytics/package.json | 2 +- packages/next-plugin-sentry/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next/package.json | 12 ++++++------ packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- 15 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lerna.json b/lerna.json index c2c1d48c45a..cf202dcade0 100644 --- a/lerna.json +++ b/lerna.json @@ -17,5 +17,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "9.5.5-canary.1" + "version": "9.5.5" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 34dca3d500f..d809c8bf0fc 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.5.5-canary.1", + "version": "9.5.5", "keywords": [ "react", "next", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index b630daa2f6c..ff265a01e76 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "9.5.5-canary.1", + "version": "9.5.5", "description": "ESLint plugin for NextJS.", "main": "lib/index.js", "license": "MIT", diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index f47c430e14a..376e6b431f6 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.5.5-canary.1", + "version": "9.5.5", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 14de03b818d..980f6caeb3f 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "9.5.5-canary.1", + "version": "9.5.5", "license": "MIT", "dependencies": { "chalk": "4.1.0", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index ad88ff652ef..5696b515821 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "9.5.5-canary.1", + "version": "9.5.5", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 1fe1891bf0d..bf341debe60 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "9.5.5-canary.1", + "version": "9.5.5", "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 659189e86a5..53d96cd42ed 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.5.5-canary.1", + "version": "9.5.5", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-google-analytics" diff --git a/packages/next-plugin-sentry/package.json b/packages/next-plugin-sentry/package.json index 3f7ab9822d5..2b9f9f9e597 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.5.5-canary.1", + "version": "9.5.5", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-sentry" diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index adc66d9ce48..16281d15243 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "9.5.5-canary.1", + "version": "9.5.5", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index b2e4407fa47..db81b43dab2 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "9.5.5-canary.1", + "version": "9.5.5", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index bab1b149831..85eb9fe92ba 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.5.5-canary.1", + "version": "9.5.5", "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 222131c534b..a25a22dcc29 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "9.5.5-canary.1", + "version": "9.5.5", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -77,10 +77,10 @@ "@babel/runtime": "7.11.2", "@babel/types": "7.11.5", "@hapi/accept": "5.0.1", - "@next/env": "9.5.5-canary.1", - "@next/polyfill-module": "9.5.5-canary.1", - "@next/react-dev-overlay": "9.5.5-canary.1", - "@next/react-refresh-utils": "9.5.5-canary.1", + "@next/env": "9.5.5", + "@next/polyfill-module": "9.5.5", + "@next/react-dev-overlay": "9.5.5", + "@next/react-refresh-utils": "9.5.5", "ast-types": "0.13.2", "babel-plugin-transform-define": "2.0.0", "babel-plugin-transform-react-remove-prop-types": "0.4.24", @@ -124,7 +124,7 @@ "react-dom": "^16.6.0" }, "devDependencies": { - "@next/polyfill-nomodule": "9.5.5-canary.1", + "@next/polyfill-nomodule": "9.5.5", "@taskr/clear": "1.1.0", "@taskr/esnext": "1.1.0", "@taskr/watch": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index dbaae512b06..e3ea389081a 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "9.5.5-canary.1", + "version": "9.5.5", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 363e48d397d..5935a6e8348 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "9.5.5-canary.1", + "version": "9.5.5", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", From 3763db91703ad70464cacdac10411b73364186e3 Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Sun, 11 Oct 2020 16:00:04 +0200 Subject: [PATCH 03/16] add tests --- .eslintrc.json | 4 +- .github/workflows/build_test_deploy.yml | 1 + babel.config.json | 3 + package.json | 3 +- test/integration/async-modules/next.config.js | 9 ++ test/integration/async-modules/pages/_app.js | 5 + .../async-modules/pages/api/hello.js | 5 + test/integration/async-modules/pages/index.js | 10 ++ .../async-modules/test/index.test.js | 98 +++++++++++++++++++ yarn.lock | 41 +++++--- 10 files changed, 161 insertions(+), 18 deletions(-) create mode 100644 babel.config.json create mode 100644 test/integration/async-modules/next.config.js create mode 100644 test/integration/async-modules/pages/_app.js create mode 100644 test/integration/async-modules/pages/api/hello.js create mode 100644 test/integration/async-modules/pages/index.js create mode 100644 test/integration/async-modules/test/index.test.js diff --git a/.eslintrc.json b/.eslintrc.json index 2a93dc67859..46de2f43792 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,6 @@ { "root": true, - "parser": "babel-eslint", + "parser": "@babel/eslint-parser", "plugins": ["react", "react-hooks", "jest", "import"], "env": { "browser": true, @@ -9,7 +9,7 @@ "node": true }, "parserOptions": { - "ecmaVersion": 2018, + "ecmaVersion": 2021, "sourceType": "module", "ecmaFeatures": { "jsx": true diff --git a/.github/workflows/build_test_deploy.yml b/.github/workflows/build_test_deploy.yml index 02cacac1639..e4a10313c8c 100644 --- a/.github/workflows/build_test_deploy.yml +++ b/.github/workflows/build_test_deploy.yml @@ -113,6 +113,7 @@ jobs: - run: yarn install --check-files - run: node run-tests.js test/integration/production/test/index.test.js - run: node run-tests.js test/integration/basic/test/index.test.js + - run: node run-tests.js test/integration/async-modules/test/index.test.js - run: node run-tests.js test/acceptance/* testFirefox: diff --git a/babel.config.json b/babel.config.json new file mode 100644 index 00000000000..0841c408fbd --- /dev/null +++ b/babel.config.json @@ -0,0 +1,3 @@ +{ + "plugins": ["@babel/plugin-syntax-top-level-await"] +} diff --git a/package.json b/package.json index 9660e457a1c..5c90e9b9245 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,9 @@ }, "pre-commit": "lint-staged", "devDependencies": { + "@babel/eslint-parser": "7.11.5", "@babel/plugin-proposal-object-rest-spread": "7.11.0", + "@babel/plugin-syntax-top-level-await": "7.10.4", "@babel/preset-flow": "7.10.4", "@babel/preset-react": "7.10.4", "@fullhuman/postcss-purgecss": "1.3.0", @@ -56,7 +58,6 @@ "amphtml-validator": "1.0.33", "async-sema": "3.0.1", "babel-core": "7.0.0-bridge.0", - "babel-eslint": "10.0.3", "babel-jest": "24.9.0", "browserslist": "^4.13.0", "browserstack-local": "1.4.0", diff --git a/test/integration/async-modules/next.config.js b/test/integration/async-modules/next.config.js new file mode 100644 index 00000000000..012728c1eef --- /dev/null +++ b/test/integration/async-modules/next.config.js @@ -0,0 +1,9 @@ +module.exports = { + // target: 'experimental-serverless-trace', + webpack: (config, options) => { + config.experiments = { + topLevelAwait: true, + } + return config + }, +} diff --git a/test/integration/async-modules/pages/_app.js b/test/integration/async-modules/pages/_app.js new file mode 100644 index 00000000000..1c933d20435 --- /dev/null +++ b/test/integration/async-modules/pages/_app.js @@ -0,0 +1,5 @@ +const appValue = await Promise.resolve('hello') + +export default function MyApp({ Component, pageProps }) { + return +} diff --git a/test/integration/async-modules/pages/api/hello.js b/test/integration/async-modules/pages/api/hello.js new file mode 100644 index 00000000000..9fe171b1fc9 --- /dev/null +++ b/test/integration/async-modules/pages/api/hello.js @@ -0,0 +1,5 @@ +const value = await Promise.resolve(42) + +export default function (req, res) { + res.json({ value }) +} diff --git a/test/integration/async-modules/pages/index.js b/test/integration/async-modules/pages/index.js new file mode 100644 index 00000000000..df079ba0f31 --- /dev/null +++ b/test/integration/async-modules/pages/index.js @@ -0,0 +1,10 @@ +const value = await Promise.resolve(42) + +export default function Index({ appValue }) { + return ( +
+
{appValue}
+
{value}
+
+ ) +} diff --git a/test/integration/async-modules/test/index.test.js b/test/integration/async-modules/test/index.test.js new file mode 100644 index 00000000000..30645006119 --- /dev/null +++ b/test/integration/async-modules/test/index.test.js @@ -0,0 +1,98 @@ +/* eslint-env jest */ + +import webdriver from 'next-webdriver' + +import cheerio from 'cheerio' +import { + fetchViaHTTP, + renderViaHTTP, + findPort, + killApp, + launchApp, + nextBuild, + nextStart, + File, +} from 'next-test-utils' +import { join } from 'path' +import webpack from 'webpack' + +jest.setTimeout(1000 * 60 * 2) + +const isWebpack5 = parseInt(webpack.version) === 5 +let app +let appPort +const appDir = join(__dirname, '../') +const nextConfig = new File(join(appDir, 'next.config.js')) + +function runTests() { + it('ssr async page modules', async () => { + const html = await renderViaHTTP(appPort, '/') + const $ = cheerio.load(html) + expect($('#app-value').text()).toBe('hello') + expect($('#page-value').text()).toBe('42') + }) + + it('csr async page modules', async () => { + let browser + try { + browser = await webdriver(appPort, '/') + expect(await browser.elementByCss('#app-value').text()).toBe('hello') + expect(await browser.elementByCss('#page-value').text()).toBe('42') + } finally { + if (browser) await browser.close() + } + }) + + it('works on api routes', async () => { + const res = await fetchViaHTTP(appPort, '/api/hello') + expect(res.status).toBe(200) + const result = await res.json() + expect(result).toHaveProperty('value', 42) + }) +} + +describe('Async modules', () => { + if (!isWebpack5) { + return + } + + describe('dev mode', () => { + beforeAll(async () => { + appPort = await findPort() + app = await launchApp(appDir, appPort) + }) + afterAll(async () => { + await killApp(app) + }) + + runTests() + }) + + describe('production mode', () => { + beforeAll(async () => { + await nextBuild(appDir) + appPort = await findPort() + app = await nextStart(appDir, appPort) + }) + afterAll(async () => { + await killApp(app) + }) + + runTests() + }) + + describe.skip('serverless mode', () => { + beforeAll(async () => { + nextConfig.replace(`// target:`, 'target:') + await nextBuild(appDir) + appPort = await findPort() + app = await nextStart(appDir, appPort) + }) + afterAll(async () => { + await nextConfig.restore() + await killApp(app) + }) + + runTests() + }) +}) diff --git a/yarn.lock b/yarn.lock index 30c492a6a51..e984f6b7ad6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -157,6 +157,15 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/eslint-parser@7.11.5": + version "7.11.5" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.11.5.tgz#398192b8d1cd3678efb709f5ab09d9aa2a2218fd" + integrity sha512-DZ3maD3ciwRg1pOzEpJ1outlV1DA/A8XHDQoyL69fC3RIJMlMq1UPudgfRkW0YFqmQPR6OPvu8chaT7Yq2Mm8A== + dependencies: + eslint-scope "5.1.0" + eslint-visitor-keys "^1.3.0" + semver "^6.3.0" + "@babel/generator@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.0.tgz#4b90c78d8c12825024568cbe83ee6c9af193585c" @@ -570,7 +579,7 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.8.3": +"@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.3.tgz#790874091d2001c9be6ec426c2eed47bc7679081" @@ -829,7 +838,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.10.4": +"@babel/plugin-syntax-top-level-await@7.10.4", "@babel/plugin-syntax-top-level-await@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz#4bbeb8917b54fcf768364e0a81f560e33a3ef57d" integrity sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ== @@ -1453,7 +1462,7 @@ "@babel/parser" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.8.3": +"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.3.tgz#a826215b011c9b4f73f3a893afbc05151358bf9a" dependencies: @@ -4192,17 +4201,6 @@ babel-core@7.0.0-bridge.0, babel-core@^7.0.0-bridge.0: version "7.0.0-bridge.0" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" -babel-eslint@10.0.3: - version "10.0.3" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a" - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.0.0" - "@babel/traverse" "^7.0.0" - "@babel/types" "^7.0.0" - eslint-visitor-keys "^1.0.0" - resolve "^1.12.0" - babel-jest@24.9.0, babel-jest@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.9.0.tgz#3fc327cb8467b89d14d7bc70e315104a783ccd54" @@ -6934,6 +6932,14 @@ eslint-plugin-react@7.18.0: prop-types "^15.7.2" resolve "^1.14.2" +eslint-scope@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" + integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" @@ -6961,10 +6967,15 @@ eslint-utils@^2.0.0: dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: +eslint-visitor-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" +eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + eslint@6.8.0: version "6.8.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" From 507923a5cd19d3bed1ed781ff0f8201d46b13720 Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Sun, 11 Oct 2020 16:12:50 +0200 Subject: [PATCH 04/16] skip when not webpack 5 --- test/integration/async-modules/test/index.test.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/integration/async-modules/test/index.test.js b/test/integration/async-modules/test/index.test.js index 30645006119..bdb2c7f20e2 100644 --- a/test/integration/async-modules/test/index.test.js +++ b/test/integration/async-modules/test/index.test.js @@ -43,7 +43,7 @@ function runTests() { } }) - it('works on api routes', async () => { + it('works on async api routes', async () => { const res = await fetchViaHTTP(appPort, '/api/hello') expect(res.status).toBe(200) const result = await res.json() @@ -51,11 +51,7 @@ function runTests() { }) } -describe('Async modules', () => { - if (!isWebpack5) { - return - } - +;(isWebpack5 ? describe : describe.skip)('Async modules', () => { describe('dev mode', () => { beforeAll(async () => { appPort = await findPort() @@ -83,7 +79,7 @@ describe('Async modules', () => { describe.skip('serverless mode', () => { beforeAll(async () => { - nextConfig.replace(`// target:`, 'target:') + nextConfig.replace('// target:', 'target:') await nextBuild(appDir) appPort = await findPort() app = await nextStart(appDir, appPort) From 22047896d7e36a8ba768668b18e8298588924cf0 Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Sun, 11 Oct 2020 16:45:34 +0200 Subject: [PATCH 05/16] fix for serverless --- .../webpack/loaders/next-serverless-loader.ts | 18 ++++++++++++------ .../async-modules/test/index.test.js | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/next/build/webpack/loaders/next-serverless-loader.ts b/packages/next/build/webpack/loaders/next-serverless-loader.ts index 82e3db7c7d2..7db19b045f9 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader.ts @@ -257,7 +257,7 @@ const nextServerlessLoader: loader.Loader = function () { : `{}` } - const resolver = require('${absolutePagePath}') + const { default: resolver } = await require('${absolutePagePath}') await apiResolver( req, res, @@ -303,16 +303,22 @@ const nextServerlessLoader: loader.Loader = function () { const {sendPayload} = require('next/dist/next-server/server/send-payload'); const buildManifest = require('${buildManifest}'); const reactLoadableManifest = require('${reactLoadableManifest}'); - const Document = require('${absoluteDocumentPath}').default; - const Error = require('${absoluteErrorPath}').default; - const App = require('${absoluteAppPath}').default; ${dynamicRouteImports} ${rewriteImports} - const ComponentInfo = require('${absolutePagePath}') + const [ + { default: App }, + { default: Document }, + { default: Error }, + { default: Component, ...ComponentInfo } + ] = await Promise.all([ + require('${absoluteAppPath}'), + require('${absoluteDocumentPath}'), + require('${absoluteErrorPath}'), + require('${absolutePagePath}'), + ]) - const Component = ComponentInfo.default export default Component export const unstable_getStaticParams = ComponentInfo['unstable_getStaticParam' + 's'] export const getStaticProps = ComponentInfo['getStaticProp' + 's'] diff --git a/test/integration/async-modules/test/index.test.js b/test/integration/async-modules/test/index.test.js index bdb2c7f20e2..4d1d9a463dd 100644 --- a/test/integration/async-modules/test/index.test.js +++ b/test/integration/async-modules/test/index.test.js @@ -77,7 +77,7 @@ function runTests() { runTests() }) - describe.skip('serverless mode', () => { + describe('serverless mode', () => { beforeAll(async () => { nextConfig.replace('// target:', 'target:') await nextBuild(appDir) From ad733a4543fe01e82bd4871b3bbe8ffa6908be2e Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Mon, 12 Oct 2020 05:16:08 +0200 Subject: [PATCH 06/16] this is not the way --- .../webpack/loaders/next-serverless-loader.ts | 16 +++++----------- .../integration/async-modules/test/index.test.js | 2 +- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/next/build/webpack/loaders/next-serverless-loader.ts b/packages/next/build/webpack/loaders/next-serverless-loader.ts index 7db19b045f9..f99a0cbcb19 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader.ts @@ -303,22 +303,16 @@ const nextServerlessLoader: loader.Loader = function () { const {sendPayload} = require('next/dist/next-server/server/send-payload'); const buildManifest = require('${buildManifest}'); const reactLoadableManifest = require('${reactLoadableManifest}'); + const Document = require('${absoluteDocumentPath}').default; + const Error = require('${absoluteErrorPath}').default; + const App = require('${absoluteAppPath}').default; ${dynamicRouteImports} ${rewriteImports} - const [ - { default: App }, - { default: Document }, - { default: Error }, - { default: Component, ...ComponentInfo } - ] = await Promise.all([ - require('${absoluteAppPath}'), - require('${absoluteDocumentPath}'), - require('${absoluteErrorPath}'), - require('${absolutePagePath}'), - ]) + const ComponentInfo = require('${absolutePagePath}') + const Component = ComponentInfo.default export default Component export const unstable_getStaticParams = ComponentInfo['unstable_getStaticParam' + 's'] export const getStaticProps = ComponentInfo['getStaticProp' + 's'] diff --git a/test/integration/async-modules/test/index.test.js b/test/integration/async-modules/test/index.test.js index 4d1d9a463dd..bdb2c7f20e2 100644 --- a/test/integration/async-modules/test/index.test.js +++ b/test/integration/async-modules/test/index.test.js @@ -77,7 +77,7 @@ function runTests() { runTests() }) - describe('serverless mode', () => { + describe.skip('serverless mode', () => { beforeAll(async () => { nextConfig.replace('// target:', 'target:') await nextBuild(appDir) From 77cda0c9d3bc24a5a2f94731fcabfe3f7b03b115 Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Mon, 12 Oct 2020 06:27:37 +0200 Subject: [PATCH 07/16] this is the correct one --- packages/next/build/webpack/loaders/next-serverless-loader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/build/webpack/loaders/next-serverless-loader.ts b/packages/next/build/webpack/loaders/next-serverless-loader.ts index a5f764d478e..89e8942f49f 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader.ts @@ -339,7 +339,7 @@ const nextServerlessLoader: loader.Loader = function () { : `{}` } - const { default: resolver } = await require('${absolutePagePath}') + const resolver = await require('${absolutePagePath}') await apiResolver( req, res, From ffe2e5dce41b81846a9db90eb0a483aede929f12 Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Mon, 12 Oct 2020 07:21:52 +0200 Subject: [PATCH 08/16] serverless support --- packages/next/build/index.ts | 2 +- packages/next/build/utils.ts | 9 +++++---- .../build/webpack/loaders/next-serverless-loader.ts | 10 ++++++---- test/integration/async-modules/test/index.test.js | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index 1ddb4f3d3c9..0633784c85e 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -531,7 +531,7 @@ export default async function build( const serverBundle = getPagePath(page, distDir, isLikeServerless) if (customAppGetInitialProps === undefined) { - customAppGetInitialProps = hasCustomGetInitialProps( + customAppGetInitialProps = await hasCustomGetInitialProps( isLikeServerless ? serverBundle : getPagePath('/_app', distDir, isLikeServerless), diff --git a/packages/next/build/utils.ts b/packages/next/build/utils.ts index 3b87d9b0a86..2842ba0cb40 100644 --- a/packages/next/build/utils.ts +++ b/packages/next/build/utils.ts @@ -705,7 +705,7 @@ export async function isPageStatic( try { require('../next-server/lib/runtime-config').setConfig(runtimeEnvConfig) const mod = await require(serverBundle) - const Comp = mod.default || mod + const Comp = await (mod.default || mod) if (!Comp || !isValidElementType(Comp) || typeof Comp === 'string') { throw new Error('INVALID_DEFAULT_EXPORT') @@ -804,19 +804,20 @@ export async function isPageStatic( } } -export function hasCustomGetInitialProps( +export async function hasCustomGetInitialProps( bundle: string, runtimeEnvConfig: any, checkingApp: boolean -): boolean { +): Promise { require('../next-server/lib/runtime-config').setConfig(runtimeEnvConfig) let mod = require(bundle) if (checkingApp) { - mod = mod._app || mod.default || mod + mod = (await mod._app) || mod.default || mod } else { mod = mod.default || mod } + mod = await mod return mod.getInitialProps !== mod.origGetInitialProps } diff --git a/packages/next/build/webpack/loaders/next-serverless-loader.ts b/packages/next/build/webpack/loaders/next-serverless-loader.ts index 89e8942f49f..13709ef4f36 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader.ts @@ -388,14 +388,16 @@ const nextServerlessLoader: loader.Loader = function () { const reactLoadableManifest = require('${reactLoadableManifest}'); const Document = require('${absoluteDocumentPath}').default; const Error = require('${absoluteErrorPath}').default; - const App = require('${absoluteAppPath}').default; + + const appMod = require('${absoluteAppPath}') + const App = appMod.default || appMod.then(mod => mod.default); ${dynamicRouteImports} ${rewriteImports} const ComponentInfo = require('${absolutePagePath}') - const Component = ComponentInfo.default + const Component = ComponentInfo.default || ComponentInfo.then(mod => mod.default) export default Component export const unstable_getStaticParams = ComponentInfo['unstable_getStaticParam' + 's'] export const getStaticProps = ComponentInfo['getStaticProp' + 's'] @@ -421,7 +423,7 @@ const nextServerlessLoader: loader.Loader = function () { setLazyProp({ req }, 'cookies', getCookieParser(req)) const options = { - App, + App: await App, Document, buildManifest, getStaticProps, @@ -473,7 +475,7 @@ const nextServerlessLoader: loader.Loader = function () { const renderOpts = Object.assign( { - Component, + Component: await Component, pageConfig: config, nextExport: fromExport, isDataReq: _nextData, diff --git a/test/integration/async-modules/test/index.test.js b/test/integration/async-modules/test/index.test.js index bdb2c7f20e2..4d1d9a463dd 100644 --- a/test/integration/async-modules/test/index.test.js +++ b/test/integration/async-modules/test/index.test.js @@ -77,7 +77,7 @@ function runTests() { runTests() }) - describe.skip('serverless mode', () => { + describe('serverless mode', () => { beforeAll(async () => { nextConfig.replace('// target:', 'target:') await nextBuild(appDir) From 2923ac17bab81703a19e4dbeab7d135079161f3b Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Mon, 12 Oct 2020 08:18:36 +0200 Subject: [PATCH 09/16] fix test --- packages/next/build/webpack/loaders/next-serverless-loader.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next/build/webpack/loaders/next-serverless-loader.ts b/packages/next/build/webpack/loaders/next-serverless-loader.ts index 13709ef4f36..4030ec01984 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader.ts @@ -390,14 +390,14 @@ const nextServerlessLoader: loader.Loader = function () { const Error = require('${absoluteErrorPath}').default; const appMod = require('${absoluteAppPath}') - const App = appMod.default || appMod.then(mod => mod.default); + const App = appMod.default || appMod.then && appMod.then(mod => mod.default); ${dynamicRouteImports} ${rewriteImports} const ComponentInfo = require('${absolutePagePath}') - const Component = ComponentInfo.default || ComponentInfo.then(mod => mod.default) + const Component = ComponentInfo.default || ComponentInfo.then && ComponentInfo.then(mod => mod.default) export default Component export const unstable_getStaticParams = ComponentInfo['unstable_getStaticParam' + 's'] export const getStaticProps = ComponentInfo['getStaticProp' + 's'] From 28585705d6a4d924b1bcecfd01cb1ead59e1d14e Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Mon, 12 Oct 2020 10:53:53 +0200 Subject: [PATCH 10/16] await everywhere --- packages/next/build/utils.ts | 14 +++++----- .../webpack/loaders/next-serverless-loader.ts | 28 +++++++++++-------- .../next-server/server/load-components.ts | 6 +++- test/integration/async-modules/pages/gsp.js | 15 ++++++++++ test/integration/async-modules/pages/gssp.js | 15 ++++++++++ .../async-modules/test/index.test.js | 20 +++++++++++++ 6 files changed, 79 insertions(+), 19 deletions(-) create mode 100644 test/integration/async-modules/pages/gsp.js create mode 100644 test/integration/async-modules/pages/gssp.js diff --git a/packages/next/build/utils.ts b/packages/next/build/utils.ts index 2842ba0cb40..7e1eb11cc53 100644 --- a/packages/next/build/utils.ts +++ b/packages/next/build/utils.ts @@ -712,13 +712,13 @@ export async function isPageStatic( } const hasGetInitialProps = !!(Comp as any).getInitialProps - const hasStaticProps = !!mod.getStaticProps - const hasStaticPaths = !!mod.getStaticPaths - const hasServerProps = !!mod.getServerSideProps - const hasLegacyServerProps = !!mod.unstable_getServerProps - const hasLegacyStaticProps = !!mod.unstable_getStaticProps - const hasLegacyStaticPaths = !!mod.unstable_getStaticPaths - const hasLegacyStaticParams = !!mod.unstable_getStaticParams + const hasStaticProps = !!(await mod.getStaticProps) + const hasStaticPaths = !!(await mod.getStaticPaths) + const hasServerProps = !!(await mod.getServerSideProps) + const hasLegacyServerProps = !!(await mod.unstable_getServerProps) + const hasLegacyStaticProps = !!(await mod.unstable_getStaticProps) + const hasLegacyStaticPaths = !!(await mod.unstable_getStaticPaths) + const hasLegacyStaticParams = !!(await mod.unstable_getStaticParams) if (hasLegacyStaticParams) { throw new Error( diff --git a/packages/next/build/webpack/loaders/next-serverless-loader.ts b/packages/next/build/webpack/loaders/next-serverless-loader.ts index 4030ec01984..a9ffc97421e 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader.ts @@ -390,33 +390,39 @@ const nextServerlessLoader: loader.Loader = function () { const Error = require('${absoluteErrorPath}').default; const appMod = require('${absoluteAppPath}') - const App = appMod.default || appMod.then && appMod.then(mod => mod.default); + let App = appMod.default || appMod.then && appMod.then(mod => mod.default); ${dynamicRouteImports} ${rewriteImports} - const ComponentInfo = require('${absolutePagePath}') + const compMod = require('${absolutePagePath}') - const Component = ComponentInfo.default || ComponentInfo.then && ComponentInfo.then(mod => mod.default) + let Component = compMod.default || compMod.then && compMod.then(mod => mod.default) export default Component - export const unstable_getStaticParams = ComponentInfo['unstable_getStaticParam' + 's'] - export const getStaticProps = ComponentInfo['getStaticProp' + 's'] - export const getStaticPaths = ComponentInfo['getStaticPath' + 's'] - export const getServerSideProps = ComponentInfo['getServerSideProp' + 's'] + export let getStaticProps = compMod['getStaticProp' + 's'] || compMod.then && compMod.then(mod => mod['getStaticProp' + 's']) + export let getStaticPaths = compMod['getStaticPath' + 's'] || compMod.then && compMod.then(mod => mod['getStaticPath' + 's']) + export let getServerSideProps = compMod['getServerSideProp' + 's'] || compMod.then && compMod.then(mod => mod['getServerSideProp' + 's']) // kept for detecting legacy exports - export const unstable_getStaticProps = ComponentInfo['unstable_getStaticProp' + 's'] - export const unstable_getStaticPaths = ComponentInfo['unstable_getStaticPath' + 's'] - export const unstable_getServerProps = ComponentInfo['unstable_getServerProp' + 's'] + export const unstable_getStaticParams = compMod['unstable_getStaticParam' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getStaticParam' + 's']) + export const unstable_getStaticProps = compMod['unstable_getStaticProp' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getStaticProp' + 's']) + export const unstable_getStaticPaths = compMod['unstable_getStaticPath' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getStaticPath' + 's']) + export const unstable_getServerProps = compMod['unstable_getServerProp' + 's'] || compMod.then && compMod.then(mod => mod['unstable_getServerProp' + 's']) ${dynamicRouteMatcher} ${defaultRouteRegex} ${normalizeDynamicRouteParams} ${handleRewrites} - export const config = ComponentInfo['confi' + 'g'] || {} + export const config = compMod['confi' + 'g'] || (compMod.then && compMod.then(mod => mod['confi' + 'g'])) || {} export const _app = App export async function renderReqToHTML(req, res, renderMode, _renderOpts, _params) { + getStaticProps = await getStaticProps + getServerSideProps = await getServerSideProps + getStaticPaths = await getStaticPaths + Component = await Component + App = await App + const fromExport = renderMode === 'export' || renderMode === true; const nextStartMode = renderMode === 'passthrough' diff --git a/packages/next/next-server/server/load-components.ts b/packages/next/next-server/server/load-components.ts index 683864bf431..85a51e236fb 100644 --- a/packages/next/next-server/server/load-components.ts +++ b/packages/next/next-server/server/load-components.ts @@ -41,7 +41,11 @@ export async function loadComponents( ): Promise { if (serverless) { const Component = await requirePage(pathname, distDir, serverless) - const { getStaticProps, getStaticPaths, getServerSideProps } = Component + let { getStaticProps, getStaticPaths, getServerSideProps } = Component + + getStaticProps = await getStaticProps + getStaticPaths = await getStaticPaths + getServerSideProps = await getServerSideProps return { Component, diff --git a/test/integration/async-modules/pages/gsp.js b/test/integration/async-modules/pages/gsp.js new file mode 100644 index 00000000000..072f2cfafef --- /dev/null +++ b/test/integration/async-modules/pages/gsp.js @@ -0,0 +1,15 @@ +const gspValue = await Promise.resolve(42) + +export async function getStaticProps() { + return { + props: { gspValue }, + } +} + +export default function Index({ gspValue }) { + return ( +
+
{gspValue}
+
+ ) +} diff --git a/test/integration/async-modules/pages/gssp.js b/test/integration/async-modules/pages/gssp.js new file mode 100644 index 00000000000..33775bf3a94 --- /dev/null +++ b/test/integration/async-modules/pages/gssp.js @@ -0,0 +1,15 @@ +const gsspValue = await Promise.resolve(42) + +export async function getServerSideProps() { + return { + props: { gsspValue }, + } +} + +export default function Index({ gsspValue }) { + return ( +
+
{gsspValue}
+
+ ) +} diff --git a/test/integration/async-modules/test/index.test.js b/test/integration/async-modules/test/index.test.js index 4d1d9a463dd..a0451072d01 100644 --- a/test/integration/async-modules/test/index.test.js +++ b/test/integration/async-modules/test/index.test.js @@ -49,6 +49,26 @@ function runTests() { const result = await res.json() expect(result).toHaveProperty('value', 42) }) + + it('works with getServerSideProps', async () => { + let browser + try { + browser = await webdriver(appPort, '/gssp') + expect(await browser.elementByCss('#gssp-value').text()).toBe('42') + } finally { + if (browser) await browser.close() + } + }) + + it('works with getStaticProps', async () => { + let browser + try { + browser = await webdriver(appPort, '/gsp') + expect(await browser.elementByCss('#gsp-value').text()).toBe('42') + } finally { + if (browser) await browser.close() + } + }) } ;(isWebpack5 ? describe : describe.skip)('Async modules', () => { From 7b495671f8ed2f97aa06a2c8ccb7714de96fc082 Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Mon, 12 Oct 2020 12:41:48 +0200 Subject: [PATCH 11/16] ok, let's disable eslint for now --- .eslintignore | 3 +- .eslintrc.json | 4 +- package.json | 3 +- .../integration/async-modules/.babelrc | 1 + yarn.lock | 41 +++++++------------ 5 files changed, 21 insertions(+), 31 deletions(-) rename babel.config.json => test/integration/async-modules/.babelrc (61%) diff --git a/.eslintignore b/.eslintignore index e58e7db214a..48f9e69a570 100644 --- a/.eslintignore +++ b/.eslintignore @@ -13,4 +13,5 @@ packages/next-codemod/transforms/__testfixtures__/**/* packages/next-codemod/transforms/__tests__/**/* packages/next-codemod/**/*.js packages/next-codemod/**/*.d.ts -packages/next-env/**/*.d.ts \ No newline at end of file +packages/next-env/**/*.d.ts +test/integration/async-modules/** diff --git a/.eslintrc.json b/.eslintrc.json index 46de2f43792..2a93dc67859 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,6 +1,6 @@ { "root": true, - "parser": "@babel/eslint-parser", + "parser": "babel-eslint", "plugins": ["react", "react-hooks", "jest", "import"], "env": { "browser": true, @@ -9,7 +9,7 @@ "node": true }, "parserOptions": { - "ecmaVersion": 2021, + "ecmaVersion": 2018, "sourceType": "module", "ecmaFeatures": { "jsx": true diff --git a/package.json b/package.json index 5c90e9b9245..9660e457a1c 100644 --- a/package.json +++ b/package.json @@ -37,9 +37,7 @@ }, "pre-commit": "lint-staged", "devDependencies": { - "@babel/eslint-parser": "7.11.5", "@babel/plugin-proposal-object-rest-spread": "7.11.0", - "@babel/plugin-syntax-top-level-await": "7.10.4", "@babel/preset-flow": "7.10.4", "@babel/preset-react": "7.10.4", "@fullhuman/postcss-purgecss": "1.3.0", @@ -58,6 +56,7 @@ "amphtml-validator": "1.0.33", "async-sema": "3.0.1", "babel-core": "7.0.0-bridge.0", + "babel-eslint": "10.0.3", "babel-jest": "24.9.0", "browserslist": "^4.13.0", "browserstack-local": "1.4.0", diff --git a/babel.config.json b/test/integration/async-modules/.babelrc similarity index 61% rename from babel.config.json rename to test/integration/async-modules/.babelrc index 0841c408fbd..3f6984a12dd 100644 --- a/babel.config.json +++ b/test/integration/async-modules/.babelrc @@ -1,3 +1,4 @@ { + "allowAwaitOutsideFunction": true, "plugins": ["@babel/plugin-syntax-top-level-await"] } diff --git a/yarn.lock b/yarn.lock index 8b4e882b368..2ac55160d99 100644 --- a/yarn.lock +++ b/yarn.lock @@ -157,15 +157,6 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/eslint-parser@7.11.5": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.11.5.tgz#398192b8d1cd3678efb709f5ab09d9aa2a2218fd" - integrity sha512-DZ3maD3ciwRg1pOzEpJ1outlV1DA/A8XHDQoyL69fC3RIJMlMq1UPudgfRkW0YFqmQPR6OPvu8chaT7Yq2Mm8A== - dependencies: - eslint-scope "5.1.0" - eslint-visitor-keys "^1.3.0" - semver "^6.3.0" - "@babel/generator@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.0.tgz#4b90c78d8c12825024568cbe83ee6c9af193585c" @@ -579,7 +570,7 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.8.3": +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.3.tgz#790874091d2001c9be6ec426c2eed47bc7679081" @@ -838,7 +829,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@7.10.4", "@babel/plugin-syntax-top-level-await@^7.10.4": +"@babel/plugin-syntax-top-level-await@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz#4bbeb8917b54fcf768364e0a81f560e33a3ef57d" integrity sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ== @@ -1462,7 +1453,7 @@ "@babel/parser" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.8.3": +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.3.tgz#a826215b011c9b4f73f3a893afbc05151358bf9a" dependencies: @@ -4221,6 +4212,17 @@ babel-core@7.0.0-bridge.0, babel-core@^7.0.0-bridge.0: version "7.0.0-bridge.0" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" +babel-eslint@10.0.3: + version "10.0.3" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a" + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + eslint-visitor-keys "^1.0.0" + resolve "^1.12.0" + babel-jest@24.9.0, babel-jest@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.9.0.tgz#3fc327cb8467b89d14d7bc70e315104a783ccd54" @@ -6952,14 +6954,6 @@ eslint-plugin-react@7.18.0: prop-types "^15.7.2" resolve "^1.14.2" -eslint-scope@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" - integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" @@ -6987,15 +6981,10 @@ eslint-utils@^2.0.0: dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.1.0: +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" -eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - eslint@6.8.0: version "6.8.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" From 8580c9aede25cefcd2c4a397a9800d16d4246e85 Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Mon, 12 Oct 2020 12:52:28 +0200 Subject: [PATCH 12/16] remove this as well --- test/integration/async-modules/.babelrc | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 test/integration/async-modules/.babelrc diff --git a/test/integration/async-modules/.babelrc b/test/integration/async-modules/.babelrc deleted file mode 100644 index 3f6984a12dd..00000000000 --- a/test/integration/async-modules/.babelrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "allowAwaitOutsideFunction": true, - "plugins": ["@babel/plugin-syntax-top-level-await"] -} From a0816a64e02d5501aea4956fac6a6b40e0150c5f Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Mon, 12 Oct 2020 13:14:03 +0200 Subject: [PATCH 13/16] this not needed anymore --- packages/next/build/webpack/loaders/next-serverless-loader.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next/build/webpack/loaders/next-serverless-loader.ts b/packages/next/build/webpack/loaders/next-serverless-loader.ts index a9ffc97421e..f2794644c11 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader.ts @@ -429,7 +429,7 @@ const nextServerlessLoader: loader.Loader = function () { setLazyProp({ req }, 'cookies', getCookieParser(req)) const options = { - App: await App, + App, Document, buildManifest, getStaticProps, @@ -481,7 +481,7 @@ const nextServerlessLoader: loader.Loader = function () { const renderOpts = Object.assign( { - Component: await Component, + Component, pageConfig: config, nextExport: fromExport, isDataReq: _nextData, From 3077f5afc586f48afc8422b1c3392e7a8fa5d50d Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Mon, 12 Oct 2020 14:02:10 +0200 Subject: [PATCH 14/16] 404 pages --- .../webpack/loaders/next-serverless-loader.ts | 4 +-- test/integration/async-modules/pages/404.jsx | 5 ++++ .../async-modules/pages/{_app.js => _app.jsx} | 0 .../async-modules/pages/_document.jsx | 25 +++++++++++++++++++ .../async-modules/pages/{gsp.js => gsp.jsx} | 0 .../async-modules/pages/{gssp.js => gssp.jsx} | 0 .../pages/{index.js => index.jsx} | 0 .../async-modules/test/index.test.js | 11 ++++++++ 8 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 test/integration/async-modules/pages/404.jsx rename test/integration/async-modules/pages/{_app.js => _app.jsx} (100%) create mode 100644 test/integration/async-modules/pages/_document.jsx rename test/integration/async-modules/pages/{gsp.js => gsp.jsx} (100%) rename test/integration/async-modules/pages/{gssp.js => gssp.jsx} (100%) rename test/integration/async-modules/pages/{index.js => index.jsx} (100%) diff --git a/packages/next/build/webpack/loaders/next-serverless-loader.ts b/packages/next/build/webpack/loaders/next-serverless-loader.ts index f2794644c11..3b18752c8fa 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader.ts @@ -386,8 +386,6 @@ const nextServerlessLoader: loader.Loader = function () { const {sendPayload} = require('next/dist/next-server/server/send-payload'); const buildManifest = require('${buildManifest}'); const reactLoadableManifest = require('${reactLoadableManifest}'); - const Document = require('${absoluteDocumentPath}').default; - const Error = require('${absoluteErrorPath}').default; const appMod = require('${absoluteAppPath}') let App = appMod.default || appMod.then && appMod.then(mod => mod.default); @@ -422,6 +420,8 @@ const nextServerlessLoader: loader.Loader = function () { getStaticPaths = await getStaticPaths Component = await Component App = await App + const { default: Document } = await require('${absoluteDocumentPath}'); + const { default: Error } = await require('${absoluteErrorPath}'); const fromExport = renderMode === 'export' || renderMode === true; const nextStartMode = renderMode === 'passthrough' diff --git a/test/integration/async-modules/pages/404.jsx b/test/integration/async-modules/pages/404.jsx new file mode 100644 index 00000000000..42176bf46e5 --- /dev/null +++ b/test/integration/async-modules/pages/404.jsx @@ -0,0 +1,5 @@ +const content = await Promise.resolve("hi y'all") + +export default function Custom404() { + return

{content}

+} diff --git a/test/integration/async-modules/pages/_app.js b/test/integration/async-modules/pages/_app.jsx similarity index 100% rename from test/integration/async-modules/pages/_app.js rename to test/integration/async-modules/pages/_app.jsx diff --git a/test/integration/async-modules/pages/_document.jsx b/test/integration/async-modules/pages/_document.jsx new file mode 100644 index 00000000000..fa5ac2ac1a6 --- /dev/null +++ b/test/integration/async-modules/pages/_document.jsx @@ -0,0 +1,25 @@ +import Document, { Html, Head, Main, NextScript } from 'next/document' + +const docValue = await Promise.resolve('doc value') + +class MyDocument extends Document { + static async getInitialProps(ctx) { + const initialProps = await Document.getInitialProps(ctx) + return { ...initialProps, docValue } + } + + render() { + return ( + + + +
{this.props.docValue}
+
+ + + + ) + } +} + +export default MyDocument diff --git a/test/integration/async-modules/pages/gsp.js b/test/integration/async-modules/pages/gsp.jsx similarity index 100% rename from test/integration/async-modules/pages/gsp.js rename to test/integration/async-modules/pages/gsp.jsx diff --git a/test/integration/async-modules/pages/gssp.js b/test/integration/async-modules/pages/gssp.jsx similarity index 100% rename from test/integration/async-modules/pages/gssp.js rename to test/integration/async-modules/pages/gssp.jsx diff --git a/test/integration/async-modules/pages/index.js b/test/integration/async-modules/pages/index.jsx similarity index 100% rename from test/integration/async-modules/pages/index.js rename to test/integration/async-modules/pages/index.jsx diff --git a/test/integration/async-modules/test/index.test.js b/test/integration/async-modules/test/index.test.js index a0451072d01..1b44992b088 100644 --- a/test/integration/async-modules/test/index.test.js +++ b/test/integration/async-modules/test/index.test.js @@ -38,6 +38,7 @@ function runTests() { browser = await webdriver(appPort, '/') expect(await browser.elementByCss('#app-value').text()).toBe('hello') expect(await browser.elementByCss('#page-value').text()).toBe('42') + expect(await browser.elementByCss('#doc-value').text()).toBe('doc value') } finally { if (browser) await browser.close() } @@ -69,6 +70,16 @@ function runTests() { if (browser) await browser.close() } }) + + it('can render async 404 pages', async () => { + let browser + try { + browser = await webdriver(appPort, '/dhiuhefoiahjeoij') + expect(await browser.elementByCss('#content-404').text()).toBe("hi y'all") + } finally { + if (browser) await browser.close() + } + }) } ;(isWebpack5 ? describe : describe.skip)('Async modules', () => { From 6446ee4305b44cb20eef6df4e4241d7308307900 Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Mon, 12 Oct 2020 14:41:36 +0200 Subject: [PATCH 15/16] optimize + error page test --- .../webpack/loaders/next-serverless-loader.ts | 26 ++++++++++++++----- .../async-modules/pages/_error.jsx | 7 +++++ .../async-modules/pages/make-error.jsx | 7 +++++ .../async-modules/test/index.test.js | 15 +++++++++-- 4 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 test/integration/async-modules/pages/_error.jsx create mode 100644 test/integration/async-modules/pages/make-error.jsx diff --git a/packages/next/build/webpack/loaders/next-serverless-loader.ts b/packages/next/build/webpack/loaders/next-serverless-loader.ts index 3b18752c8fa..3c89a525107 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader.ts @@ -415,13 +415,25 @@ const nextServerlessLoader: loader.Loader = function () { export const config = compMod['confi' + 'g'] || (compMod.then && compMod.then(mod => mod['confi' + 'g'])) || {} export const _app = App export async function renderReqToHTML(req, res, renderMode, _renderOpts, _params) { - getStaticProps = await getStaticProps - getServerSideProps = await getServerSideProps - getStaticPaths = await getStaticPaths - Component = await Component - App = await App - const { default: Document } = await require('${absoluteDocumentPath}'); - const { default: Error } = await require('${absoluteErrorPath}'); + let Document + let Error + ;[ + getStaticProps, + getServerSideProps, + getStaticPaths, + Component, + App, + { default: Document }, + { default: Error } + ] = await Promise.all([ + getStaticProps, + getServerSideProps, + getStaticPaths, + Component, + App, + require('${absoluteDocumentPath}'), + require('${absoluteErrorPath}') + ]) const fromExport = renderMode === 'export' || renderMode === true; const nextStartMode = renderMode === 'passthrough' diff --git a/test/integration/async-modules/pages/_error.jsx b/test/integration/async-modules/pages/_error.jsx new file mode 100644 index 00000000000..521df7a7bd8 --- /dev/null +++ b/test/integration/async-modules/pages/_error.jsx @@ -0,0 +1,7 @@ +const errorContent = await Promise.resolve('hello error') + +function Error({ statusCode }) { + return

{errorContent}

+} + +export default Error diff --git a/test/integration/async-modules/pages/make-error.jsx b/test/integration/async-modules/pages/make-error.jsx new file mode 100644 index 00000000000..bd44466d288 --- /dev/null +++ b/test/integration/async-modules/pages/make-error.jsx @@ -0,0 +1,7 @@ +export async function getServerSideProps() { + throw new Error('BOOM') +} + +export default function Page() { + return
hello
+} diff --git a/test/integration/async-modules/test/index.test.js b/test/integration/async-modules/test/index.test.js index 1b44992b088..f4f77654a2c 100644 --- a/test/integration/async-modules/test/index.test.js +++ b/test/integration/async-modules/test/index.test.js @@ -24,7 +24,7 @@ let appPort const appDir = join(__dirname, '../') const nextConfig = new File(join(appDir, 'next.config.js')) -function runTests() { +function runTests(dev = false) { it('ssr async page modules', async () => { const html = await renderViaHTTP(appPort, '/') const $ = cheerio.load(html) @@ -80,6 +80,17 @@ function runTests() { if (browser) await browser.close() } }) + ;(dev ? it.skip : it)('can render async error page', async () => { + let browser + try { + browser = await webdriver(appPort, '/make-error') + expect(await browser.elementByCss('#content-error').text()).toBe( + 'hello error' + ) + } finally { + if (browser) await browser.close() + } + }) } ;(isWebpack5 ? describe : describe.skip)('Async modules', () => { @@ -92,7 +103,7 @@ function runTests() { await killApp(app) }) - runTests() + runTests(true) }) describe('production mode', () => { From f8615a9c827e7571812b2b98e6c0aea548eb30eb Mon Sep 17 00:00:00 2001 From: Jan Potoms <2109932+Janpot@users.noreply.github.com> Date: Mon, 12 Oct 2020 16:46:24 +0200 Subject: [PATCH 16/16] Missed AMP support --- .../webpack/loaders/next-serverless-loader.ts | 4 +++- .../next-server/server/load-components.ts | 3 ++- .../async-modules/pages/config.jsx | 22 +++++++++++++++++++ .../async-modules/test/index.test.js | 10 +++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 test/integration/async-modules/pages/config.jsx diff --git a/packages/next/build/webpack/loaders/next-serverless-loader.ts b/packages/next/build/webpack/loaders/next-serverless-loader.ts index 3c89a525107..f437b85ce32 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader.ts @@ -412,7 +412,7 @@ const nextServerlessLoader: loader.Loader = function () { ${normalizeDynamicRouteParams} ${handleRewrites} - export const config = compMod['confi' + 'g'] || (compMod.then && compMod.then(mod => mod['confi' + 'g'])) || {} + export let config = compMod['confi' + 'g'] || (compMod.then && compMod.then(mod => mod['confi' + 'g'])) || {} export const _app = App export async function renderReqToHTML(req, res, renderMode, _renderOpts, _params) { let Document @@ -423,6 +423,7 @@ const nextServerlessLoader: loader.Loader = function () { getStaticPaths, Component, App, + config, { default: Document }, { default: Error } ] = await Promise.all([ @@ -431,6 +432,7 @@ const nextServerlessLoader: loader.Loader = function () { getStaticPaths, Component, App, + config, require('${absoluteDocumentPath}'), require('${absoluteErrorPath}') ]) diff --git a/packages/next/next-server/server/load-components.ts b/packages/next/next-server/server/load-components.ts index 85a51e236fb..4eac4dce063 100644 --- a/packages/next/next-server/server/load-components.ts +++ b/packages/next/next-server/server/load-components.ts @@ -46,10 +46,11 @@ export async function loadComponents( getStaticProps = await getStaticProps getStaticPaths = await getStaticPaths getServerSideProps = await getServerSideProps + const pageConfig = (await Component.config) || {} return { Component, - pageConfig: Component.config || {}, + pageConfig, getStaticProps, getStaticPaths, getServerSideProps, diff --git a/test/integration/async-modules/pages/config.jsx b/test/integration/async-modules/pages/config.jsx new file mode 100644 index 00000000000..ff9aa6ea34e --- /dev/null +++ b/test/integration/async-modules/pages/config.jsx @@ -0,0 +1,22 @@ +export const config = { + amp: true, +} + +await Promise.resolve('tadaa') + +export default function Config() { + const date = new Date() + return ( +
+ + fail + +
+ ) +} diff --git a/test/integration/async-modules/test/index.test.js b/test/integration/async-modules/test/index.test.js index f4f77654a2c..2e671529432 100644 --- a/test/integration/async-modules/test/index.test.js +++ b/test/integration/async-modules/test/index.test.js @@ -80,6 +80,16 @@ function runTests(dev = false) { if (browser) await browser.close() } }) + + it('can render async AMP pages', async () => { + let browser + try { + browser = await webdriver(appPort, '/config') + expect(await browser.elementByCss('#amp-timeago').text()).not.toBe('fail') + } finally { + if (browser) await browser.close() + } + }) ;(dev ? it.skip : it)('can render async error page', async () => { let browser try {