diff --git a/server/index.js b/server/index.js index a1436ed5..401773c6 100644 --- a/server/index.js +++ b/server/index.js @@ -150,41 +150,42 @@ export default class Server { } } + // In development we expose all compiled files for react-error-overlay's line show feature + if (this.dev) { + routes['/_next/development/:path*'] = async (req, res, params) => { + const p = join(this.distDir, ...(params.path || [])) + console.log('page', p) + await this.serveStatic(req, res, p) + } + } + + // This path is needed because `render()` does a check for `/_next` and the calls the routing again + routes['/_next/:path*'] = async (req, res, params, parsedUrl) => { + await this.render404(req, res, parsedUrl) + } + + // Makes `next export` exportPathMap work in development mode. + // So that the user doesn't have to define a custom server reading the exportPathMap + if (this.dev && this.nextConfig.exportPathMap) { + console.log('Defining routes from exportPathMap') + const exportPathMap = await this.nextConfig.exportPathMap({}, {dev: true, dir: this.dir, outDir: null, distDir: this.distDir, buildId: this.buildId}) // In development we can't give a default path mapping + for (const path in exportPathMap) { + const {page, query = {}} = exportPathMap[path] + routes[path] = async (req, res, params, parsedUrl) => { + const { query: urlQuery } = parsedUrl + + Object.keys(urlQuery) + .filter(key => query[key] === undefined) + .forEach(key => console.warn(`Url defines a query parameter '${key}' that is missing in exportPathMap`)) + + const mergedQuery = {...urlQuery, ...query} + + await this.render(req, res, page, mergedQuery, parsedUrl) + } + } + } + if (this.nextConfig.useFileSystemPublicRoutes) { - // Makes `next export` exportPathMap work in development mode. - // So that the user doesn't have to define a custom server reading the exportPathMap - if (this.dev && this.nextConfig.exportPathMap) { - console.log('Defining routes from exportPathMap') - const exportPathMap = await this.nextConfig.exportPathMap({}, {dev: true, dir: this.dir, outDir: null, distDir: this.distDir, buildId: this.buildId}) // In development we can't give a default path mapping - for (const path in exportPathMap) { - const {page, query = {}} = exportPathMap[path] - routes[path] = async (req, res, params, parsedUrl) => { - const { query: urlQuery } = parsedUrl - - Object.keys(urlQuery) - .filter(key => query[key] === undefined) - .forEach(key => console.warn(`Url defines a query parameter '${key}' that is missing in exportPathMap`)) - - const mergedQuery = {...urlQuery, ...query} - - await this.render(req, res, page, mergedQuery, parsedUrl) - } - } - } - - // In development we expose all compiled files for react-error-overlay's line show feature - if (this.dev) { - routes['/_next/development/:path*'] = async (req, res, params) => { - const p = join(this.distDir, ...(params.path || [])) - await this.serveStatic(req, res, p) - } - } - - // This path is needed because `render()` does a check for `/_next` and the calls the routing again - routes['/_next/:path*'] = async (req, res, params, parsedUrl) => { - await this.render404(req, res, parsedUrl) - } - // It's very important keep this route's param optional. // (but it should support as many as params, seperated by '/') // Othewise this will lead to a pretty simple DOS attack. diff --git a/test/integration/basic/test/rendering.js b/test/integration/basic/test/rendering.js index e662c138..5371aad8 100644 --- a/test/integration/basic/test/rendering.js +++ b/test/integration/basic/test/rendering.js @@ -128,6 +128,19 @@ export default function ({ app }, suiteName, render, fetch, appPort) { expect(res.status).toBe(404) }) + test('should expose the compiled page file in development', async () => { + await fetch('/stateless') // make sure the stateless page is built + const clientSideJsRes = await fetch('/_next/development/static/development/pages/stateless.js') + 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('Zeit')).toBeTruthy() diff --git a/test/integration/filesystempublicroutes/next.config.js b/test/integration/filesystempublicroutes/next.config.js new file mode 100644 index 00000000..7e9b9ec9 --- /dev/null +++ b/test/integration/filesystempublicroutes/next.config.js @@ -0,0 +1,12 @@ +module.exports = { + onDemandEntries: { + // Make sure entries are not getting disposed. + maxInactiveAge: 1000 * 60 * 60 + }, + useFileSystemPublicRoutes: false, + exportPathMap () { + return { + '/exportpathmap-route': {page: '/exportpathmap-route'} + } + } +} diff --git a/test/integration/filesystempublicroutes/pages/exportpathmap-route.js b/test/integration/filesystempublicroutes/pages/exportpathmap-route.js new file mode 100644 index 00000000..1137e041 --- /dev/null +++ b/test/integration/filesystempublicroutes/pages/exportpathmap-route.js @@ -0,0 +1 @@ +export default () =>