diff --git a/lib/app/app.js b/lib/app/app.js index 44db745354..8b78a28733 100644 --- a/lib/app/app.js +++ b/lib/app/app.js @@ -4,7 +4,6 @@ import Content from './Content' import ClientOnly from './ClientOnly' import dataMixin from './dataMixin' import store from './store' -import NotFound from '@notFound' import { routes } from '@temp/routes' import { siteData } from '@temp/siteData' import enhanceApp from '@temp/enhanceApp' @@ -42,12 +41,6 @@ Vue.prototype.$withBase = function (path) { } } -// add 404 route -routes.push({ - path: '*', - component: NotFound -}) - export function createApp () { const router = new Router({ base: siteData.base, diff --git a/lib/prepare.js b/lib/prepare.js index 2d0fc56db2..1ba21461c7 100644 --- a/lib/prepare.js +++ b/lib/prepare.js @@ -19,6 +19,15 @@ async function writeTemp (file, content) { } } +async function writeEnhanceTemp (destName, srcPath) { + await writeTemp( + destName, + fs.existsSync(srcPath) + ? `export { default } from ${JSON.stringify(srcPath)}` + : `export default function () {}` + ) +} + module.exports = async function prepare (sourceDir) { // 1. load options const options = await resolveOptions(sourceDir) @@ -50,29 +59,12 @@ if (!Object.assign) Object.assign = require('object-assign')` const hasUserOverride = options.useDefaultTheme && fs.existsSync(overridePath) await writeTemp(`override.styl`, hasUserOverride ? `@import(${JSON.stringify(overridePath)})` : ``) - async function writeEnhanceTemp (destName, srcPath, isEnhanceExist) { - await writeTemp( - destName, - isEnhanceExist - ? `export { default } from ${JSON.stringify(srcPath)}` - : `export default function () {}` - ) - } - // 6. handle enhanceApp.js const enhanceAppPath = path.resolve(sourceDir, '.vuepress/enhanceApp.js') - writeEnhanceTemp( - 'enhanceApp.js', - enhanceAppPath, - fs.existsSync(enhanceAppPath) - ) + await writeEnhanceTemp('enhanceApp.js', enhanceAppPath) // 7. handle the theme enhanceApp.js - writeEnhanceTemp( - 'themeEnhanceApp.js', - options.themeEnhanceAppPath, - fs.existsSync(options.themeEnhanceAppPath) - ) + await writeEnhanceTemp('themeEnhanceApp.js', options.themeEnhanceAppPath) return options } @@ -84,6 +76,8 @@ async function resolveOptions (sourceDir) { const configTomlPath = path.resolve(vuepressDir, 'config.toml') delete require.cache[configPath] + + // resolve siteConfig let siteConfig = {} if (fs.existsSync(configYmlPath)) { siteConfig = await parseConfig(configYmlPath) @@ -111,77 +105,79 @@ async function resolveOptions (sourceDir) { }) } + // resolve outDir + const outDir = siteConfig.dest + ? path.resolve(siteConfig.dest) + : path.resolve(sourceDir, '.vuepress/dist') + // resolve theme const useDefaultTheme = ( !siteConfig.theme && !fs.existsSync(path.resolve(vuepressDir, 'theme')) ) - - // resolve algolia - const themeConfig = siteConfig.themeConfig || {} - const isAlgoliaSearch = ( - themeConfig.algolia || - Object.keys(siteConfig.locales && themeConfig.locales || {}) - .some(base => themeConfig.locales[base].algolia) - ) - - const options = { - siteConfig, - sourceDir, - outDir: siteConfig.dest - ? path.resolve(siteConfig.dest) - : path.resolve(sourceDir, '.vuepress/dist'), - publicPath: base, - pageFiles: sort(await globby(['**/*.md', '!.vuepress', '!node_modules'], { cwd: sourceDir })), - pagesData: null, - themePath: null, - notFoundPath: null, - useDefaultTheme, - isAlgoliaSearch, - markdown: createMarkdown(siteConfig) - } + const defaultThemePath = path.resolve(__dirname, 'default-theme') + let themePath = null + let themeLayoutPath = null + let themeNotFoundPath = null + let themeEnhanceAppPath = null if (useDefaultTheme) { // use default theme - options.themePath = path.resolve(__dirname, 'default-theme/Layout.vue') - options.notFoundPath = path.resolve(__dirname, 'default-theme/NotFound.vue') + themePath = defaultThemePath + themeLayoutPath = path.resolve(defaultThemePath, 'Layout.vue') + themeNotFoundPath = path.resolve(defaultThemePath, 'NotFound.vue') } else { - let themeDir - let themePath - // resolve custom theme + // resolve theme Layout if (siteConfig.theme) { + // use external theme try { - themePath = require.resolve(`vuepress-theme-${siteConfig.theme}/Layout.vue`) - themeDir = path.dirname(themePath) + themeLayoutPath = require.resolve(`vuepress-theme-${siteConfig.theme}/Layout.vue`) + themePath = path.dirname(themeLayoutPath) } catch (e) { throw new Error(`[vuepress] Failed to load custom theme "${ siteConfig.theme }". File vuepress-theme-${siteConfig.theme}/Layout.vue does not exist.`) } } else { - themeDir = path.resolve(vuepressDir, 'theme') - themePath = path.resolve(themeDir, 'Layout.vue') - if (!fs.existsSync(themePath)) { + // use custom theme + themePath = path.resolve(vuepressDir, 'theme') + themeLayoutPath = path.resolve(themePath, 'Layout.vue') + if (!fs.existsSync(themeLayoutPath)) { throw new Error(`[vuepress] Cannot resolve Layout.vue file in .vuepress/theme.`) } } - options.themePath = themePath - const notFoundPath = path.resolve(themeDir, 'NotFound.vue') - if (fs.existsSync(notFoundPath)) { - options.notFoundPath = notFoundPath - } else { - options.notFoundPath = path.resolve(__dirname, 'default-theme/NotFound.vue') + // resolve theme NotFound + themeNotFoundPath = path.resolve(themePath, 'NotFound.vue') + if (!fs.existsSync(themeNotFoundPath)) { + themeNotFoundPath = path.resolve(defaultThemePath, 'NotFound.vue') } - const themeEnhanceAppPath = path.resolve(themeDir, 'enhanceApp.js') - if (fs.existsSync(themeEnhanceAppPath)) { - options.themeEnhanceAppPath = themeEnhanceAppPath + // resolve theme enhanceApp + themeEnhanceAppPath = path.resolve(themePath, 'enhanceApp.js') + if (!fs.existsSync(themeEnhanceAppPath)) { + themeEnhanceAppPath = null } } - // resolve pages - const pagesData = await Promise.all(options.pageFiles.map(async (file) => { + // resolve theme config + const themeConfig = siteConfig.themeConfig || {} + + // resolve algolia + const isAlgoliaSearch = ( + themeConfig.algolia || + Object.keys(siteConfig.locales && themeConfig.locales || {}) + .some(base => themeConfig.locales[base].algolia) + ) + + // resolve markdown + const markdown = createMarkdown(siteConfig) + + // resolve pageFiles + const pageFiles = sort(await globby(['**/*.md', '!.vuepress', '!node_modules'], { cwd: sourceDir })) + + // resolve pagesData + const pagesData = await Promise.all(pageFiles.map(async (file) => { const data = { path: fileToPath(file) } @@ -197,7 +193,7 @@ async function resolveOptions (sourceDir) { const headers = extractHeaders( frontmatter.content, ['h2', 'h3'], - options.markdown + markdown ) if (headers.length) { data.headers = headers @@ -212,15 +208,32 @@ async function resolveOptions (sourceDir) { })) // resolve site data - options.siteData = { + const siteData = { title: siteConfig.title || '', description: siteConfig.description || '', - base: siteConfig.base || '/', + base, pages: pagesData, themeConfig, locales: siteConfig.locales } + const options = { + siteConfig, + siteData, + sourceDir, + outDir, + publicPath: base, + pageFiles, + pagesData, + themePath, + themeLayoutPath, + themeNotFoundPath, + themeEnhanceAppPath, + useDefaultTheme, + isAlgoliaSearch, + markdown + } + return options } @@ -279,30 +292,38 @@ async function genRoutesFile ({ siteData: { pages }, sourceDir, pageFiles }) { const file = pageFiles[index] const filePath = path.resolve(sourceDir, file) let code = ` - { - path: ${JSON.stringify(pagePath)}, - component: Theme, - beforeEnter: (to, from, next) => { - import(${JSON.stringify(filePath)}).then(comp => { - Vue.component(${JSON.stringify(fileToComponentName(file))}, comp.default) - next() - }) - } - }` + { + path: ${JSON.stringify(pagePath)}, + component: ThemeLayout, + beforeEnter: (to, from, next) => { + import(${JSON.stringify(filePath)}).then(comp => { + Vue.component(${JSON.stringify(fileToComponentName(file))}, comp.default) + next() + }) + } + }` if (/\/$/.test(pagePath)) { - code += `,{ - path: ${JSON.stringify(pagePath + 'index.html')}, - redirect: ${JSON.stringify(pagePath)} - }` + code += `, + { + path: ${JSON.stringify(pagePath + 'index.html')}, + redirect: ${JSON.stringify(pagePath)} + }` } return code } + const notFoundRoute = `, + { + path: '*', + component: ThemeNotFound + }` + return ( - `import Theme from '@theme'\n` + - `export const routes = [${pages.map(genRoute).join(',')}\n]` + `import ThemeLayout from '@themeLayout'\n` + + `import ThemeNotFound from '@themeNotFound'\n` + + `export const routes = [${pages.map(genRoute).join(',')}${notFoundRoute}\n]` ) } diff --git a/lib/webpack/createBaseConfig.js b/lib/webpack/createBaseConfig.js index b26788ddac..f2a6ec82fa 100644 --- a/lib/webpack/createBaseConfig.js +++ b/lib/webpack/createBaseConfig.js @@ -6,7 +6,8 @@ module.exports = function createBaseConfig ({ outDir, publicPath, themePath, - notFoundPath, + themeLayoutPath, + themeNotFoundPath, isAlgoliaSearch, markdown }, { debug } = {}, isServer) { @@ -36,7 +37,8 @@ module.exports = function createBaseConfig ({ .set('symlinks', true) .alias .set('@theme', themePath) - .set('@notFound', notFoundPath) + .set('@themeLayout', themeLayoutPath) + .set('@themeNotFound', themeNotFoundPath) .set('@source', sourceDir) .set('@app', path.resolve(__dirname, '../app')) .set('@temp', path.resolve(__dirname, '../app/.temp'))