From: Eduardo San Martin Morote Date: Mon, 13 Apr 2020 14:20:00 +0000 (+0200) Subject: fix(history): allow base with / and base tag X-Git-Tag: v4.0.0-alpha.6~29 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d7c71b55ee4a11ecaf3a72f25eb126d118829d3f;p=thirdparty%2Fvuejs%2Frouter.git fix(history): allow base with / and base tag Close #164 --- diff --git a/__tests__/history/html5.spec.ts b/__tests__/history/html5.spec.ts index 606deee1..e0b48448 100644 --- a/__tests__/history/html5.spec.ts +++ b/__tests__/history/html5.spec.ts @@ -1,11 +1,24 @@ +import { JSDOM } from 'jsdom' import createWebHistory from '../../src/history/html5' import { createDom } from '../utils' // These unit tests are supposed to tests very specific scenarios that are easier to setup // on a unit test than an e2e tests describe('History HTMl5', () => { + let dom: JSDOM beforeAll(() => { - createDom() + dom = createDom() + }) + + afterAll(() => { + dom.window.close() + }) + + afterEach(() => { + // ensure no base element is left after a test as only the first is + // respected + for (let element of Array.from(document.getElementsByTagName('base'))) + element.remove() }) // this problem is very common on hash history when using a regular link @@ -17,4 +30,42 @@ describe('History HTMl5', () => { fullPath: '/', }) }) + + it('handles a basic base', () => { + expect(createWebHistory().base).toBe('') + expect(createWebHistory('/').base).toBe('') + }) + + it('handles a base tag', () => { + const baseEl = document.createElement('base') + baseEl.href = '/foo/' + document.head.appendChild(baseEl) + expect(createWebHistory().base).toBe('/foo') + }) + + it('handles a base tag with origin', () => { + const baseEl = document.createElement('base') + baseEl.href = 'https://example.com/foo/' + document.head.appendChild(baseEl) + expect(createWebHistory().base).toBe('/foo') + }) + + it('handles a base tag with origin without trailing slash', () => { + const baseEl = document.createElement('base') + baseEl.href = 'https://example.com/bar' + document.head.appendChild(baseEl) + expect(createWebHistory().base).toBe('/bar') + }) + + it('ignores base tag if base is provided', () => { + const baseEl = document.createElement('base') + baseEl.href = '/foo/' + document.head.appendChild(baseEl) + expect(createWebHistory('/bar/').base).toBe('/bar') + }) + + it('handles a non-empty base', () => { + expect(createWebHistory('/foo/').base).toBe('/foo') + expect(createWebHistory('/foo').base).toBe('/foo') + }) }) diff --git a/jest.config.js b/jest.config.js index 63ee84ff..7b070c13 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,6 +2,7 @@ module.exports = { preset: 'ts-jest', globals: { __DEV__: true, + __BROWSER__: true, }, coverageDirectory: 'coverage', coverageReporters: ['html', 'lcov', 'text'], diff --git a/src/history/html5.ts b/src/history/html5.ts index 84752344..8ac97dd4 100644 --- a/src/history/html5.ts +++ b/src/history/html5.ts @@ -262,7 +262,36 @@ function useHistoryStateNavigation(base: string) { } } -export default function createWebHistory(base: string = ''): RouterHistory { +/** + * Normalizes a base by removing any trailing slash and reading the base tag if + * present. + * + * @param base base to normalize + */ +function normalizeBase(base?: string): string { + if (!base) { + if (__BROWSER__) { + // respect tag + const baseEl = document.querySelector('base') + base = (baseEl && baseEl.getAttribute('href')) || '/' + // strip full URL origin + base = base.replace(/^\w+:\/\/[^\/]+/, '') + } else { + base = '/' + } + } + + // ensure leading slash when it was removed by the regex above + if (base.charAt(0) !== '/') base = '/' + base + + // remove the trailing slash so all other method can just do `base + fullPath` + // to build an href + return base.replace(/\/$/, '') +} + +export default function createWebHistory(base?: string): RouterHistory { + base = normalizeBase(base) + const historyNavigation = useHistoryStateNavigation(base) const historyListeners = useHistoryListeners( base, @@ -283,7 +312,7 @@ export default function createWebHistory(base: string = ''): RouterHistory { const routerHistory: RouterHistory = { // it's overridden right after // @ts-ignore - location: historyNavigation.location.value, + location: '', base, back, forward,