未验证 提交 3d6d033a 编写于 作者: J JJ Kasper 提交者: GitHub

Normalize asPath between SSR and CSR with basePath (#14040)

To make `asPath` consistent with `basePath` handling this makes sure it is always stripped including on the client under the `asPath` value and from `req.url` in the `serverless-loader`. Additional tests have been added for this behavior to ensure we don't regress on this

Closes: https://github.com/vercel/next.js/issues/14037
Closes: https://github.com/vercel/next.js/issues/14039
上级 90638c70
......@@ -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,
......
......@@ -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
)
......
......@@ -14,5 +14,6 @@ export default (props) => (
<h3 id="gssp">getServerSideProps</h3>
<p id="props">{JSON.stringify(props)}</p>
<div id="pathname">{useRouter().pathname}</div>
<div id="asPath">{useRouter().asPath}</div>
</>
)
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)
})
......@@ -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')
})
})
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册