pull/869/head
Georges Gomes 3 years ago
parent a689f6b6d3
commit 2e4a33eb82

@ -6,6 +6,7 @@ export default defineConfig({
description: 'Vite & Vue powered static site generator.', description: 'Vite & Vue powered static site generator.',
lastUpdated: true, lastUpdated: true,
cleanUrls: true,
themeConfig: { themeConfig: {
nav: nav(), nav: nav(),

@ -42,9 +42,14 @@ export function createRouter(
function go(href: string = inBrowser ? location.href : '/') { function go(href: string = inBrowser ? location.href : '/') {
// ensure correct deep link so page refresh lands on correct files. // ensure correct deep link so page refresh lands on correct files.
const url = new URL(href, fakeHost) const url = new URL(href, fakeHost)
if (!url.pathname.endsWith('/') && !url.pathname.endsWith('.html')) { // ensure correct deep link so page refresh lands on correct files.
url.pathname += '.html' if (siteDataRef.value.cleanUrls) {
href = url.pathname + url.search + url.hash // Should we replace `/foo.html` -> `/foo` ? :thinking:
} else {
if (!url.pathname.endsWith('/') && !url.pathname.endsWith('.html')) {
url.pathname += '.html'
href = url.pathname + url.search + url.hash
}
} }
if (inBrowser) { if (inBrowser) {
// save scroll position before changing url // save scroll position before changing url
@ -101,7 +106,12 @@ export function createRouter(
} }
} }
} catch (err: any) { } catch (err: any) {
if (!err.message.match(/fetch/) && !href.match(/^[\\/]404\.html$/)) { if (
!err.message.match(/fetch/) &&
(siteDataRef.value.cleanUrls
? !href.match(/^[\\/]404$/)
: !href.match(/^[\\/]404\.html$/))
) {
console.error(err) console.error(err)
} }

@ -165,11 +165,22 @@ export async function renderPage(
${inlinedScript} ${inlinedScript}
</body> </body>
</html>`.trim() </html>`.trim()
const htmlFileName = path.join(config.outDir, page.replace(/\.md$/, '.html')) const htmlFileName = path.join(
config.outDir,
transformHTMLFileName(page, config.cleanUrls)
)
await fs.ensureDir(path.dirname(htmlFileName)) await fs.ensureDir(path.dirname(htmlFileName))
await fs.writeFile(htmlFileName, html) await fs.writeFile(htmlFileName, html)
} }
function transformHTMLFileName(page: string, shouldCleanUrls: boolean): string {
if (page === 'index.md' || page.endsWith('/index.md') || page === '404.md') {
return page.replace(/\.md$/, '.html')
}
return page.replace(/\.md$/, shouldCleanUrls ? '/index.html' : '.html')
}
function resolvePageImports( function resolvePageImports(
config: SiteConfig, config: SiteConfig,
page: string, page: string,

@ -71,6 +71,14 @@ export interface UserConfig<ThemeConfig = any> {
* @default false * @default false
*/ */
ignoreDeadLinks?: boolean ignoreDeadLinks?: boolean
/**
* Always use "clean URLs" without the `.html`.
* Also generate static files as `foo/index.html` insted of `foo.html`.
* Works with MPA config too.
* (default: false)
*/
cleanUrls?: boolean
} }
export type RawConfigExports<ThemeConfig = any> = export type RawConfigExports<ThemeConfig = any> =
@ -98,6 +106,7 @@ export interface SiteConfig<ThemeConfig = any>
tempDir: string tempDir: string
alias: AliasOptions alias: AliasOptions
pages: string[] pages: string[]
cleanUrls: boolean
} }
const resolve = (root: string, file: string) => const resolve = (root: string, file: string) =>
@ -166,7 +175,8 @@ export async function resolveConfig(
vite: userConfig.vite, vite: userConfig.vite,
shouldPreload: userConfig.shouldPreload, shouldPreload: userConfig.shouldPreload,
mpa: !!userConfig.mpa, mpa: !!userConfig.mpa,
ignoreDeadLinks: userConfig.ignoreDeadLinks ignoreDeadLinks: userConfig.ignoreDeadLinks,
cleanUrls: !!userConfig.cleanUrls
} }
return config return config
@ -270,7 +280,8 @@ export async function resolveSiteData(
themeConfig: userConfig.themeConfig || {}, themeConfig: userConfig.themeConfig || {},
locales: userConfig.locales || {}, locales: userConfig.locales || {},
langs: createLangDictionary(userConfig), langs: createLangDictionary(userConfig),
scrollOffset: userConfig.scrollOffset || 90 scrollOffset: userConfig.scrollOffset || 90,
cleanUrls: userConfig.cleanUrls || false
} }
} }

