diff --git a/packages/@vuepress/core/lib/build.js b/packages/@vuepress/core/lib/build.js index cee72ad6..7d291d17 100644 --- a/packages/@vuepress/core/lib/build.js +++ b/packages/@vuepress/core/lib/build.js @@ -65,12 +65,12 @@ module.exports = async function build (sourceDir, cliOptions = {}) { // render pages logger.wait('Rendering static HTML...') - for (const page of options.siteData.pages) { + for (const page of options.pages) { await renderPage(page) } // if the user does not have a custom 404.md, generate the theme's default - if (!options.siteData.pages.some(p => p.path === '/404.html')) { + if (!options.pages.some(p => p.path === '/404.html')) { await renderPage({ path: '/404.html' }) } diff --git a/packages/@vuepress/core/lib/dev.js b/packages/@vuepress/core/lib/dev.js index e1c74944..a2cfd0a1 100644 --- a/packages/@vuepress/core/lib/dev.js +++ b/packages/@vuepress/core/lib/dev.js @@ -81,7 +81,7 @@ module.exports = async function dev (sourceDir, cliOptions = {}) { .use(DevLogPlugin, [{ port, displayHost, - publicPath: options.publicPath + publicPath: options.base }]) config = config.toConfig() @@ -118,7 +118,7 @@ module.exports = async function dev (sourceDir, cliOptions = {}) { // respect base when serving static files... if (fs.existsSync(userPublic)) { - app.use(mount(options.publicPath, serveStatic(userPublic))) + app.use(mount(options.base, serveStatic(userPublic))) } app.use(convert(history({ diff --git a/packages/@vuepress/core/lib/internal-plugins/importAsyncComponent.js b/packages/@vuepress/core/lib/internal-plugins/importAsyncComponent.js index bf0bc652..33bfb423 100644 --- a/packages/@vuepress/core/lib/internal-plugins/importAsyncComponent.js +++ b/packages/@vuepress/core/lib/internal-plugins/importAsyncComponent.js @@ -1,7 +1,7 @@ function genImportAsyncComponentFile (pages) { return `export function loadComponent (key) { switch (key) { -${pages.map(({ key, filePath }) => ` case "${key}": return import("${filePath}");`).join('\n')} +${pages.map(({ key, _filePath }) => ` case "${key}": return import("${_filePath}");`).join('\n')} } }` } @@ -11,7 +11,7 @@ module.exports = (options, context) => ({ // @internal/async-component async clientDynamicModules () { - const importAsyncComponentCode = genImportAsyncComponentFile(context.siteData.pages) + const importAsyncComponentCode = genImportAsyncComponentFile(context.pages) return { name: 'async-component.js', content: importAsyncComponentCode, diff --git a/packages/@vuepress/core/lib/internal-plugins/routes.js b/packages/@vuepress/core/lib/internal-plugins/routes.js index 5fdd9dd7..aa832882 100644 --- a/packages/@vuepress/core/lib/internal-plugins/routes.js +++ b/packages/@vuepress/core/lib/internal-plugins/routes.js @@ -3,7 +3,7 @@ module.exports = (options, context) => ({ // @internal/routes async clientDynamicModules () { - const routesCode = await genRoutesFile(context.siteData.pages) + const routesCode = await genRoutesFile(context.pages) return { name: 'routes.js', content: routesCode, dirname: 'internal' } } }) @@ -14,11 +14,15 @@ module.exports = (options, context) => ({ * @returns {Promise} */ async function genRoutesFile (pages) { - function genRoute ({ path: pagePath, filePath, key: componentName }) { + function genRoute ({ + path: pagePath, + key: componentName, + frontmatter = {} + }) { let code = ` { name: ${JSON.stringify(componentName)}, - path: ${JSON.stringify(pagePath)}, + path: ${JSON.stringify(frontmatter.permalink || pagePath)}, component: ThemeLayout, beforeEnter: (to, from, next) => { registerComponent(${JSON.stringify(componentName)}).then(() => next()) diff --git a/packages/@vuepress/core/lib/internal-plugins/siteData.js b/packages/@vuepress/core/lib/internal-plugins/siteData.js index 0fdfcb88..91a99baf 100644 --- a/packages/@vuepress/core/lib/internal-plugins/siteData.js +++ b/packages/@vuepress/core/lib/internal-plugins/siteData.js @@ -3,7 +3,7 @@ module.exports = (options, context) => ({ // @internal/siteData async clientDynamicModules () { - const code = `export const siteData = ${JSON.stringify(context.siteData, null, 2)}` + const code = `export const siteData = ${JSON.stringify(context.getSiteData(), null, 2)}` return { name: 'siteData.js', content: code, dirname: 'internal' } } }) diff --git a/packages/@vuepress/core/lib/plugin-api/context.js b/packages/@vuepress/core/lib/plugin-api/context.js deleted file mode 100644 index f697ea56..00000000 --- a/packages/@vuepress/core/lib/plugin-api/context.js +++ /dev/null @@ -1,64 +0,0 @@ -const path = require('path') -const { writeTemp } = require('@vuepress/shared-utils') - -class PluginContext { - constructor (options) { - Object.defineProperty(this, '_options', { - enumerable: false, - configurable: false, - writable: false, - value: options - }) - } - - get base () { - return this._options.siteConfig.base - } - - get isProd () { - return this._options.isProd - } - - get sourceDir () { - return this._options.sourceDir - } - - get publicDir () { - path.resolve(this.sourceDir, '.vuepress/public') - } - - get outDir () { - return this._options.outDir - } - - get themePath () { - return this._options.themePath - } - - get publicPath () { - return this._options.publicPath - } - - get themeConfig () { - return this._options.themeConfig - } - - get siteConfig () { - return this._options.siteConfig - } - - get siteData () { - return this._options.siteData - } - - get self () { - return this._options.self - } -} - -Object.assign(PluginContext.prototype, { - resolve: path.resolve, - writeTemp -}) - -module.exports = PluginContext diff --git a/packages/@vuepress/core/lib/plugin-api/util.js b/packages/@vuepress/core/lib/plugin-api/util.js index 234deab8..84ef9341 100644 --- a/packages/@vuepress/core/lib/plugin-api/util.js +++ b/packages/@vuepress/core/lib/plugin-api/util.js @@ -107,11 +107,14 @@ exports.hydratePlugin = function ({ config, name, shortcut, isLocal }, pluginOpt exports.normalizePluginsConfig = function (pluginsConfig) { const { valid, warnMsg } = assertTypes(pluginsConfig, [Object, Array]) if (!valid) { - logger.warn( - `[${chalk.gray('config')}] ` + - `Invalid value for "plugin" field : ${warnMsg}` - ) + if (pluginsConfig !== undefined) { + logger.warn( + `[${chalk.gray('config')}] ` + + `Invalid value for "plugin" field : ${warnMsg}` + ) + } pluginsConfig = [] + return pluginsConfig } if (Array.isArray(pluginsConfig)) { pluginsConfig = pluginsConfig.map(item => { diff --git a/packages/@vuepress/core/lib/prepare/AppContext.js b/packages/@vuepress/core/lib/prepare/AppContext.js new file mode 100644 index 00000000..1c8ab191 --- /dev/null +++ b/packages/@vuepress/core/lib/prepare/AppContext.js @@ -0,0 +1,249 @@ +const path = require('path') +const createMarkdown = require('../markdown/index') +const loadConfig = require('./loadConfig') +const { globby } = require('@vuepress/shared-utils') +const { sort } = require('./util') +const { fs, logger, chalk } = require('@vuepress/shared-utils') + +const Page = require('./Page') +const PluginAPI = require('../plugin-api/index') + +module.exports = class AppContext { + /** + * Instantiate the app context with a new API + * @param { string } sourceDir + * @param {{ + * isProd: boolean, + * plugins: pluginsConfig, + * theme: themeNameConfig + * }} options + */ + constructor (sourceDir, options) { + this.sourceDir = sourceDir + this._options = options + this.isProd = options.isProd + this.vuepressDir = path.resolve(sourceDir, '.vuepress') + this.siteConfig = loadConfig(this.vuepressDir) + this.base = this.siteConfig.base || '/' + this.themeConfig = this.siteConfig.themeConfig || {} + this.outDir = this.siteConfig.dest + ? path.resolve(this.siteConfig.dest) + : path.resolve(sourceDir, '.vuepress/dist') + + this.markdown = createMarkdown(this.siteConfig) + this.pluginAPI = new PluginAPI(this) + this.pages = [] // Array + } + + /** + * Load pages, load plugins, apply plugins / plugin options, etc. + * @returns {Promise} + */ + async process () { + this.normalizeHeadTagUrls() + await this.resolveTheme() + this.resolvePlugins() + + await this.resolvePages() + await this.pluginAPI.options.additionalPages.values.map(async ({ path, permalink }) => { + await this.addPage(path, { permalink }) + }) + + await this.pluginAPI.options.ready.apply() + this.pluginAPI.options.extendMarkdown.syncApply(this.markdown) + await this.pluginAPI.options.clientDynamicModules.apply() + await this.pluginAPI.options.globalUIComponents.apply() + await this.pluginAPI.options.enhanceAppFiles.apply() + } + + /** + * Apply internal and user plugins + */ + resolvePlugins () { + const themeConfig = this.themeConfig + const siteConfig = this.siteConfig + + const shouldUseLastUpdated = ( + themeConfig.lastUpdated || + Object.keys(siteConfig.locales && themeConfig.locales || {}) + .some(base => themeConfig.locales[base].lastUpdated) + ) + + this.pluginAPI + // internl core plugins + .use(require('../internal-plugins/siteData')) + .use(require('../internal-plugins/routes')) + .use(require('../internal-plugins/rootMixins')) + .use(require('../internal-plugins/importAsyncComponent')) + .use(require('../internal-plugins/enhanceApp')) + .use(require('../internal-plugins/overrideCSS')) + .use(require('../internal-plugins/data-mixins')) + // user plugin + .useByPluginsConfig(this._options.plugins) + .useByPluginsConfig(this.siteConfig.plugins) + .useByPluginsConfig(this.themeplugins) + // built-in plugins + .use('@vuepress/last-updated', shouldUseLastUpdated) + .use('@vuepress/register-components', { + componentsDir: [ + path.resolve(this.sourceDir, '.vuepress/components'), + path.resolve(this.themePath, 'components') + ] + }) + .apply() + } + + /** + * normalize head tag urls for base + */ + normalizeHeadTagUrls () { + if (this.base !== '/' && this.siteConfig.head) { + this.siteConfig.head.forEach(tag => { + const attrs = tag[1] + if (attrs) { + for (const name in attrs) { + if (name === 'src' || name === 'href') { + const value = attrs[name] + if (value.charAt(0) === '/') { + attrs[name] = this.base + value.slice(1) + } + } + } + } + }) + } + } + + /** + * Find all page source files located in sourceDir + * @returns {Promise} + */ + async resolvePages () { + // resolve pageFiles + const patterns = ['**/*.md', '!.vuepress', '!node_modules'] + if (this.siteConfig.dest) { + // #654 exclude dest folder when dest dir was set in + // sourceDir but not in '.vuepress' + const outDirRelative = path.relative(this.sourceDir, this.outDir) + if (!outDirRelative.includes('..')) { + patterns.push('!' + outDirRelative) + } + } + const pageFiles = sort(await globby(patterns, { cwd: this.sourceDir })) + + await Promise.all(pageFiles.map(async (relative) => { + const filePath = path.resolve(this.sourceDir, relative) + await this.addPage(filePath, { relative }) + })) + } + + /** + * Add a page + * @param { string } filePath + * @param { string } relative relative path of source markdown file. + * @param { string } permalink the URL (excluding the domain name) + * for your pages, posts. + * @returns { Promise } + */ + async addPage (filePath, { relative, permalink }) { + const page = new Page(filePath, { relative, permalink }) + await page.process(this.markdown) + await this.pluginAPI.options.extendPageData.apply(page) + this.pages.push(page) + } + + /** + * Resolve theme + * @returns { Promise } + */ + async resolveTheme () { + const theme = this.siteConfig.theme || this._options.theme + const requireResolve = (target) => { + return require.resolve(target, { + paths: [ + path.resolve(__dirname, '../../node_modules'), + path.resolve(this.sourceDir) + ] + }) + } + + // resolve theme + const localThemePath = path.resolve(this.vuepressDir, 'theme') + const useLocalTheme = await fs.exists(localThemePath) + + let themePath = null + let themeLayoutPath = null + let themeNotFoundPath = null + let themeIndexFile = null + let themePlugins = [] + + if (useLocalTheme) { + logger.tip(`\nApply theme located at ${localThemePath}...`) + + // use local custom theme + themePath = localThemePath + themeLayoutPath = path.resolve(localThemePath, 'Layout.vue') + themeNotFoundPath = path.resolve(localThemePath, 'NotFound.vue') + if (!fs.existsSync(themeLayoutPath)) { + throw new Error(`[vuepress] Cannot resolve Layout.vue file in .vuepress/theme.`) + } + if (!fs.existsSync(themeNotFoundPath)) { + throw new Error(`[vuepress] Cannot resolve NotFound.vue file in .vuepress/theme.`) + } + } else if (theme) { + // use external theme + try { + // backward-compatible 0.x.x. + themeLayoutPath = requireResolve(`vuepress-theme-${theme}/Layout.vue`) + themePath = path.dirname(themeLayoutPath) + themeNotFoundPath = path.resolve(themeLayoutPath, 'NotFound.vue') + } catch (e) { + try { + themeIndexFile = requireResolve(`vuepress-theme-${theme}/index.js`) + } catch (e) { + try { + themeIndexFile = requireResolve(`@vuepress/theme-${theme}`) + themePath = path.dirname(themeIndexFile) + themeIndexFile = require(themeIndexFile) + themeLayoutPath = themeIndexFile.layout + themeNotFoundPath = themeIndexFile.notFound + themePlugins = themeIndexFile.plugins + } catch (e) { + throw new Error(`[vuepress] Failed to load custom theme "${theme}". File vuepress-theme-${theme}/Layout.vue does not exist.`) + } + } + } + logger.tip(`\nApply theme ${chalk.gray(theme)}`) + } else { + throw new Error(`[vuepress] You must specify a theme, or create a local custom theme. \n For more details, refer to https://vuepress.vuejs.org/guide/custom-themes.html#custom-themes. \n`) + } + + this.themePath = themePath + this.themeLayoutPath = themeLayoutPath + this.themeNotFoundPath = themeNotFoundPath + this.themeplugins = themePlugins + } + + /** + * Get the data to be delivered to the client. + * @returns {{ + * title: string, + * description: string, + * base: string, + * pages: Page[], + * themeConfig: ThemeConfig, + * locales: Locales + * }} + */ + getSiteData () { + return { + title: this.siteConfig.title || '', + description: this.siteConfig.description || '', + base: this.base, + pages: this.pages.map(page => page.toJson()), + themeConfig: this.siteConfig.themeConfig || {}, + locales: this.siteConfig.locales + } + } +} + diff --git a/packages/@vuepress/core/lib/prepare/Page.js b/packages/@vuepress/core/lib/prepare/Page.js new file mode 100644 index 00000000..4e48e6d0 --- /dev/null +++ b/packages/@vuepress/core/lib/prepare/Page.js @@ -0,0 +1,72 @@ +const path = require('path') +const slugify = require('../markdown/slugify') +const { fs } = require('@vuepress/shared-utils') +const { encodePath, fileToPath } = require('./util') +const { + inferTitle, + extractHeaders, + parseFrontmatter +} = require('../util/index') + +module.exports = class Page { + constructor (filePath, { + relative, + routePath + }) { + this._filePath = filePath + if (relative) { + this._routePath = encodePath(fileToPath(relative)) + } else { + this._routePath = routePath + } + this.path = this._routePath + } + + async process (markdown) { + this.key = 'v-' + Math.random().toString(16).slice(2) + this.content = await fs.readFile(this._filePath, 'utf-8') + const frontmatter = parseFrontmatter(this.content) + + // infer title + const title = inferTitle(frontmatter) + if (title) { + this.title = title + } + + // headers + const headers = extractHeaders( + frontmatter.content, + ['h2', 'h3'], + markdown + ) + if (headers.length) { + this.headers = headers + } + + this.frontmatter = frontmatter.data + + if (frontmatter.excerpt) { + const { html } = markdown.render(frontmatter.excerpt) + this.excerpt = html + } + } + + get filename () { + return path.parse(this._filePath).name + } + + get slug () { + return slugify(this.filename) + } + + toJson () { + const json = {} + Object.keys(this).reduce((json, key) => { + if (!key.startsWith('_')) { + json[key] = this[key] + } + return json + }, json) + return json + } +} diff --git a/packages/@vuepress/core/lib/prepare/index.js b/packages/@vuepress/core/lib/prepare/index.js index 19cd487e..68c09980 100644 --- a/packages/@vuepress/core/lib/prepare/index.js +++ b/packages/@vuepress/core/lib/prepare/index.js @@ -1,66 +1,14 @@ -const path = require('path') -const resolveOptions = require('./resolveOptions') -const resolveSiteData = require('./resolveSiteData') -const PluginAPI = require('../plugin-api/index') -const PluginContext = require('../plugin-api/context') +const AppContext = require('./AppContext') module.exports = async function prepare ({ sourceDir, isProd, - cliOptions + cliOptions: { + plugins, + theme + } }) { - // 1. load options - const options = await resolveOptions(sourceDir, cliOptions) - options.isProd = isProd - - // 2. apply plugins - const { siteConfig, themeConfig, themePath, themePlugins, cliPlugins, markdown } = options - const pluginContext = new PluginContext(options) - const pluginAPI = new PluginAPI(pluginContext) - options.pluginAPI = pluginAPI - - const shouldUseLastUpdated = ( - themeConfig.lastUpdated || - Object.keys(siteConfig.locales && themeConfig.locales || {}) - .some(base => themeConfig.locales[base].lastUpdated) - ) - - pluginAPI - // internl core plugins - .use(require('../internal-plugins/routes')) - .use(require('../internal-plugins/rootMixins')) - .use(require('../internal-plugins/importAsyncComponent')) - .use(require('../internal-plugins/enhanceApp')) - .use(require('../internal-plugins/siteData')) - .use(require('../internal-plugins/overrideCSS')) - .use(require('../internal-plugins/data-mixins')) - // user plugin - .useByPluginsConfig(cliPlugins) - .useByPluginsConfig(siteConfig.plugins) - .useByPluginsConfig(themePlugins) - // built-in plugins - .use('@vuepress/last-updated', shouldUseLastUpdated) - .use('@vuepress/register-components', { - componentsDir: [ - path.resolve(sourceDir, '.vuepress/components'), - path.resolve(themePath, 'components') - ] - }) - .apply() - - // 3. resolve siteData - // SiteData must be resolved after the plugin initialization - // because plugins can be able to extend the sitedata. - options.siteData = await resolveSiteData(options) - - // 4. ready hook, user can do some options transformation here. - await pluginAPI.options.ready.apply() - - // 5. apply plugin options - pluginAPI.options.extendMarkdown.syncApply(markdown) - await pluginAPI.options.clientDynamicModules.apply() - await pluginAPI.options.globalUIComponents.apply() - await pluginAPI.options.enhanceAppFiles.apply() - - return options + const appContext = new AppContext(sourceDir, { plugins, theme, isProd }) + await appContext.process() + return appContext } diff --git a/packages/@vuepress/core/lib/prepare/resolveOptions.js b/packages/@vuepress/core/lib/prepare/resolveOptions.js deleted file mode 100644 index 3f63c411..00000000 --- a/packages/@vuepress/core/lib/prepare/resolveOptions.js +++ /dev/null @@ -1,129 +0,0 @@ -const path = require('path') -const createMarkdown = require('../markdown/index') -const loadConfig = require('./loadConfig') -const { sort } = require('./util') -const { chalk, fs, logger, globby } = require('@vuepress/shared-utils') - -module.exports = async function resolveOptions (sourceDir, cliOptions) { - function requireResolve (target) { - return require.resolve(target, { - paths: [ - path.resolve(__dirname, '../../node_modules'), - path.resolve(sourceDir) - ] - }) - } - - const vuepressDir = path.resolve(sourceDir, '.vuepress') - const siteConfig = loadConfig(vuepressDir) - - // normalize head tag urls for base - const base = siteConfig.base || '/' - if (base !== '/' && siteConfig.head) { - siteConfig.head.forEach(tag => { - const attrs = tag[1] - if (attrs) { - for (const name in attrs) { - if (name === 'src' || name === 'href') { - const value = attrs[name] - if (value.charAt(0) === '/') { - attrs[name] = base + value.slice(1) - } - } - } - } - }) - } - - // resolve outDir - const outDir = siteConfig.dest - ? path.resolve(siteConfig.dest) - : path.resolve(sourceDir, '.vuepress/dist') - - // resolve theme - const localThemePath = path.resolve(vuepressDir, 'theme') - const useLocalTheme = fs.existsSync(localThemePath) - const theme = siteConfig.theme || cliOptions.theme - - let themePath = null - let themeLayoutPath = null - let themeNotFoundPath = null - let themeIndexFile = null - let themePlugins = [] - - if (useLocalTheme) { - logger.tip(`\nApply theme located at ${localThemePath}...`) - - // use local custom theme - themePath = localThemePath - themeLayoutPath = path.resolve(localThemePath, 'Layout.vue') - themeNotFoundPath = path.resolve(localThemePath, 'NotFound.vue') - if (!fs.existsSync(themeLayoutPath)) { - throw new Error(`[vuepress] Cannot resolve Layout.vue file in .vuepress/theme.`) - } - if (!fs.existsSync(themeNotFoundPath)) { - throw new Error(`[vuepress] Cannot resolve NotFound.vue file in .vuepress/theme.`) - } - } else if (theme) { - // use external theme - try { - // backward-compatible 0.x.x. - themeLayoutPath = requireResolve(`vuepress-theme-${theme}/Layout.vue`) - themePath = path.dirname(themeLayoutPath) - themeNotFoundPath = path.resolve(themeLayoutPath, 'NotFound.vue') - } catch (e) { - try { - themeIndexFile = requireResolve(`vuepress-theme-${theme}/index.js`) - } catch (e) { - try { - themeIndexFile = requireResolve(`@vuepress/theme-${theme}`) - themePath = path.dirname(themeIndexFile) - themeIndexFile = require(themeIndexFile) - themeLayoutPath = themeIndexFile.layout - themeNotFoundPath = themeIndexFile.notFound - themePlugins = themeIndexFile.plugins - } catch (e) { - throw new Error(`[vuepress] Failed to load custom theme "${theme}". File vuepress-theme-${theme}/Layout.vue does not exist.`) - } - } - } - logger.tip(`\nApply theme ${chalk.gray(theme)}`) - } else { - throw new Error(`[vuepress] You must specify a theme, or create a local custom theme. \n For more details, refer to https://vuepress.vuejs.org/guide/custom-themes.html#custom-themes. \n`) - } - - // resolve theme config - const themeConfig = siteConfig.themeConfig || {} - - // resolve markdown - const markdown = createMarkdown(siteConfig) - - // resolve pageFiles - const patterns = ['**/*.md', '!.vuepress', '!node_modules'] - if (siteConfig.dest) { - // #654 exclude dest folder when dest dir was set in - // sourceDir but not in '.vuepress' - const outDirRelative = path.relative(sourceDir, outDir) - if (!outDirRelative.includes('..')) { - patterns.push('!' + outDirRelative) - } - } - const pageFiles = sort(await globby(patterns, { cwd: sourceDir })) - - const options = { - siteConfig, - themeConfig, - sourceDir, - outDir, - publicPath: base, - pageFiles, - themePath, - themeLayoutPath, - themeNotFoundPath, - themePlugins, - cliPlugins: cliOptions.plugins || [], - markdown - } - - return options -} diff --git a/packages/@vuepress/core/lib/prepare/resolveSiteData.js b/packages/@vuepress/core/lib/prepare/resolveSiteData.js deleted file mode 100644 index 9ce28b4e..00000000 --- a/packages/@vuepress/core/lib/prepare/resolveSiteData.js +++ /dev/null @@ -1,82 +0,0 @@ -const { fs } = require('@vuepress/shared-utils') -const path = require('path') -const { encodePath, fileToPath } = require('./util') -const { - inferTitle, - extractHeaders, - parseFrontmatter -} = require('../util/index') - -module.exports = async function ({ - sourceDir, - pageFiles, - pluginAPI, - markdown, - siteConfig, - themeConfig, - publicPath -}) { - async function getPageData ({ filePath, routePath, base }) { - const key = 'v-' + Math.random().toString(16).slice(2) - const data = { key, path: routePath, filePath } - - const content = await fs.readFile(filePath, 'utf-8') - - // extract yaml frontmatter - const frontmatter = parseFrontmatter(content) - // infer title - const title = inferTitle(frontmatter) - if (title) { - data.title = title - } - const headers = extractHeaders( - frontmatter.content, - ['h2', 'h3'], - markdown - ) - if (headers.length) { - data.headers = headers - } - - data.frontmatter = frontmatter.data - - if (frontmatter.excerpt) { - const { html } = markdown.render(frontmatter.excerpt) - data.excerpt = html - } - - await pluginAPI.options.extendPageData.apply(data) - return data - } - - // resolve pagesData - const pagesData = await Promise.all(pageFiles.map(async (base) => { - const filePath = path.resolve(sourceDir, base) - const routePath = encodePath(fileToPath(base)) - return getPageData({ filePath, routePath, base }) - })) - - // resolve additional pagesData - const additionalPagesData = await Promise.all( - pluginAPI.options.additionalPages.values.map(async ({ route: routePath, path: filePath }) => { - if (!fs.existsSync(filePath)) { - throw new Error(`[vuepress] Cannot resolve additional page: ${filePath}`) - } - return getPageData({ filePath, routePath }) - }) - ) - - const siteData = { - title: siteConfig.title || '', - description: siteConfig.description || '', - base: publicPath, - pages: [ - ...pagesData, - ...additionalPagesData - ], - themeConfig, - locales: siteConfig.locales - } - - return siteData -} diff --git a/packages/@vuepress/core/lib/webpack/createBaseConfig.js b/packages/@vuepress/core/lib/webpack/createBaseConfig.js index 832cc0cd..43ddf425 100644 --- a/packages/@vuepress/core/lib/webpack/createBaseConfig.js +++ b/packages/@vuepress/core/lib/webpack/createBaseConfig.js @@ -2,14 +2,12 @@ const path = require('path') module.exports = function createBaseConfig ({ siteConfig, - siteData, sourceDir, outDir, - publicPath, + base: publicPath, themePath, themeLayoutPath, themeNotFoundPath, - isAlgoliaSearch, markdown }, { debug } = {}, isServer) { const Config = require('webpack-chain') diff --git a/packages/@vuepress/plugin-back-to-top/index.js b/packages/@vuepress/plugin-back-to-top/index.js index 900f0df1..ecfc0b64 100644 --- a/packages/@vuepress/plugin-back-to-top/index.js +++ b/packages/@vuepress/plugin-back-to-top/index.js @@ -1,6 +1,8 @@ +const path = require('path') + module.exports = (options, context) => ({ enhanceAppFiles: [ - context.resolve(__dirname, 'client.js') + path.resolve(__dirname, 'client.js') ], globalUIComponents: 'BackToTop' diff --git a/packages/@vuepress/plugin-i18n-ui/index.js b/packages/@vuepress/plugin-i18n-ui/index.js index ad573886..34f15e64 100644 --- a/packages/@vuepress/plugin-i18n-ui/index.js +++ b/packages/@vuepress/plugin-i18n-ui/index.js @@ -1,3 +1,5 @@ +const path = require('path') + module.exports = (pluginOptions = {}, context) => ({ name: 'i18n-ui', @@ -5,14 +7,14 @@ module.exports = (pluginOptions = {}, context) => ({ enabled: !context.isProd, enhanceAppFiles: [ - context.resolve(__dirname, 'client.js') + path.resolve(__dirname, 'client.js') ], additionalPages: [ { override: false, - route: pluginOptions.route || '/i18n/', - path: context.resolve(__dirname, 'index.md') + permalink: pluginOptions.route || '/i18n/', + path: path.resolve(__dirname, 'index.md') } ] }) diff --git a/packages/@vuepress/plugin-last-updated/index.js b/packages/@vuepress/plugin-last-updated/index.js index 864c600b..2324244f 100644 --- a/packages/@vuepress/plugin-last-updated/index.js +++ b/packages/@vuepress/plugin-last-updated/index.js @@ -1,9 +1,9 @@ const spawn = require('cross-spawn') module.exports = (options = {}, context) => ({ - extendPageData ({ filePath }) { + extendPageData ({ _filePath }) { const { transformer } = options - const timestamp = getGitLastUpdatedTimeStamp(filePath) + const timestamp = getGitLastUpdatedTimeStamp(_filePath) const lastUpdated = typeof transformer === 'function' ? transformer(timestamp) : timestamp return { lastUpdated } }