diff --git a/packages/next/build/webpack/loaders/next-serverless-loader.ts b/packages/next/build/webpack/loaders/next-serverless-loader.ts index 1c12085ceea96eae9011a8db4d6b522efdcad27b..a6493a4e111d18f4fb38027a263071494cc3df40 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader.ts @@ -142,6 +142,13 @@ const nextServerlessLoader: loader.Loader = function () { } ` + const handleBasePath = basePath + ? ` + // always strip the basePath if configured since it is required + req.url = req.url.replace(new RegExp('^${basePath}'), '') + ` + : '' + if (page.match(API_ROUTE)) { return ` import initServer from 'next-plugin-loader?middleware=on-init-server!' @@ -169,15 +176,7 @@ const nextServerlessLoader: loader.Loader = function () { try { await initServer() - ${ - basePath - ? ` - if(req.url.startsWith('${basePath}')) { - req.url = req.url.replace('${basePath}', '') - } - ` - : '' - } + ${handleBasePath} const parsedUrl = handleRewrites(parse(req.url, true)) const params = ${ @@ -259,15 +258,9 @@ const nextServerlessLoader: loader.Loader = function () { export const _app = App export async function renderReqToHTML(req, res, renderMode, _renderOpts, _params) { const fromExport = renderMode === 'export' || renderMode === true; - ${ - basePath - ? ` - if(req.url.startsWith('${basePath}')) { - req.url = req.url.replace('${basePath}', '') - } - ` - : '' - } + + ${handleBasePath} + const options = { App, Document, diff --git a/packages/next/next-server/lib/router/router.ts b/packages/next/next-server/lib/router/router.ts index bbd9bb95304b8c4eee3a376d2521a849989ced24..2a35f415af6965b9f4b1e1d47d94a7ee3e6bd9d2 100644 --- a/packages/next/next-server/lib/router/router.ts +++ b/packages/next/next-server/lib/router/router.ts @@ -232,7 +232,9 @@ export default class Router implements BaseRouter { // until after mount to prevent hydration mismatch this.asPath = // @ts-ignore this is temporarily global (attached to window) - isDynamicRoute(pathname) && __NEXT_DATA__.autoExport ? pathname : as + isDynamicRoute(pathname) && __NEXT_DATA__.autoExport + ? pathname + : delBasePath(as) this.basePath = basePath this.sub = subscription this.clc = null @@ -524,19 +526,21 @@ export default class Router implements BaseRouter { !(routeInfo.Component as any).getInitialProps } - this.set(route, pathname!, query, as, routeInfo).then(() => { - if (error) { - Router.events.emit('routeChangeError', error, as) - throw error - } + this.set(route, pathname!, query, delBasePath(as), routeInfo).then( + () => { + if (error) { + Router.events.emit('routeChangeError', error, as) + throw error + } - Router.events.emit('routeChangeComplete', as) + Router.events.emit('routeChangeComplete', as) - if (manualScrollRestoration && '_N_X' in options) { - window.scrollTo(options._N_X, options._N_Y) + if (manualScrollRestoration && '_N_X' in options) { + window.scrollTo(options._N_X, options._N_Y) + } + return resolve(true) } - return resolve(true) - }) + ) }, reject ) diff --git a/test/integration/basepath/pages/gssp.js b/test/integration/basepath/pages/gssp.js index 83737eadd4eaf21d528e4bedc9663e44c0652076..40a5f611cacd400b967c3bcfec615583dc0db2a8 100644 --- a/test/integration/basepath/pages/gssp.js +++ b/test/integration/basepath/pages/gssp.js @@ -14,5 +14,6 @@ export default (props) => (

getServerSideProps

{JSON.stringify(props)}

{useRouter().pathname}
+
{useRouter().asPath}
) diff --git a/test/integration/basepath/server.js b/test/integration/basepath/server.js new file mode 100644 index 0000000000000000000000000000000000000000..e2a5c822d800121b07dde990e2b82f1c25796f07 --- /dev/null +++ b/test/integration/basepath/server.js @@ -0,0 +1,24 @@ +const path = require('path') +const http = require('http') + +const server = http.createServer((req, res) => { + const pagePath = (page) => path.join('.next/serverless/pages/', page) + const render = (page) => { + require(`./${pagePath(page)}`).render(req, res) + } + + switch (req.url) { + case '/docs/gssp': { + return render('/gssp.js') + } + default: { + res.statusCode(404) + return res.end('404') + } + } +}) + +const port = process.env.PORT || 3000 +server.listen(port, () => { + console.log('ready on', port) +}) diff --git a/test/integration/basepath/test/index.test.js b/test/integration/basepath/test/index.test.js index 5a31e08164b7417c4f4003c5a61e7ef4d50c7b01..5244ff89c1e924713eb8f4b289e0aaf0cc04fc4c 100644 --- a/test/integration/basepath/test/index.test.js +++ b/test/integration/basepath/test/index.test.js @@ -17,6 +17,7 @@ import { renderViaHTTP, File, nextStart, + initNextServerScript, } from 'next-test-utils' import fs, { readFileSync, @@ -203,7 +204,9 @@ const runTests = (context, dev = false) => { expect(props.hello).toBe('world') const pathname = await browser.elementByCss('#pathname').text() + const asPath = await browser.elementByCss('#asPath').text() expect(pathname).toBe('/gssp') + expect(asPath).toBe('/gssp') }) it('should have correct href for a link', async () => { @@ -634,4 +637,24 @@ describe('basePath serverless', () => { }) runTests(context) + + it('should always strip basePath in serverless-loader', async () => { + const appPort = await findPort() + const app = await initNextServerScript( + join(appDir, 'server.js'), + /ready on/, + { + ...process.env, + PORT: appPort, + } + ) + + const html = await renderViaHTTP(appPort, '/docs/gssp') + await killApp(app) + + const $ = cheerio.load(html) + + expect($('#pathname').text()).toBe('/gssp') + expect($('#asPath').text()).toBe('/gssp') + }) })