@ -56,7 +56,8 @@ export type { Header }
export const createMarkdownRenderer = async ( export const createMarkdownRenderer = async (
srcDir: string, srcDir: string,
options: MarkdownOptions = {}, options: MarkdownOptions = {},
base = '/' base = '/',
cleanUrls: boolean = false
): Promise<MarkdownRenderer> => { ): Promise<MarkdownRenderer> => {
const md = MarkdownIt({ const md = MarkdownIt({
html: true, html: true,
@ -81,7 +82,8 @@ export const createMarkdownRenderer = async (
rel: 'noopener noreferrer', rel: 'noopener noreferrer',
...options.externalLinks ...options.externalLinks
}, },
base base,
cleanUrls
) )
// 3rd party plugins // 3rd party plugins

@ -12,7 +12,8 @@ const indexRE = /(^|.*\/)index.md(#?.*)$/i
export const linkPlugin = ( export const linkPlugin = (
md: MarkdownIt, md: MarkdownIt,
externalAttrs: Record<string, string>, externalAttrs: Record<string, string>,
base: string base: string,
shouldCleanUrls: boolean
) => { ) => {
md.renderer.rules.link_open = (tokens, idx, options, env, self) => { md.renderer.rules.link_open = (tokens, idx, options, env, self) => {
const token = tokens[idx] const token = tokens[idx]
@ -37,7 +38,7 @@ export const linkPlugin = (
// links to files (other than html/md) // links to files (other than html/md)
!/\.(?!html|md)\w+($|\?)/i.test(url) !/\.(?!html|md)\w+($|\?)/i.test(url)
) { ) {
normalizeHref(hrefAttr) normalizeHref(hrefAttr, shouldCleanUrls)
} }
// encode vite-specific replace strings in case they appear in URLs // encode vite-specific replace strings in case they appear in URLs
@ -50,7 +51,7 @@ export const linkPlugin = (
return self.renderToken(tokens, idx, options) return self.renderToken(tokens, idx, options)
} }
function normalizeHref(hrefAttr: [string, string]) { function normalizeHref(hrefAttr: [string, string], shouldCleanUrls: boolean) {
let url = hrefAttr[1] let url = hrefAttr[1]
const indexMatch = url.match(indexRE) const indexMatch = url.match(indexRE)
@ -58,13 +59,17 @@ export const linkPlugin = (
const [, path, hash] = indexMatch const [, path, hash] = indexMatch
url = path + hash url = path + hash
} else { } else {
let cleanUrl = url.replace(/[?#].*$/, '') let cleanUrl = url.replace(/[?#].*$/, '').replace(/\?.*$/, '')
// .md -> .html // transform foo.md -> foo[.html]
if (cleanUrl.endsWith('.md')) { if (cleanUrl.endsWith('.md')) {
cleanUrl = cleanUrl.replace(/\.md$/, '.html') cleanUrl = cleanUrl.replace(/\.md$/, shouldCleanUrls ? '' : '.html')
} }
// ./foo -> ./foo.html // transform ./foo -> ./foo[.html]
if (!cleanUrl.endsWith('.html') && !cleanUrl.endsWith('/')) { if (
!shouldCleanUrls &&
!cleanUrl.endsWith('.html') &&
!cleanUrl.endsWith('/')
) {
cleanUrl += '.html' cleanUrl += '.html'
} }
const parsed = new URL(url, 'http://a.com') const parsed = new URL(url, 'http://a.com')

@ -28,9 +28,10 @@ export async function createMarkdownToVueRenderFn(
userDefines: Record<string, any> | undefined, userDefines: Record<string, any> | undefined,
isBuild = false, isBuild = false,
base = '/', base = '/',
includeLastUpdatedData = false includeLastUpdatedData = false,
cleanUrls: boolean = false
) { ) {
const md = await createMarkdownRenderer(srcDir, options, base) const md = await createMarkdownRenderer(srcDir, options, base, cleanUrls)
pages = pages.map((p) => slash(p.replace(/\.md$/, ''))) pages = pages.map((p) => slash(p.replace(/\.md$/, '')))

@ -45,7 +45,8 @@ export async function createVitePressPlugin(
vue: userVuePluginOptions, vue: userVuePluginOptions,
vite: userViteConfig, vite: userViteConfig,
pages, pages,
ignoreDeadLinks ignoreDeadLinks,
cleanUrls
} = siteConfig } = siteConfig
let markdownToVue: Awaited<ReturnType<typeof createMarkdownToVueRenderFn>> let markdownToVue: Awaited<ReturnType<typeof createMarkdownToVueRenderFn>>
@ -83,7 +84,8 @@ export async function createVitePressPlugin(
config.define, config.define,
config.command === 'build', config.command === 'build',
config.base, config.base,
siteConfig.lastUpdated siteConfig.lastUpdated,
cleanUrls
) )
}, },

1
types/shared.d.ts vendored

@ -57,6 +57,7 @@ export interface SiteData<ThemeConfig = any> {
label: string label: string
} }
> >
cleanUrls: boolean
} }
export type HeadConfig = export type HeadConfig =

Loading…
Cancel
Save