From 6c2ce706086cc2b6ffbbbf6dfbc8f39aa7c73722 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Mon, 22 Jun 2020 23:12:36 +0200 Subject: [PATCH] Remove buildId from server-side files (#14413) Gets rid of the custom function for naming files by removing buildId from the file paths. --- packages/next/build/entries.ts | 6 +- packages/next/build/webpack-config.ts | 20 +--- packages/next/export/index.ts | 23 ++-- .../server/get-route-from-entrypoint.ts | 12 +-- .../next/next-server/server/next-server.ts | 4 +- packages/next/server/hot-reloader.ts | 2 +- .../next/server/on-demand-entry-handler.ts | 2 +- test/integration/404-page-app/next.config.js | 1 + test/integration/404-page-app/pages/404.js | 5 + test/integration/404-page-app/pages/_app.js | 18 ++++ test/integration/404-page-app/pages/err.js | 5 + test/integration/404-page-app/pages/index.js | 1 + .../404-page-app/test/index.test.js | 89 +++++++++++++++ .../404-page-custom-error/test/index.test.js | 21 +--- test/integration/404-page/test/index.test.js | 101 +----------------- .../amphtml-ssg/test/index.test.js | 9 +- test/integration/amphtml/pages/nav.js | 17 +++ test/integration/amphtml/test/index.test.js | 88 +++------------ test/integration/chunking/next.config.js | 1 - test/integration/chunking/test/index.test.js | 74 ++++--------- .../client-navigation/test/rendering.js | 22 ---- .../test/index.test.js | 11 +- .../non-next-dist-exclude/test/index.test.js | 11 +- .../test/index.test.js | 19 ++-- test/integration/prerender/test/index.test.js | 3 +- .../integration/production/test/index.test.js | 26 ++--- .../serverless-trace/test/index.test.js | 21 ++-- .../integration/serverless/test/index.test.js | 20 ++-- .../integration/static-404/test/index.test.js | 12 --- test/lib/next-test-utils.js | 13 ++- 30 files changed, 269 insertions(+), 388 deletions(-) create mode 100644 test/integration/404-page-app/next.config.js create mode 100644 test/integration/404-page-app/pages/404.js create mode 100644 test/integration/404-page-app/pages/_app.js create mode 100644 test/integration/404-page-app/pages/err.js create mode 100644 test/integration/404-page-app/pages/index.js create mode 100644 test/integration/404-page-app/test/index.test.js create mode 100644 test/integration/amphtml/pages/nav.js diff --git a/packages/next/build/entries.ts b/packages/next/build/entries.ts index e0e8032c1b..dc87eb2d9a 100644 --- a/packages/next/build/entries.ts +++ b/packages/next/build/entries.ts @@ -101,7 +101,7 @@ export function createEntrypoints( const isApiRoute = page.match(API_ROUTE) const clientBundlePath = join('static', 'pages', bundleFile) - const serverBundlePath = join('static', 'BUILD_ID', 'pages', bundleFile) + const serverBundlePath = join('pages', bundleFile) const isLikeServerless = isTargetLikeServerless(target) @@ -111,7 +111,7 @@ export function createEntrypoints( absolutePagePath, ...defaultServerlessOptions, } - server[join('pages', bundleFile)] = `next-serverless-loader?${stringify( + server[serverBundlePath] = `next-serverless-loader?${stringify( serverlessLoaderOptions )}!` } else if (isApiRoute || target === 'server') { @@ -122,7 +122,7 @@ export function createEntrypoints( absolutePagePath, ...defaultServerlessOptions, } - server[join('pages', bundleFile)] = `next-serverless-loader?${stringify( + server[serverBundlePath] = `next-serverless-loader?${stringify( serverlessLoaderOptions )}!` } diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index a9cf8f87f4..b242d59819 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -679,24 +679,8 @@ export default async function getBaseWebpackConfig( }, output: { path: outputPath, - filename: isServer - ? ({ chunk }: { chunk: { name: string } }) => { - // Use `[name]-[contenthash].js` in production - if (chunk.name.includes('BUILD_ID')) { - return ( - escapePathVariables(chunk.name).replace( - 'BUILD_ID', - isServer || dev ? buildId : '[contenthash]' - ) + '.js' - ) - } - - return '[name].js' - } - : // Client compilation only - dev - ? '[name].js' - : '[name]-[chunkhash].js', + // On the server we don't use the chunkhash + filename: dev || isServer ? '[name].js' : '[name]-[chunkhash].js', libraryTarget: isServer ? 'commonjs2' : 'var', hotUpdateChunkFilename: isWebpack5 ? 'static/webpack/[id].[fullhash].hot-update.js' diff --git a/packages/next/export/index.ts b/packages/next/export/index.ts index c747ea65a5..23d40b0ba0 100644 --- a/packages/next/export/index.ts +++ b/packages/next/export/index.ts @@ -41,6 +41,7 @@ import { loadEnvConfig } from '../lib/load-env-config' import { PrerenderManifest } from '../build' import type exportPage from './worker' import { PagesManifest } from '../build/webpack/plugins/pages-manifest-plugin' +import { getPagePath } from '../next-server/server/require' const exists = promisify(existsOrig) @@ -157,14 +158,6 @@ export default async function exportApp( prerenderManifest = require(join(distDir, PRERENDER_MANIFEST)) } catch (_) {} - const distPagesDir = join( - distDir, - isLikeServerless - ? SERVERLESS_DIRECTORY - : join(SERVER_DIRECTORY, 'static', buildId), - 'pages' - ) - const excludedPrerenderRoutes = new Set() const pages = options.pages || Object.keys(pagesManifest) const defaultPathMap: ExportPathMap = {} @@ -425,7 +418,21 @@ export default async function exportApp( if (!options.buildExport && prerenderManifest) { await Promise.all( Object.keys(prerenderManifest.routes).map(async (route) => { + const { srcRoute } = prerenderManifest!.routes[route] + const pageName = srcRoute || route + const pagePath = getPagePath(pageName, distDir, isLikeServerless) + const distPagesDir = join( + pagePath, + // strip leading / and then recurse number of nested dirs + // to place from base folder + pageName + .substr(1) + .split('/') + .map(() => '..') + .join('/') + ) route = normalizePagePath(route) + const orig = join(distPagesDir, route) const htmlDest = join( outDir, diff --git a/packages/next/next-server/server/get-route-from-entrypoint.ts b/packages/next/next-server/server/get-route-from-entrypoint.ts index 65c4f75cd1..4d9756da20 100644 --- a/packages/next/next-server/server/get-route-from-entrypoint.ts +++ b/packages/next/next-server/server/get-route-from-entrypoint.ts @@ -1,9 +1,9 @@ import { denormalizePagePath } from './normalize-page-path' // matches static//pages/:page*.js -const ROUTE_NAME_REGEX = /^static[/\\][^/\\]+[/\\]pages[/\\](.*)$/ +// const SERVER_ROUTE_NAME_REGEX = /^static[/\\][^/\\]+[/\\]pages[/\\](.*)$/ // matches pages/:page*.js -const SERVERLESS_ROUTE_NAME_REGEX = /^pages[/\\](.*)$/ +const SERVER_ROUTE_NAME_REGEX = /^pages[/\\](.*)$/ // matches static/pages/:page*.js const BROWSER_ROUTE_NAME_REGEX = /^static[/\\]pages[/\\](.*)$/ @@ -19,12 +19,10 @@ function matchBundle(regex: RegExp, input: string): string | null { export default function getRouteFromEntrypoint( entryFile: string, - isServerlessLike: boolean = false + // TODO: Remove this parameter + _isServerlessLike: boolean = false ): string | null { - let pagePath = matchBundle( - isServerlessLike ? SERVERLESS_ROUTE_NAME_REGEX : ROUTE_NAME_REGEX, - entryFile - ) + let pagePath = matchBundle(SERVER_ROUTE_NAME_REGEX, entryFile) if (pagePath) { return pagePath diff --git a/packages/next/next-server/server/next-server.ts b/packages/next/next-server/server/next-server.ts index 4fd040cb51..9158099f8b 100644 --- a/packages/next/next-server/server/next-server.ts +++ b/packages/next/next-server/server/next-server.ts @@ -220,9 +220,7 @@ export default class Server { distDir: this.distDir, pagesDir: join( this.distDir, - this._isLikeServerless - ? SERVERLESS_DIRECTORY - : `${SERVER_DIRECTORY}/static/${this.buildId}`, + this._isLikeServerless ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY, 'pages' ), flushToDisk: this.nextConfig.experimental.sprFlushToDisk, diff --git a/packages/next/server/hot-reloader.ts b/packages/next/server/hot-reloader.ts index f506935bb5..72b1e61f75 100644 --- a/packages/next/server/hot-reloader.ts +++ b/packages/next/server/hot-reloader.ts @@ -380,7 +380,7 @@ export default class HotReloader { // We only watch `_document` for changes on the server compilation // the rest of the files will be triggered by the client compilation const documentChunk = compilation.chunks.find( - (c) => c.name === normalize(`static/BUILD_ID/pages/_document`) + (c) => c.name === normalize(`pages/_document`) ) // If the document chunk can't be found we do nothing if (!documentChunk) { diff --git a/packages/next/server/on-demand-entry-handler.ts b/packages/next/server/on-demand-entry-handler.ts index 599083b479..b8ec5b49f8 100644 --- a/packages/next/server/on-demand-entry-handler.ts +++ b/packages/next/server/on-demand-entry-handler.ts @@ -228,7 +228,7 @@ export default function onDemandEntryHandler( pageUrl = pageUrl === '' ? '/' : pageUrl const bundleFile = normalizePagePath(pageUrl) - const serverBundlePath = join('static', 'BUILD_ID', 'pages', bundleFile) + const serverBundlePath = join('pages', bundleFile) const clientBundlePath = join('static', 'pages', bundleFile) const absolutePagePath = pagePath.startsWith('next/dist/pages') ? require.resolve(pagePath) diff --git a/test/integration/404-page-app/next.config.js b/test/integration/404-page-app/next.config.js new file mode 100644 index 0000000000..4ba52ba2c8 --- /dev/null +++ b/test/integration/404-page-app/next.config.js @@ -0,0 +1 @@ +module.exports = {} diff --git a/test/integration/404-page-app/pages/404.js b/test/integration/404-page-app/pages/404.js new file mode 100644 index 0000000000..3d9ab7e2fa --- /dev/null +++ b/test/integration/404-page-app/pages/404.js @@ -0,0 +1,5 @@ +const page = (props) => { + return

{props.extraProp}

+} + +export default page diff --git a/test/integration/404-page-app/pages/_app.js b/test/integration/404-page-app/pages/_app.js new file mode 100644 index 0000000000..3357dfc43d --- /dev/null +++ b/test/integration/404-page-app/pages/_app.js @@ -0,0 +1,18 @@ +import App from 'next/app' + +function MyApp({ Component, pageProps, extraProp }) { + return +} + +// Only uncomment this method if you have blocking data requirements for +// every single page in your application. This disables the ability to +// perform automatic static optimization, causing every page in your app to +// be server-side rendered. +MyApp.getInitialProps = async (appContext) => { + // calls page's `getInitialProps` and fills `appProps.pageProps` + const appProps = await App.getInitialProps(appContext) + + return { ...appProps, extraProp: 'Hi There' } +} + +export default MyApp diff --git a/test/integration/404-page-app/pages/err.js b/test/integration/404-page-app/pages/err.js new file mode 100644 index 0000000000..938b5e49ac --- /dev/null +++ b/test/integration/404-page-app/pages/err.js @@ -0,0 +1,5 @@ +const page = () => 'custom 404 page' +page.getInitialProps = () => { + throw new Error('oops') +} +export default page diff --git a/test/integration/404-page-app/pages/index.js b/test/integration/404-page-app/pages/index.js new file mode 100644 index 0000000000..f6c15d1f66 --- /dev/null +++ b/test/integration/404-page-app/pages/index.js @@ -0,0 +1 @@ +export default () => 'hello from index' diff --git a/test/integration/404-page-app/test/index.test.js b/test/integration/404-page-app/test/index.test.js new file mode 100644 index 0000000000..36079a1c9d --- /dev/null +++ b/test/integration/404-page-app/test/index.test.js @@ -0,0 +1,89 @@ +/* eslint-env jest */ + +import fs from 'fs-extra' +import { join } from 'path' +import { + killApp, + findPort, + launchApp, + nextStart, + nextBuild, + fetchViaHTTP, +} from 'next-test-utils' +import webdriver from 'next-webdriver' +import cheerio from 'cheerio' + +jest.setTimeout(1000 * 60 * 2) + +const appDir = join(__dirname, '../') +const gip404Err = /`pages\/404` can not have getInitialProps\/getServerSideProps/ + +let appPort +let app + +describe('404 Page Support with _app', () => { + describe('production mode', () => { + afterAll(() => killApp(app)) + + it('should build successfully', async () => { + const { code, stderr, stdout } = await nextBuild(appDir, [], { + stderr: true, + stdout: true, + }) + + expect(code).toBe(0) + expect(stderr).not.toMatch(gip404Err) + expect(stdout).not.toMatch(gip404Err) + + appPort = await findPort() + app = await nextStart(appDir, appPort) + }) + + it('should not output static 404 if _app has getInitialProps', async () => { + const browser = await webdriver(appPort, '/404') + const isAutoExported = await browser.eval('__NEXT_DATA__.autoExport') + expect(isAutoExported).toBe(null) + }) + + it('specify to use the 404 page still in the routes-manifest', async () => { + const manifest = await fs.readJSON( + join(appDir, '.next/routes-manifest.json') + ) + expect(manifest.pages404).toBe(true) + }) + + it('should still use 404 page', async () => { + const res = await fetchViaHTTP(appPort, '/abc') + expect(res.status).toBe(404) + const $ = cheerio.load(await res.text()) + expect($('#404-title').text()).toBe('Hi There') + }) + }) + + describe('dev mode', () => { + let stderr = '' + let stdout = '' + + beforeAll(async () => { + appPort = await findPort() + app = await launchApp(appDir, appPort, { + onStderr(msg) { + stderr += msg + }, + onStdout(msg) { + stdout += msg + }, + }) + }) + afterAll(() => killApp(app)) + + it('should not show pages/404 GIP error if _app has GIP', async () => { + const res = await fetchViaHTTP(appPort, '/abc') + expect(res.status).toBe(404) + const $ = cheerio.load(await res.text()) + expect($('#404-title').text()).toBe('Hi There') + expect(stderr).not.toMatch(gip404Err) + expect(stdout).not.toMatch(gip404Err) + }) + }) +}) diff --git a/test/integration/404-page-custom-error/test/index.test.js b/test/integration/404-page-custom-error/test/index.test.js index 09b91b25d5..cdbb58a6e3 100644 --- a/test/integration/404-page-custom-error/test/index.test.js +++ b/test/integration/404-page-custom-error/test/index.test.js @@ -10,6 +10,7 @@ import { nextBuild, renderViaHTTP, fetchViaHTTP, + getPageFileFromPagesManifest, } from 'next-test-utils' jest.setTimeout(1000 * 60 * 2) @@ -18,7 +19,6 @@ const appDir = join(__dirname, '../') const nextConfig = join(appDir, 'next.config.js') let appPort -let buildId let app const runTests = (mode) => { @@ -47,21 +47,8 @@ const runTests = (mode) => { }) it('should have output 404.html', async () => { - expect( - await fs - .access( - join( - appDir, - '.next', - ...(mode === 'server' - ? ['server', 'static', buildId, 'pages'] - : ['serverless', 'pages']), - '404.html' - ) - ) - .then(() => true) - .catch(() => false) - ).toBe(true) + const page = getPageFileFromPagesManifest(appDir, '/404') + expect(page.endsWith('.html')).toBe(true) }) } } @@ -81,7 +68,6 @@ describe('Default 404 Page with custom _error', () => { appPort = await findPort() app = await nextStart(appDir, appPort) - buildId = await fs.readFile(join(appDir, '.next/BUILD_ID'), 'utf8') }) runTests('server') @@ -109,7 +95,6 @@ describe('Default 404 Page with custom _error', () => { appPort = await findPort() app = await nextStart(appDir, appPort) - buildId = await fs.readFile(join(appDir, '.next/BUILD_ID'), 'utf8') }) runTests('serverless') diff --git a/test/integration/404-page/test/index.test.js b/test/integration/404-page/test/index.test.js index e93b9f4864..7f4aa59b04 100644 --- a/test/integration/404-page/test/index.test.js +++ b/test/integration/404-page/test/index.test.js @@ -11,18 +11,17 @@ import { renderViaHTTP, fetchViaHTTP, waitFor, + getPageFileFromPagesManifest, } from 'next-test-utils' jest.setTimeout(1000 * 60 * 2) const appDir = join(__dirname, '../') const pages404 = join(appDir, 'pages/404.js') -const appPage = join(appDir, 'pages/_app.js') const nextConfig = join(appDir, 'next.config.js') const gip404Err = /`pages\/404` can not have getInitialProps\/getServerSideProps/ let nextConfigContent -let buildId let appPort let app @@ -51,18 +50,8 @@ const runTests = (mode = 'server') => { if (mode !== 'dev') { it('should output 404.html during build', async () => { - expect( - await fs.exists( - join( - appDir, - '.next', - mode === 'serverless' - ? 'serverless/pages' - : `server/static/${buildId}/pages`, - '404.html' - ) - ) - ).toBe(true) + const page = getPageFileFromPagesManifest(appDir, '/404') + expect(page.endsWith('.html')).toBe(true) }) it('should add /404 to pages-manifest correctly', async () => { @@ -79,7 +68,6 @@ describe('404 Page Support', () => { beforeAll(async () => { appPort = await findPort() app = await launchApp(appDir, appPort) - buildId = 'development' }) afterAll(() => killApp(app)) @@ -91,7 +79,6 @@ describe('404 Page Support', () => { await nextBuild(appDir) appPort = await findPort() app = await nextStart(appDir, appPort) - buildId = await fs.readFile(join(appDir, '.next/BUILD_ID'), 'utf8') }) afterAll(() => killApp(app)) @@ -112,7 +99,6 @@ describe('404 Page Support', () => { await nextBuild(appDir) appPort = await findPort() app = await nextStart(appDir, appPort) - buildId = await fs.readFile(join(appDir, '.next/BUILD_ID'), 'utf8') }) afterAll(async () => { await fs.writeFile(nextConfig, nextConfigContent) @@ -275,85 +261,4 @@ describe('404 Page Support', () => { expect(stderr).toMatch(gip404Err) }) - - describe('_app with getInitialProps', () => { - beforeAll(() => - fs.writeFile( - appPage, - ` - import NextApp from 'next/app' - const App = ({ Component, pageProps }) => - App.getInitialProps = NextApp.getInitialProps - export default App - ` - ) - ) - afterAll(() => fs.remove(appPage)) - - describe('production mode', () => { - afterAll(() => killApp(app)) - - it('should build successfully', async () => { - const { code, stderr, stdout } = await nextBuild(appDir, [], { - stderr: true, - stdout: true, - }) - - expect(code).toBe(0) - expect(stderr).not.toMatch(gip404Err) - expect(stdout).not.toMatch(gip404Err) - - appPort = await findPort() - app = await nextStart(appDir, appPort) - buildId = await fs.readFile(join(appDir, '.next/BUILD_ID'), 'utf8') - }) - - it('should not output static 404 if _app has getInitialProps', async () => { - expect( - await fs.exists( - join(appDir, '.next/server/static', buildId, 'pages/404.html') - ) - ).toBe(false) - }) - - it('specify to use the 404 page still in the routes-manifest', async () => { - const manifest = await fs.readJSON( - join(appDir, '.next/routes-manifest.json') - ) - expect(manifest.pages404).toBe(true) - }) - - it('should still use 404 page', async () => { - const res = await fetchViaHTTP(appPort, '/abc') - expect(res.status).toBe(404) - expect(await res.text()).toContain('custom 404 page') - }) - }) - - describe('dev mode', () => { - let stderr = '' - let stdout = '' - - beforeAll(async () => { - appPort = await findPort() - app = await launchApp(appDir, appPort, { - onStderr(msg) { - stderr += msg - }, - onStdout(msg) { - stdout += msg - }, - }) - }) - afterAll(() => killApp(app)) - - it('should not show pages/404 GIP error if _app has GIP', async () => { - const res = await fetchViaHTTP(appPort, '/abc') - expect(res.status).toBe(404) - expect(await res.text()).toContain('custom 404 page') - expect(stderr).not.toMatch(gip404Err) - expect(stdout).not.toMatch(gip404Err) - }) - }) - }) }) diff --git a/test/integration/amphtml-ssg/test/index.test.js b/test/integration/amphtml-ssg/test/index.test.js index 8fae756665..ef82517031 100644 --- a/test/integration/amphtml-ssg/test/index.test.js +++ b/test/integration/amphtml-ssg/test/index.test.js @@ -117,13 +117,8 @@ describe('AMP SSG Support', () => { await nextBuild(appDir) appPort = await findPort() app = await nextStart(appDir, appPort) - const buildId = await fs.readFile(join(appDir, '.next/BUILD_ID'), 'utf8') - builtServerPagesDir = join( - appDir, - '.next/server/static', - buildId, - 'pages' - ) + // TODO: use browser instead to do checks that now need filesystem access + builtServerPagesDir = join(appDir, '.next', 'server', 'pages') }) afterAll(() => killApp(app)) runTests() diff --git a/test/integration/amphtml/pages/nav.js b/test/integration/amphtml/pages/nav.js new file mode 100644 index 0000000000..f3d38a2491 --- /dev/null +++ b/test/integration/amphtml/pages/nav.js @@ -0,0 +1,17 @@ +import Link from 'next/link' + +if (typeof window !== 'undefined') { + window.NAV_PAGE_LOADED = true +} + +export default function Nav() { + return ( + + ) +} diff --git a/test/integration/amphtml/test/index.test.js b/test/integration/amphtml/test/index.test.js index 1dbc48a1a2..a9e730f948 100644 --- a/test/integration/amphtml/test/index.test.js +++ b/test/integration/amphtml/test/index.test.js @@ -2,13 +2,7 @@ import { validateAMP } from 'amp-test-utils' import cheerio from 'cheerio' -import { - accessSync, - readFile, - readFileSync, - writeFile, - writeFileSync, -} from 'fs-extra' +import { readFile, readFileSync, writeFile, writeFileSync } from 'fs-extra' import { check, findPort, @@ -72,31 +66,12 @@ describe('AMP Usage', () => { }) it('should not output client pages for AMP only', async () => { - const buildId = readFileSync(join(appDir, '.next/BUILD_ID'), 'utf8') - const ampOnly = ['only-amp', 'root-hmr', 'another-amp'] - for (const pg of ampOnly) { - expect(() => - accessSync( - join(appDir, '.next/static', buildId, 'pages', pg + '.js') - ) - ).toThrow() - expect(() => - accessSync( - join( - appDir, - '.next/server/static', - buildId, - 'pages', - pg + '.html' - ) - ) - ).not.toThrow() - expect(() => - accessSync( - join(appDir, '.next/server/static', buildId, 'pages', pg + '.js') - ) - ).toThrow() - } + const browser = await webdriver(appPort, '/nav') + await browser.elementByCss('#only-amp-link').click() + + const result = await browser.eval('window.NAV_PAGE_LOADED') + + expect(result).toBe(null) }) it('should add link preload for amp script', async () => { @@ -285,51 +260,12 @@ describe('AMP Usage', () => { }) it('should not output client pages for AMP only', async () => { - const buildId = readFileSync(join(appDir, '.next/BUILD_ID'), 'utf8') - const ampOnly = ['only-amp', 'root-hmr', 'another-amp'] - for (const pg of ampOnly) { - expect(() => - accessSync(join(appDir, '.next/static', buildId, 'pages', pg + '.js')) - ).toThrow() - expect(() => - accessSync( - join(appDir, '.next/server/static', buildId, 'pages', pg + '.html') - ) - ).not.toThrow() - expect(() => - accessSync( - join(appDir, '.next/server/static', buildId, 'pages', pg + '.js') - ) - ).toThrow() - } - }) + const browser = await webdriver(appPort, '/nav') + await browser.elementByCss('#only-amp-link').click() - it('should not output modern client pages for AMP only', async () => { - const buildId = readFileSync(join(appDir, '.next/BUILD_ID'), 'utf8') - const ampOnly = ['only-amp', 'root-hmr', 'another-amp'] - for (const pg of ampOnly) { - expect(() => - accessSync( - join(appDir, '.next/static', buildId, 'pages', pg + '.module.js') - ) - ).toThrow() - expect(() => - accessSync( - join(appDir, '.next/server/static', buildId, 'pages', pg + '.html') - ) - ).not.toThrow() - expect(() => - accessSync( - join( - appDir, - '.next/server/static', - buildId, - 'pages', - pg + '.module.js' - ) - ) - ).toThrow() - } + const result = await browser.eval('window.NAV_PAGE_LOADED') + + expect(result).toBe(null) }) }) diff --git a/test/integration/chunking/next.config.js b/test/integration/chunking/next.config.js index 7b05b6cf8c..319b03a117 100644 --- a/test/integration/chunking/next.config.js +++ b/test/integration/chunking/next.config.js @@ -1,7 +1,6 @@ const BundleAnalyzerPlugin = require('webpack-bundle-analyzer') .BundleAnalyzerPlugin module.exports = { - assetPrefix: '/foo/', webpack(config) { config.plugins = config.plugins || [] config.plugins.push( diff --git a/test/integration/chunking/test/index.test.js b/test/integration/chunking/test/index.test.js index b5440ca3bc..24bcfd92d2 100644 --- a/test/integration/chunking/test/index.test.js +++ b/test/integration/chunking/test/index.test.js @@ -1,10 +1,14 @@ /* eslint-env jest */ import cheerio from 'cheerio' -import express from 'express' -import { access, readdir, readFile, unlink } from 'fs-extra' -import http from 'http' -import { nextBuild, nextServer, promiseCall, stopApp } from 'next-test-utils' +import { readdir, readFile, unlink } from 'fs-extra' +import { + nextBuild, + killApp, + nextStart, + findPort, + renderViaHTTP, +} from 'next-test-utils' import webdriver from 'next-webdriver' import { join } from 'path' @@ -12,10 +16,10 @@ jest.setTimeout(1000 * 60 * 1) const appDir = join(__dirname, '../') -let buildId let chunks let stats - +let appPort +let app const existsChunkNamed = (name) => { return chunks.some((chunk) => new RegExp(name).test(chunk)) } @@ -33,21 +37,20 @@ describe('Chunking', () => { } catch (e) { // Error here means old chunks don't exist, so we don't need to do anything } - const { stdout, stderr } = await nextBuild(appDir, [], { - stdout: true, - stderr: true, - }) - console.log(stdout) - console.error(stderr) + await nextBuild(appDir, []) + stats = (await readFile(join(appDir, '.next', 'stats.json'), 'utf8')) // fixes backslashes in keyNames not being escaped on windows .replace(/"static\\(.*?":?)/g, (match) => match.replace(/\\/g, '\\\\')) stats = JSON.parse(stats) - buildId = await readFile(join(appDir, '.next/BUILD_ID'), 'utf8') + appPort = await findPort() + app = await nextStart(appDir, appPort) chunks = await readdir(join(appDir, '.next', 'static', 'chunks')) }) + afterAll(() => killApp(app)) + it('should use all url friendly names', () => { expect(chunks).toEqual(chunks.map((name) => encodeURIComponent(name))) }) @@ -68,20 +71,9 @@ describe('Chunking', () => { expect(existsChunkNamed('react|react-dom')).toBe(false) }) - it('should create a _buildManifest.js file', async () => { - expect( - await access( - join(appDir, '.next', 'static', buildId, '_buildManifest.js') - ) - ).toBe(undefined) /* fs.access callback returns undefined if file exists */ - }) - it('should not preload the build manifest', async () => { - const indexPage = await readFile( - join(appDir, '.next', 'server', 'static', buildId, 'pages', 'index.html') - ) - - const $ = cheerio.load(indexPage) + const html = await renderViaHTTP(appPort, '/') + const $ = cheerio.load(html) expect( [].slice .call($('link[rel="preload"][as="script"]')) @@ -91,11 +83,9 @@ describe('Chunking', () => { }) it('should execute the build manifest', async () => { - const indexPage = await readFile( - join(appDir, '.next', 'server', 'static', buildId, 'pages', 'index.html') - ) - - const $ = cheerio.load(indexPage) + const html = await renderViaHTTP(appPort, '/') + console.log(html) + const $ = cheerio.load(html) expect( Array.from($('script')) .map((e) => e.attribs.src) @@ -117,28 +107,6 @@ describe('Chunking', () => { }) describe('Serving', () => { - let server - let appPort - - beforeAll(async () => { - await nextBuild(appDir) - const app = nextServer({ - dir: join(__dirname, '../'), - dev: false, - quiet: true, - }) - - const expressApp = express() - await app.prepare() - expressApp.use('/foo/_next', express.static(join(__dirname, '../.next'))) - expressApp.use(app.getRequestHandler()) - server = http.createServer(expressApp) - await promiseCall(server, 'listen') - appPort = server.address().port - }) - - afterAll(() => stopApp(server)) - it('should hydrate with aggressive chunking', async () => { const browser = await webdriver(appPort, '/page2') const text = await browser.elementByCss('#padded-str').text() diff --git a/test/integration/client-navigation/test/rendering.js b/test/integration/client-navigation/test/rendering.js index e449498081..32d04ed250 100644 --- a/test/integration/client-navigation/test/rendering.js +++ b/test/integration/client-navigation/test/rendering.js @@ -4,9 +4,6 @@ import cheerio from 'cheerio' import { BUILD_MANIFEST, REACT_LOADABLE_MANIFEST } from 'next/constants' import { join } from 'path' import url from 'url' -import { getPageFileFromBuildManifest } from 'next-test-utils' - -const appDir = join(__dirname, '../') export default function (render, fetch) { async function get$(path, query) { @@ -268,25 +265,6 @@ export default function (render, fetch) { expect(res.status).toBe(200) }) - test('should expose the compiled page file in development', async () => { - await fetch('/stateless') // make sure the stateless page is built - const statelessPageFile = getPageFileFromBuildManifest( - appDir, - '/stateless' - ) - const clientSideJsRes = await fetch(join('/_next', statelessPageFile)) - expect(clientSideJsRes.status).toBe(200) - const clientSideJsBody = await clientSideJsRes.text() - expect(clientSideJsBody).toMatch(/My component!/) - - const serverSideJsRes = await fetch( - '/_next/development/server/static/development/pages/stateless.js' - ) - expect(serverSideJsRes.status).toBe(200) - const serverSideJsBody = await serverSideJsRes.text() - expect(serverSideJsBody).toMatch(/My component!/) - }) - test('allows to import .json files', async () => { const html = await render('/json') expect(html.includes('Vercel')).toBeTruthy() diff --git a/test/integration/externalize-next-server/test/index.test.js b/test/integration/externalize-next-server/test/index.test.js index 50c7e55dea..d545af0fb8 100644 --- a/test/integration/externalize-next-server/test/index.test.js +++ b/test/integration/externalize-next-server/test/index.test.js @@ -1,26 +1,19 @@ /* eslint-env jest */ - -import fs from 'fs-extra' import path from 'path' -import { nextBuild } from 'next-test-utils' +import { nextBuild, readNextBuildServerPageFile } from 'next-test-utils' import escapeStringRegexp from 'escape-string-regexp' jest.setTimeout(1000 * 60 * 1) const appDir = path.join(__dirname, '../app') -let buildId describe('externalize next/dist/next-server', () => { beforeAll(async () => { await nextBuild(appDir) - buildId = await fs.readFile(path.join(appDir, '.next/BUILD_ID'), 'utf8') }) it('Does not bundle next/dist/next-server/lib/head.js in _error', async () => { - const content = await fs.readFile( - path.join(appDir, '.next/server/static', buildId, 'pages/_error.js'), - 'utf8' - ) + const content = readNextBuildServerPageFile(appDir, '/_error') expect(content).toMatch( new RegExp( '^' + diff --git a/test/integration/non-next-dist-exclude/test/index.test.js b/test/integration/non-next-dist-exclude/test/index.test.js index 6308167060..d4d3b46a3d 100644 --- a/test/integration/non-next-dist-exclude/test/index.test.js +++ b/test/integration/non-next-dist-exclude/test/index.test.js @@ -1,25 +1,18 @@ /* eslint-env jest */ - -import fs from 'fs-extra' import path from 'path' -import { nextBuild } from 'next-test-utils' +import { nextBuild, readNextBuildServerPageFile } from 'next-test-utils' jest.setTimeout(1000 * 60 * 1) const appDir = path.join(__dirname, '../app') -let buildId describe('Non-Next externalization', () => { beforeAll(async () => { await nextBuild(appDir) - buildId = await fs.readFile(path.join(appDir, '.next/BUILD_ID'), 'utf8') }) it('Externalized non-Next dist-using package', async () => { - const content = await fs.readFile( - path.join(appDir, '.next/server/static', buildId, 'pages/index.js'), - 'utf8' - ) + const content = readNextBuildServerPageFile(appDir, '/') expect(content).not.toContain('BrokenExternalMarker') }) }) diff --git a/test/integration/prerender-no-revalidate/test/index.test.js b/test/integration/prerender-no-revalidate/test/index.test.js index abe6662a98..77611e0100 100644 --- a/test/integration/prerender-no-revalidate/test/index.test.js +++ b/test/integration/prerender-no-revalidate/test/index.test.js @@ -8,6 +8,7 @@ import { nextStart, renderViaHTTP, waitFor, + getPageFileFromPagesManifest, } from 'next-test-utils' import { join } from 'path' @@ -23,9 +24,9 @@ function runTests(route, routePath, serverless) { it(`[${route}] should not revalidate when set to false`, async () => { const fileName = join( appDir, - `.next`, - ...(serverless ? ['serverless'] : ['server', 'static', buildId]), - `pages/${routePath}.html` + '.next', + serverless ? 'serverless' : 'server', + getPageFileFromPagesManifest(appDir, routePath) ) const initialHtml = await renderViaHTTP(appPort, route) const initialFileHtml = await fs.readFile(fileName, 'utf8') @@ -50,13 +51,13 @@ function runTests(route, routePath, serverless) { }) it(`[${route}] should not revalidate /_next/data when set to false`, async () => { - const route = join(`/_next/data/${buildId}`, `${routePath}.json`) const fileName = join( appDir, - `.next`, - ...(serverless ? ['serverless'] : ['server', 'static', buildId]), - `pages/${routePath}.json` + '.next', + serverless ? 'serverless' : 'server', + getPageFileFromPagesManifest(appDir, routePath) ) + const route = join(`/_next/data/${buildId}`, `${routePath}.json`) const initialData = JSON.parse(await renderViaHTTP(appPort, route)) const initialFileJson = await fs.readFile(fileName, 'utf8') @@ -99,7 +100,7 @@ describe('SSG Prerender No Revalidate', () => { }) afterAll(() => killApp(app)) - runTests('/', '/index', true) + runTests('/', '/', true) runTests('/named', '/named', true) runTests('/nested', '/nested', true) runTests('/nested/named', '/nested/named', true) @@ -121,7 +122,7 @@ describe('SSG Prerender No Revalidate', () => { }) afterAll(() => killApp(app)) - runTests('/', '/index') + runTests('/', '/') runTests('/named', '/named') runTests('/nested', '/nested') runTests('/nested/named', '/nested/named') diff --git a/test/integration/prerender/test/index.test.js b/test/integration/prerender/test/index.test.js index 7d0f91d4f0..ebd2548509 100644 --- a/test/integration/prerender/test/index.test.js +++ b/test/integration/prerender/test/index.test.js @@ -1541,7 +1541,8 @@ describe('SSG Prerender', () => { }, }) buildId = await fs.readFile(join(appDir, '.next/BUILD_ID'), 'utf8') - distPagesDir = join(appDir, '.next/server/static', buildId, 'pages') + // TODO: Don't rely on this path + distPagesDir = join(appDir, '.next', 'server', 'pages') }) afterAll(() => killApp(app)) diff --git a/test/integration/production/test/index.test.js b/test/integration/production/test/index.test.js index b76b5a17cc..263a53929c 100644 --- a/test/integration/production/test/index.test.js +++ b/test/integration/production/test/index.test.js @@ -1,7 +1,7 @@ /* eslint-env jest */ /* global browserName */ import cheerio from 'cheerio' -import { existsSync, readFileSync } from 'fs' +import { existsSync } from 'fs' import { nextServer, renderViaHTTP, @@ -9,6 +9,7 @@ import { startApp, stopApp, waitFor, + getPageFileFromPagesManifest, } from 'next-test-utils' import webdriver from 'next-webdriver' import { @@ -23,7 +24,6 @@ import dynamicImportTests from './dynamic' import processEnv from './process-env' import security from './security' const appDir = join(__dirname, '../') -let serverDir let appPort let server let app @@ -43,9 +43,6 @@ describe('Production Usage', () => { server = await startApp(app) context.appPort = appPort = server.address().port - - const buildId = readFileSync(join(appDir, '.next/BUILD_ID'), 'utf8') - serverDir = join(appDir, '.next/server/static/', buildId, 'pages') }) afterAll(() => stopApp(server)) @@ -641,18 +638,21 @@ describe('Production Usage', () => { }) it('should replace static pages with HTML files', async () => { - const staticFiles = ['about', 'another', 'counter', 'dynamic', 'prefetch'] - for (const file of staticFiles) { - expect(existsSync(join(serverDir, file + '.html'))).toBe(true) - expect(existsSync(join(serverDir, file + '.js'))).toBe(false) + const pages = ['/about', '/another', '/counter', '/dynamic', '/prefetch'] + for (const page of pages) { + const file = getPageFileFromPagesManifest(appDir, page) + + expect(file.endsWith('.html')).toBe(true) } }) it('should not replace non-static pages with HTML files', async () => { - const nonStaticFiles = ['api', 'external-and-back', 'finish-response'] - for (const file of nonStaticFiles) { - expect(existsSync(join(serverDir, file + '.js'))).toBe(true) - expect(existsSync(join(serverDir, file + '.html'))).toBe(false) + const pages = ['/api', '/external-and-back', '/finish-response'] + + for (const page of pages) { + const file = getPageFileFromPagesManifest(appDir, page) + + expect(file.endsWith('.js')).toBe(true) } }) diff --git a/test/integration/serverless-trace/test/index.test.js b/test/integration/serverless-trace/test/index.test.js index db75f3bfd1..cf8967440a 100644 --- a/test/integration/serverless-trace/test/index.test.js +++ b/test/integration/serverless-trace/test/index.test.js @@ -11,6 +11,7 @@ import { fetchViaHTTP, renderViaHTTP, readNextBuildClientPageFile, + getPageFileFromPagesManifest, } from 'next-test-utils' import fetch from 'node-fetch' @@ -117,21 +118,23 @@ describe('Serverless Trace', () => { }) it('should replace static pages with HTML files', async () => { - const staticFiles = ['abc', 'dynamic', 'dynamic-two', 'some-amp'] - for (const file of staticFiles) { - expect(existsSync(join(serverlessDir, file + '.html'))).toBe(true) - expect(existsSync(join(serverlessDir, file + '.js'))).toBe(false) + const pages = ['/abc', '/dynamic', '/dynamic-two', '/some-amp'] + for (const page of pages) { + const file = getPageFileFromPagesManifest(appDir, page) + + expect(file.endsWith('.html')).toBe(true) } }) it('should not replace non-static pages with HTML files', async () => { - const nonStaticFiles = ['fetch', '_error'] - for (const file of nonStaticFiles) { - expect(existsSync(join(serverlessDir, file + '.js'))).toBe(true) - expect(existsSync(join(serverlessDir, file + '.html'))).toBe(false) + const pages = ['/fetch', '/_error'] + + for (const page of pages) { + const file = getPageFileFromPagesManifest(appDir, page) + + expect(file.endsWith('.js')).toBe(true) } }) - it('should reply on API request successfully', async () => { const content = await renderViaHTTP(appPort, '/api/hello') expect(content).toMatch(/hello world/) diff --git a/test/integration/serverless/test/index.test.js b/test/integration/serverless/test/index.test.js index b7cf8cc4d7..58dd322e67 100644 --- a/test/integration/serverless/test/index.test.js +++ b/test/integration/serverless/test/index.test.js @@ -13,6 +13,7 @@ import { fetchViaHTTP, renderViaHTTP, getPageFileFromBuildManifest, + getPageFileFromPagesManifest, } from 'next-test-utils' import qs from 'querystring' import path from 'path' @@ -186,18 +187,21 @@ describe('Serverless', () => { }) it('should replace static pages with HTML files', async () => { - const staticFiles = ['abc', 'dynamic', 'dynamic-two', 'some-amp'] - for (const file of staticFiles) { - expect(existsSync(join(serverlessDir, file + '.html'))).toBe(true) - expect(existsSync(join(serverlessDir, file + '.js'))).toBe(false) + const pages = ['/abc', '/dynamic', '/dynamic-two', '/some-amp'] + for (const page of pages) { + const file = getPageFileFromPagesManifest(appDir, page) + + expect(file.endsWith('.html')).toBe(true) } }) it('should not replace non-static pages with HTML files', async () => { - const nonStaticFiles = ['fetch', '_error'] - for (const file of nonStaticFiles) { - expect(existsSync(join(serverlessDir, file + '.js'))).toBe(true) - expect(existsSync(join(serverlessDir, file + '.html'))).toBe(false) + const pages = ['/fetch', '/_error'] + + for (const page of pages) { + const file = getPageFileFromPagesManifest(appDir, page) + + expect(file.endsWith('.js')).toBe(true) } }) diff --git a/test/integration/static-404/test/index.test.js b/test/integration/static-404/test/index.test.js index f66ca690b7..308d910fc9 100644 --- a/test/integration/static-404/test/index.test.js +++ b/test/integration/static-404/test/index.test.js @@ -13,10 +13,8 @@ import { jest.setTimeout(1000 * 60 * 2) const appDir = join(__dirname, '..') const nextConfig = join(appDir, 'next.config.js') -const static404 = join(appDir, '.next/server/static/test-id/pages/404.html') const appPage = join(appDir, 'pages/_app.js') const errorPage = join(appDir, 'pages/_error.js') -const buildId = `generateBuildId: () => 'test-id'` let app let appPort @@ -29,10 +27,6 @@ describe('Static 404 page', () => { beforeEach(() => fs.remove(join(appDir, '.next/server'))) describe('With config enabled', () => { - beforeEach(() => - fs.writeFile(nextConfig, `module.exports = { ${buildId} }`) - ) - it('should export 404 page without custom _error', async () => { await nextBuild(appDir) appPort = await findPort() @@ -40,7 +34,6 @@ describe('Static 404 page', () => { const html = await renderViaHTTP(appPort, '/non-existent') await killApp(app) expect(html).toContain('This page could not be found') - expect(await fs.exists(static404)).toBe(true) }) it('should export 404 page without custom _error (serverless)', async () => { @@ -58,9 +51,6 @@ describe('Static 404 page', () => { const html = await renderViaHTTP(appPort, '/non-existent') await killApp(app) expect(html).toContain('This page could not be found') - expect( - await fs.exists(join(appDir, '.next/serverless/pages/404.html')) - ).toBe(true) }) it('should not export 404 page with custom _error GIP', async () => { @@ -79,7 +69,6 @@ describe('Static 404 page', () => { ) await nextBuild(appDir) await fs.remove(errorPage) - expect(await fs.exists(static404)).toBe(false) }) it('should not export 404 page with getInitialProps in _app', async () => { @@ -95,7 +84,6 @@ describe('Static 404 page', () => { ) await nextBuild(appDir) await fs.remove(appPage) - expect(await fs.exists(static404)).toBe(false) }) }) }) diff --git a/test/lib/next-test-utils.js b/test/lib/next-test-utils.js index 62f90d3be1..a2f550b1a2 100644 --- a/test/lib/next-test-utils.js +++ b/test/lib/next-test-utils.js @@ -493,8 +493,12 @@ export function normalizeRegEx(src) { return new RegExp(src).source.replace(/\^\//g, '^\\/') } +function readJson(path) { + return JSON.parse(readFileSync(path)) +} + export function getBuildManifest(dir) { - return JSON.parse(readFileSync(path.join(dir, '.next/build-manifest.json'))) + return readJson(path.join(dir, '.next/build-manifest.json')) } export function getPageFileFromBuildManifest(dir, page) { @@ -522,7 +526,12 @@ export function readNextBuildClientPageFile(appDir, page) { } export function getPagesManifest(dir) { - return require(path.join(dir, '.next/server/pages-manifest.json')) + const serverFile = path.join(dir, '.next/server/pages-manifest.json') + + if (existsSync(serverFile)) { + return readJson(serverFile) + } + return readJson(path.join(dir, '.next/serverless/pages-manifest.json')) } export function getPageFileFromPagesManifest(dir, page) { -- GitLab