mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
fix: handle route encoding (#8325)
Co-authored-by: farnabaz <farnabaz@users.noreply.github.com>
This commit is contained in:
parent
7cac3c7fc9
commit
cc1f6d94b5
@ -63,7 +63,7 @@
|
||||
"vue-client-only": "^2.0.0",
|
||||
"vue-meta": "^2.4.0",
|
||||
"vue-no-ssr": "^1.1.1",
|
||||
"vue-router": "3.4.8",
|
||||
"vue-router": "^3.4.9",
|
||||
"vuex": "^3.5.1"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -126,6 +126,7 @@ export function getNuxtConfig (_options) {
|
||||
if (!/\/$/.test(options.router.base)) {
|
||||
options.router.base += '/'
|
||||
}
|
||||
options.router.base = encodeURI(decodeURI(options.router.base))
|
||||
|
||||
// Legacy support for export
|
||||
if (options.export) {
|
||||
|
@ -50,6 +50,7 @@ export default class Listener {
|
||||
}
|
||||
this.port = address.port
|
||||
this.url = `http${this.https ? 's' : ''}://${this.host}:${this.port}${this.baseURL}`
|
||||
this.url = decodeURI(this.url)
|
||||
return
|
||||
}
|
||||
this.url = `unix+http://${address}`
|
||||
|
@ -167,7 +167,7 @@ export default class Server {
|
||||
prefix: false,
|
||||
handler: (req, res) => {
|
||||
const to = urlJoin(this.nuxt.options.router.base, req.url)
|
||||
consola.info(`[Development] Redirecting from \`${req.url}\` to \`${to}\` (router.base specified).`)
|
||||
consola.info(`[Development] Redirecting from \`${decodeURI(req.url)}\` to \`${decodeURI(to)}\` (router.base specified).`)
|
||||
res.writeHead(302, {
|
||||
Location: to
|
||||
})
|
||||
|
@ -19,7 +19,7 @@
|
||||
"vue-client-only": "^2.0.0",
|
||||
"vue-meta": "^2.4.0",
|
||||
"vue-no-ssr": "^1.1.1",
|
||||
"vue-router": "3.4.8",
|
||||
"vue-router": "^3.4.9",
|
||||
"vue-template-compiler": "^2.6.12",
|
||||
"vuex": "^3.5.1"
|
||||
},
|
||||
|
@ -47,7 +47,7 @@ import scrollBehavior from './router.scrollBehavior.js'
|
||||
}
|
||||
// @see: https://router.vuejs.org/api/#router-construction-options
|
||||
res += '{'
|
||||
res += firstIndent + 'path: ' + JSON.stringify(route.path)
|
||||
res += firstIndent + 'path: ' + JSON.stringify(encodeURI(decodeURI(route.path)))
|
||||
res += (route.components) ? nextIndent + 'components: {' + resMap + '\n' + baseIndent + tab + '}' : ''
|
||||
res += (route.component) ? nextIndent + 'component: ' + route._name : ''
|
||||
res += (route.redirect) ? nextIndent + 'redirect: ' + JSON.stringify(route.redirect) : ''
|
||||
@ -93,7 +93,7 @@ Vue.use(Router)
|
||||
|
||||
export const routerOptions = {
|
||||
mode: '<%= router.mode %>',
|
||||
base: decodeURI('<%= router.base %>'),
|
||||
base: '<%= router.base %>',
|
||||
linkActiveClass: '<%= router.linkActiveClass %>',
|
||||
linkExactActiveClass: '<%= router.linkExactActiveClass %>',
|
||||
scrollBehavior,
|
||||
@ -106,5 +106,16 @@ export const routerOptions = {
|
||||
}
|
||||
|
||||
export function createRouter () {
|
||||
return new Router(routerOptions)
|
||||
const router = new Router(routerOptions)
|
||||
const resolve = router.resolve.bind(router)
|
||||
|
||||
// encodeURI(decodeURI()) ~> support both encoded and non-encoded urls
|
||||
router.resolve = (to, current, append) => {
|
||||
if (typeof to === 'string') {
|
||||
to = encodeURI(decodeURI(to))
|
||||
}
|
||||
return resolve(to, current, append)
|
||||
}
|
||||
|
||||
return router
|
||||
}
|
||||
|
@ -7,7 +7,8 @@ import {
|
||||
<% if (features.middleware) { %>middlewareSeries,<% } %>
|
||||
<% if (features.middleware && features.layouts) { %>sanitizeComponent,<% } %>
|
||||
getMatchedComponents,
|
||||
promisify
|
||||
promisify,
|
||||
ensureURIEncoded
|
||||
} from './utils.js'
|
||||
<% if (features.fetch) { %>import fetchMixin from './mixins/fetch.server'<% } %>
|
||||
import { createApp<% if (features.layouts) { %>, NuxtError<% } %> } from './index.js'
|
||||
@ -50,7 +51,7 @@ const createNext = ssrContext => (opts) => {
|
||||
opts.path = urlJoin(routerBase, opts.path)
|
||||
}
|
||||
// Avoid loop redirect
|
||||
if (decodeURIComponent(opts.path) === ssrContext.url) {
|
||||
if (encodeURI(decodeURI(opts.path)) === ssrContext.url) {
|
||||
ssrContext.redirected = false
|
||||
return
|
||||
}
|
||||
|
@ -296,15 +296,20 @@ export function promisify (fn, context) {
|
||||
|
||||
// Imported from vue-router
|
||||
export function getLocation (base, mode) {
|
||||
let path = decodeURI(window.location.pathname)
|
||||
if (mode === 'hash') {
|
||||
return window.location.hash.replace(/^#\//, '')
|
||||
}
|
||||
// To get matched with sanitized router.base add trailing slash
|
||||
if (base && (path.endsWith('/') ? path : path + '/').startsWith(base)) {
|
||||
|
||||
base = decodeURI(base).slice(0, -1) // consideration is base is normalized with trailing slash
|
||||
let path = decodeURI(window.location.pathname)
|
||||
|
||||
if (base && path.startsWith(base)) {
|
||||
path = path.slice(base.length)
|
||||
}
|
||||
return (path || '/') + window.location.search + window.location.hash
|
||||
|
||||
const fullPath = (path || '/') + window.location.search + window.location.hash
|
||||
|
||||
return encodeURI(fullPath)
|
||||
}
|
||||
|
||||
// Imported from path-to-regexp
|
||||
|
@ -274,7 +274,8 @@ export default class VueRenderer {
|
||||
consola.debug(`Rendering url ${url}`)
|
||||
|
||||
// Add url to the renderContext
|
||||
renderContext.url = url
|
||||
renderContext.url = encodeURI(decodeURI(url))
|
||||
|
||||
// Add target to the renderContext
|
||||
renderContext.target = this.options.target
|
||||
|
||||
|
@ -5,9 +5,9 @@ const url = route => 'http://localhost:' + port + encodeURI(route)
|
||||
|
||||
let nuxt = null
|
||||
|
||||
describe('unicode-base', () => {
|
||||
describe('encoding', () => {
|
||||
beforeAll(async () => {
|
||||
const config = await loadFixture('unicode-base')
|
||||
const config = await loadFixture('encoding')
|
||||
nuxt = new Nuxt(config)
|
||||
await nuxt.ready()
|
||||
|
||||
@ -18,7 +18,7 @@ describe('unicode-base', () => {
|
||||
test('/ö/ (router base)', async () => {
|
||||
const { body: response } = await rp(url('/ö/'))
|
||||
|
||||
expect(response).toContain('<h1>Unicode base works!</h1>')
|
||||
expect(response).toContain('Unicode base works!')
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
@ -1,26 +0,0 @@
|
||||
import { resolve } from 'path'
|
||||
import { getResourcesSize } from '../utils'
|
||||
|
||||
const distDir = resolve(__dirname, '../fixtures/unicode-base/.nuxt/dist')
|
||||
|
||||
describe('nuxt minimal vue-app bundle size limit', () => {
|
||||
expect.extend({
|
||||
toBeWithinSize (received, size) {
|
||||
const maxSize = size * 1.02
|
||||
const minSize = size * 0.98
|
||||
const pass = received >= minSize && received <= maxSize
|
||||
return {
|
||||
pass,
|
||||
message: () =>
|
||||
`expected ${received} to be within range ${minSize} - ${maxSize}`
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should stay within the size limit range', async () => {
|
||||
const filter = filename => filename === 'vue-app.nuxt.js'
|
||||
const legacyResourcesSize = await getResourcesSize(distDir, 'client', { filter })
|
||||
const LEGACY_JS_RESOURCES_KB_SIZE = 17.1
|
||||
expect(legacyResourcesSize.uncompressed).toBeWithinSize(LEGACY_JS_RESOURCES_KB_SIZE)
|
||||
})
|
||||
})
|
@ -1,3 +1,3 @@
|
||||
import { buildFixture } from '../../utils/build'
|
||||
|
||||
buildFixture('unicode-base')
|
||||
buildFixture('encoding')
|
32
test/fixtures/encoding/layouts/default.vue
vendored
Normal file
32
test/fixtures/encoding/layouts/default.vue
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<NLink to="/тест">
|
||||
/тест
|
||||
</NLink>
|
||||
<NLink :to="encodeURI('/тест')">
|
||||
/тест (encoded)
|
||||
</NLink>
|
||||
<br>
|
||||
<NLink to="/тест?spa">
|
||||
/тест (SPA)
|
||||
</NLink>
|
||||
<NLink :to="encodeURI('/тест?spa')">
|
||||
/тест (SPA encoded)
|
||||
</NLink>
|
||||
</div>
|
||||
<Nuxt />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
a {
|
||||
color: grey;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nuxt-link-exact-active {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
12
test/fixtures/encoding/nuxt.config.js
vendored
Normal file
12
test/fixtures/encoding/nuxt.config.js
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
export default {
|
||||
router: {
|
||||
base: '/ö/'
|
||||
},
|
||||
hooks: {
|
||||
'vue-renderer:context' (ssrContext) {
|
||||
if (ssrContext.url.includes('?spa')) {
|
||||
ssrContext.spa = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
5
test/fixtures/encoding/pages/index.vue
vendored
Normal file
5
test/fixtures/encoding/pages/index.vue
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
Unicode base works!
|
||||
</div>
|
||||
</template>
|
43
test/fixtures/unicode-base/nuxt.config.js
vendored
43
test/fixtures/unicode-base/nuxt.config.js
vendored
@ -1,43 +0,0 @@
|
||||
export default {
|
||||
modern: 'server',
|
||||
router: {
|
||||
base: '/%C3%B6/'
|
||||
},
|
||||
loading: false,
|
||||
loadingIndicator: false,
|
||||
fetch: {
|
||||
client: false,
|
||||
server: false
|
||||
},
|
||||
features: {
|
||||
store: false,
|
||||
layouts: false,
|
||||
meta: false,
|
||||
middleware: false,
|
||||
transitions: false,
|
||||
deprecations: false,
|
||||
validate: false,
|
||||
asyncData: false,
|
||||
fetch: false,
|
||||
clientOnline: false,
|
||||
clientPrefetch: false,
|
||||
clientUseUrl: true,
|
||||
componentAliases: false,
|
||||
componentClientOnly: false
|
||||
},
|
||||
build: {
|
||||
indicator: false,
|
||||
terser: true,
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
cacheGroups: {
|
||||
nuxtApp: {
|
||||
test: /[\\/]\.nuxt[\\/]/,
|
||||
filename: 'vue-app.nuxt.js',
|
||||
enforce: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -13403,6 +13403,11 @@ vue-router@3.4.8:
|
||||
resolved "https://registry.npmjs.org/vue-router/-/vue-router-3.4.8.tgz#2c06261d35d8075893470352d42d70b6287b8194"
|
||||
integrity sha512-3BsR84AqarcmweXjItxw3jwQsiYNssYg090yi4rlzTnCJxmHtkyCvhNz9Z7qRSOkmiV485KkUCReTp5AjNY4wg==
|
||||
|
||||
vue-router@^3.4.9:
|
||||
version "3.4.9"
|
||||
resolved "https://registry.npmjs.org/vue-router/-/vue-router-3.4.9.tgz#c016f42030ae2932f14e4748b39a1d9a0e250e66"
|
||||
integrity sha512-CGAKWN44RqXW06oC+u4mPgHLQQi2t6vLD/JbGRDAXm0YpMv0bgpKuU5bBd7AvMgfTz9kXVRIWKHqRwGEb8xFkA==
|
||||
|
||||
vue-server-renderer@^2.6.12:
|
||||
version "2.6.12"
|
||||
resolved "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.6.12.tgz#a8cb9c49439ef205293cb41c35d0d2b0541653a5"
|
||||
|
Loading…
Reference in New Issue
Block a user