未验证 提交 5b70802f 编写于 作者: J JJ Kasper 提交者: GitHub

Preserve asPath while resolving rewrites (#21410)

* Preserve asPath while resolving rewrites

* remove un-needed alias

* Add new alias

* Add return type for resolve rewrites
上级 9fd9d832
...@@ -213,7 +213,7 @@ export default async function getBaseWebpackConfig( ...@@ -213,7 +213,7 @@ export default async function getBaseWebpackConfig(
let plugins: PluginMetaData[] = [] let plugins: PluginMetaData[] = []
let babelPresetPlugins: { dir: string; config: any }[] = [] let babelPresetPlugins: { dir: string; config: any }[] = []
const hasRewrites = rewrites.length > 0 || dev const hasRewrites = rewrites.length > 0
if (config.experimental.plugins) { if (config.experimental.plugins) {
plugins = await collectPlugins(dir, config.env, config.plugins) plugins = await collectPlugins(dir, config.env, config.plugins)
...@@ -344,6 +344,9 @@ export default async function getBaseWebpackConfig( ...@@ -344,6 +344,9 @@ export default async function getBaseWebpackConfig(
const clientResolveRewrites = require.resolve( const clientResolveRewrites = require.resolve(
'next/dist/next-server/lib/router/utils/resolve-rewrites' 'next/dist/next-server/lib/router/utils/resolve-rewrites'
) )
const clientResolveRewritesNoop = require.resolve(
'next/dist/next-server/lib/router/utils/resolve-rewrites-noop'
)
const resolveConfig = { const resolveConfig = {
// Disable .mjs for node_modules bundling // Disable .mjs for node_modules bundling
...@@ -385,7 +388,7 @@ export default async function getBaseWebpackConfig( ...@@ -385,7 +388,7 @@ export default async function getBaseWebpackConfig(
...getReactProfilingInProduction(), ...getReactProfilingInProduction(),
[clientResolveRewrites]: hasRewrites [clientResolveRewrites]: hasRewrites
? clientResolveRewrites ? clientResolveRewrites
: require.resolve('next/dist/client/dev/noop.js'), : clientResolveRewritesNoop,
}, },
mainFields: isServer ? ['main', 'module'] : ['browser', 'module', 'main'], mainFields: isServer ? ['main', 'module'] : ['browser', 'module', 'main'],
plugins: isWebpack5 plugins: isWebpack5
......
...@@ -932,39 +932,23 @@ export default class Router implements BaseRouter { ...@@ -932,39 +932,23 @@ export default class Router implements BaseRouter {
let resolvedAs = as let resolvedAs = as
if (process.env.__NEXT_HAS_REWRITES && as.startsWith('/')) { if (process.env.__NEXT_HAS_REWRITES && as.startsWith('/')) {
resolvedAs = resolveRewrites( const rewritesResult = resolveRewrites(
addBasePath( addBasePath(addLocale(delBasePath(as), this.locale)),
addLocale(delBasePath(parseRelativeUrl(as).pathname), this.locale)
),
pages, pages,
rewrites, rewrites,
query, query,
(p: string) => this._resolveHref({ pathname: p }, pages).pathname!, (p: string) => this._resolveHref({ pathname: p }, pages).pathname!,
this.locales this.locales
) )
resolvedAs = rewritesResult.asPath
if (resolvedAs !== as) { if (rewritesResult.matchedPage && rewritesResult.resolvedHref) {
const potentialHref = removePathTrailingSlash(
this._resolveHref(
Object.assign({}, parsed, {
pathname: normalizeLocalePath(
hasBasePath(resolvedAs) ? delBasePath(resolvedAs) : resolvedAs,
this.locales
).pathname,
}),
pages,
false
).pathname!
)
// if this directly matches a page we need to update the href to // if this directly matches a page we need to update the href to
// allow the correct page chunk to be loaded // allow the correct page chunk to be loaded
if (pages.includes(potentialHref)) { route = rewritesResult.resolvedHref
route = potentialHref pathname = rewritesResult.resolvedHref
pathname = potentialHref parsed.pathname = pathname
parsed.pathname = pathname url = formatWithValidation(parsed)
url = formatWithValidation(parsed)
}
} }
} }
...@@ -1045,7 +1029,8 @@ export default class Router implements BaseRouter { ...@@ -1045,7 +1029,8 @@ export default class Router implements BaseRouter {
route, route,
pathname, pathname,
query, query,
addBasePath(addLocale(resolvedAs, this.locale)), as,
resolvedAs,
routeProps routeProps
) )
let { error, props, __N_SSG, __N_SSP } = routeInfo let { error, props, __N_SSG, __N_SSP } = routeInfo
...@@ -1092,6 +1077,7 @@ export default class Router implements BaseRouter { ...@@ -1092,6 +1077,7 @@ export default class Router implements BaseRouter {
notFoundRoute, notFoundRoute,
query, query,
as, as,
resolvedAs,
{ shallow: false } { shallow: false }
) )
} }
...@@ -1259,6 +1245,7 @@ export default class Router implements BaseRouter { ...@@ -1259,6 +1245,7 @@ export default class Router implements BaseRouter {
pathname: string, pathname: string,
query: any, query: any,
as: string, as: string,
resolvedAs: string,
routeProps: RouteProperties routeProps: RouteProperties
): Promise<PrivateRouteInfo> { ): Promise<PrivateRouteInfo> {
try { try {
...@@ -1298,7 +1285,7 @@ export default class Router implements BaseRouter { ...@@ -1298,7 +1285,7 @@ export default class Router implements BaseRouter {
if (__N_SSG || __N_SSP) { if (__N_SSG || __N_SSP) {
dataHref = this.pageLoader.getDataHref( dataHref = this.pageLoader.getDataHref(
formatWithValidation({ pathname, query }), formatWithValidation({ pathname, query }),
delBasePath(as), resolvedAs,
__N_SSG, __N_SSG,
this.locale this.locale
) )
......
...@@ -4,6 +4,8 @@ import prepareDestination from './prepare-destination' ...@@ -4,6 +4,8 @@ import prepareDestination from './prepare-destination'
import { Rewrite } from '../../../../lib/load-custom-routes' import { Rewrite } from '../../../../lib/load-custom-routes'
import { removePathTrailingSlash } from '../../../../client/normalize-trailing-slash' import { removePathTrailingSlash } from '../../../../client/normalize-trailing-slash'
import { normalizeLocalePath } from '../../i18n/normalize-locale-path' import { normalizeLocalePath } from '../../i18n/normalize-locale-path'
import { parseRelativeUrl } from './parse-relative-url'
import { delBasePath } from '../router'
const customRouteMatcher = pathMatch(true) const customRouteMatcher = pathMatch(true)
...@@ -14,11 +16,23 @@ export default function resolveRewrites( ...@@ -14,11 +16,23 @@ export default function resolveRewrites(
query: ParsedUrlQuery, query: ParsedUrlQuery,
resolveHref: (path: string) => string, resolveHref: (path: string) => string,
locales?: string[] locales?: string[]
) { ): {
if (!pages.includes(normalizeLocalePath(asPath, locales).pathname)) { matchedPage: boolean
parsedAs: ReturnType<typeof parseRelativeUrl>
asPath: string
resolvedHref?: string
} {
let matchedPage = false
let parsedAs = parseRelativeUrl(asPath)
let fsPathname = removePathTrailingSlash(
normalizeLocalePath(delBasePath(parsedAs.pathname), locales).pathname
)
let resolvedHref
if (!pages.includes(fsPathname)) {
for (const rewrite of rewrites) { for (const rewrite of rewrites) {
const matcher = customRouteMatcher(rewrite.source) const matcher = customRouteMatcher(rewrite.source)
const params = matcher(asPath) const params = matcher(parsedAs.pathname)
if (params) { if (params) {
if (!rewrite.destination) { if (!rewrite.destination) {
...@@ -31,30 +45,36 @@ export default function resolveRewrites( ...@@ -31,30 +45,36 @@ export default function resolveRewrites(
query, query,
true true
) )
asPath = destRes.parsedDestination.pathname! parsedAs = destRes.parsedDestination
asPath = destRes.newUrl
Object.assign(query, destRes.parsedDestination.query) Object.assign(query, destRes.parsedDestination.query)
const fsPathname = normalizeLocalePath( fsPathname = removePathTrailingSlash(
removePathTrailingSlash(asPath), normalizeLocalePath(delBasePath(asPath), locales).pathname
locales )
).pathname
if (pages.includes(fsPathname)) { if (pages.includes(fsPathname)) {
asPath = fsPathname
// check if we now match a page as this means we are done // check if we now match a page as this means we are done
// resolving the rewrites // resolving the rewrites
matchedPage = true
resolvedHref = fsPathname
break break
} }
// check if we match a dynamic-route, if so we break the rewrites chain // check if we match a dynamic-route, if so we break the rewrites chain
const resolvedHref = resolveHref(fsPathname) resolvedHref = resolveHref(fsPathname)
if (resolvedHref !== asPath && pages.includes(resolvedHref)) { if (resolvedHref !== asPath && pages.includes(resolvedHref)) {
asPath = fsPathname matchedPage = true
break break
} }
} }
} }
} }
return asPath return {
asPath,
parsedAs,
matchedPage,
resolvedHref,
}
} }
...@@ -94,7 +94,13 @@ const runTests = () => { ...@@ -94,7 +94,13 @@ const runTests = () => {
await browser.elementByCss('#to-about').click() await browser.elementByCss('#to-about').click()
await check(async () => { await check(async () => {
const data = JSON.parse(await browser.elementByCss('#data').text()) const data = JSON.parse(
cheerio
.load(await browser.eval('document.documentElement.innerHTML'))(
'#data'
)
.text()
)
console.log(data) console.log(data)
return data.url === `${expectedIndex ? '/fr' : ''}/about` return data.url === `${expectedIndex ? '/fr' : ''}/about`
? 'success' ? 'success'
...@@ -108,7 +114,13 @@ const runTests = () => { ...@@ -108,7 +114,13 @@ const runTests = () => {
.click() .click()
await check(async () => { await check(async () => {
const data = JSON.parse(await browser.elementByCss('#data').text()) const data = JSON.parse(
cheerio
.load(await browser.eval('document.documentElement.innerHTML'))(
'#data'
)
.text()
)
console.log(data) console.log(data)
return data.url === `${expectedIndex ? '/fr' : ''}/hello` return data.url === `${expectedIndex ? '/fr' : ''}/hello`
? 'success' ? 'success'
......
...@@ -10,6 +10,7 @@ import { ...@@ -10,6 +10,7 @@ import {
stopApp, stopApp,
waitFor, waitFor,
getPageFileFromPagesManifest, getPageFileFromPagesManifest,
check,
} from 'next-test-utils' } from 'next-test-utils'
import webdriver from 'next-webdriver' import webdriver from 'next-webdriver'
import { import {
...@@ -860,6 +861,27 @@ describe('Production Usage', () => { ...@@ -860,6 +861,27 @@ describe('Production Usage', () => {
expect(missing).toBe(false) expect(missing).toBe(false)
}) })
it('should preserve query when hard navigating from page 404', async () => {
const browser = await webdriver(appPort, '/')
await browser.eval(`(function() {
window.beforeNav = 1
window.next.router.push({
pathname: '/non-existent',
query: { hello: 'world' }
})
})()`)
await check(
() => browser.eval('document.documentElement.innerHTML'),
/page could not be found/
)
expect(await browser.eval('window.beforeNav')).toBe(null)
expect(await browser.eval('window.location.hash')).toBe('')
expect(await browser.eval('window.location.search')).toBe('?hello=world')
expect(await browser.eval('window.location.pathname')).toBe('/non-existent')
})
dynamicImportTests(context, (p, q) => renderViaHTTP(context.appPort, p, q)) dynamicImportTests(context, (p, q) => renderViaHTTP(context.appPort, p, q))
processEnv(context) processEnv(context)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册