diff --git a/packages/@vuepress/core/lib/node/plugin-api/index.js b/packages/@vuepress/core/lib/node/plugin-api/index.js index 1606286f46..6dc8a9e3fd 100644 --- a/packages/@vuepress/core/lib/node/plugin-api/index.js +++ b/packages/@vuepress/core/lib/node/plugin-api/index.js @@ -5,12 +5,12 @@ */ const instantiateOption = require('./override/instantiateOption') -const { flattenPlugin, normalizePluginsConfig } = require('./util') +const { flattenPlugin } = require('./util') const { PLUGIN_OPTION_MAP } = require('./constants') const { moduleResolver: { getPluginResolver }, datatypes: { assertTypes, isPlainObject }, - logger, chalk + logger, chalk, normalizeConfig } = require('@vuepress/shared-utils') /** @@ -136,7 +136,7 @@ module.exports = class PluginAPI { */ useByPluginsConfig (pluginsConfig) { - pluginsConfig = normalizePluginsConfig(pluginsConfig) + pluginsConfig = normalizeConfig(pluginsConfig) pluginsConfig.forEach(([pluginRaw, pluginOptions]) => { this.use(pluginRaw, pluginOptions) }) diff --git a/packages/@vuepress/core/lib/node/plugin-api/util.js b/packages/@vuepress/core/lib/node/plugin-api/util.js index 706da428a5..af2ede4440 100644 --- a/packages/@vuepress/core/lib/node/plugin-api/util.js +++ b/packages/@vuepress/core/lib/node/plugin-api/util.js @@ -57,34 +57,3 @@ exports.flattenPlugin = function ( $$options: pluginOptions /* used for test */ }) } - -/** - * Normalize plugins config in `.vuepress/config.js` - * - * @param pluginsConfig - */ - -exports.normalizePluginsConfig = function (pluginsConfig) { - const { valid, warnMsg } = assertTypes(pluginsConfig, [Object, Array]) - if (!valid) { - 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 => { - return Array.isArray(item) ? item : [item] - }) - } else if (typeof pluginsConfig === 'object') { - pluginsConfig = Object.keys(pluginsConfig).map(item => { - return [item, pluginsConfig[item]] - }) - } - return pluginsConfig -} diff --git a/packages/@vuepress/markdown/index.js b/packages/@vuepress/markdown/index.js index dd5271d9fb..fdb0481fbe 100644 --- a/packages/@vuepress/markdown/index.js +++ b/packages/@vuepress/markdown/index.js @@ -18,7 +18,11 @@ const snippetPlugin = require('./lib/snippet') const tocPlugin = require('./lib/tableOfContents') const emojiPlugin = require('markdown-it-emoji') const anchorPlugin = require('markdown-it-anchor') -const { slugify: _slugify, logger, chalk, hash } = require('@vuepress/shared-utils') +const { + slugify: _slugify, + logger, chalk, hash, normalizeConfig, + moduleResolver: { getMarkdownItResolver } +} = require('@vuepress/shared-utils') /** * Create markdown by config. @@ -29,11 +33,14 @@ module.exports = (markdown = {}) => { externalLinks, anchor, toc, + plugins, lineNumbers, beforeInstantiate, afterInstantiate } = markdown + const resolver = getMarkdownItResolver() + // allow user config slugify const slugify = markdown.slugify || _slugify @@ -100,6 +107,16 @@ module.exports = (markdown = {}) => { const md = config.toMd(require('markdown-it'), markdown) + const pluginsConfig = normalizeConfig(plugins || []) + pluginsConfig.forEach(([pluginRaw, pluginOptions]) => { + const plugin = resolver.resolve(pluginRaw) + if (plugin.entry) { + md.use(plugin.entry, pluginOptions) + } else { + // TODO: error handling + } + }) + afterInstantiate && afterInstantiate(md) // override parse to allow cache diff --git a/packages/@vuepress/shared-utils/src/index.ts b/packages/@vuepress/shared-utils/src/index.ts index 689300274e..ade68a6ed2 100644 --- a/packages/@vuepress/shared-utils/src/index.ts +++ b/packages/@vuepress/shared-utils/src/index.ts @@ -14,6 +14,7 @@ import * as isIndexFile from './isIndexFile' import logger from './logger' import * as moduleLoader from './moduleLoader' import * as moduleResolver from './moduleResolver' +import normalizeConfig from './normalizeConfig' import * as parseEmojis from './parseEmojis' import parseFrontmatter from './parseFrontmatter' import parseHeaders from './parseHeaders' @@ -50,6 +51,7 @@ export { logger, moduleLoader, moduleResolver, + normalizeConfig, parseEmojis, parseFrontmatter, parseHeaders, diff --git a/packages/@vuepress/shared-utils/src/moduleResolver.ts b/packages/@vuepress/shared-utils/src/moduleResolver.ts index ecab531b3f..93ab58cde4 100644 --- a/packages/@vuepress/shared-utils/src/moduleResolver.ts +++ b/packages/@vuepress/shared-utils/src/moduleResolver.ts @@ -76,8 +76,12 @@ class ModuleResolver { this.allowedTypes = allowedTypes this.load = load this.cwd = cwd || process.cwd() - this.nonScopePrefix = `${org}-${type}-` - this.scopePrefix = `@${org}/${type}-` + if (org) { + this.nonScopePrefix = `${org}-${type}-` + this.scopePrefix = `@${org}/${type}-` + } else { + this.nonScopePrefix = `${type}-` + } this.typePrefixLength = type.length + 1 /* - */ this.prefixSlicePosition = this.typePrefixLength + org.length + 1 @@ -197,7 +201,7 @@ class ModuleResolver { const pkg = resolveScopePackage(req) if (pkg) { // speicial handling for default org. - if (pkg.org === this.org) { + if (this.org && pkg.org === this.org) { shortcut = pkg.name.startsWith(`${this.type}-`) ? pkg.name.slice(this.typePrefixLength) : pkg.name @@ -265,6 +269,10 @@ export function resolveScopePackage (name: string) { } } +export const getMarkdownItResolver = (cwd: string) => new ModuleResolver( + 'markdown-it', '', [String, Function], true /* load module */, cwd +) + export const getPluginResolver = (cwd: string): ModuleResolver => new ModuleResolver( 'plugin', 'vuepress', [String, Function, Object], true /* load module */, cwd ) diff --git a/packages/@vuepress/shared-utils/src/normalizeConfig.ts b/packages/@vuepress/shared-utils/src/normalizeConfig.ts new file mode 100644 index 0000000000..4c9a8c41b0 --- /dev/null +++ b/packages/@vuepress/shared-utils/src/normalizeConfig.ts @@ -0,0 +1,28 @@ +import { assertTypes } from './datatypes' +import logger from './logger' +import chalk from 'chalk' + +export default function normalizeConfig (pluginsConfig: any) { + const { valid, warnMsg } = assertTypes(pluginsConfig, [Object, Array]) + if (!valid) { + 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 => { + return Array.isArray(item) ? item : [item] + }) + } else if (typeof pluginsConfig === 'object') { + pluginsConfig = Object.keys(pluginsConfig).map(item => { + return [item, pluginsConfig[item]] + }) + } + return pluginsConfig +} diff --git a/packages/docs/docs/config/README.md b/packages/docs/docs/config/README.md index 84f6ec7b53..f09a0d3818 100644 --- a/packages/docs/docs/config/README.md +++ b/packages/docs/docs/config/README.md @@ -240,6 +240,38 @@ This attribute will control the behaviour of `[[TOC]]`. It contains the followin We also provide a [global component TOC](../guide/using-vue.md#toc) which allows for more free control by passing props directly to ``. +### markdown.plugins + +You can install any markdown-it plugins through `markdown.plugins` option. It is similar with [using VuePress plugins](../plugin/using-a-plugin.html#using-a-plugin). You can either use Babel style or object style. The `markdown-it-` prefix is optional and can omit in the list. + +``` js +module.exports = { + markdown: { + plugins: [ + '@org/foo', // equals to @org/markdown-it-foo if exists + ['markdown-it-bar', { + // provide options here + }] + ] + } +} +``` + +or + +``` js +module.exports = { + markdown: { + plugins: { + '@org/foo': {} + 'markdown-it-bar': { + // provide options here + } + } + } +} +``` + ### markdown.extendMarkdown - Type: `Function` diff --git a/packages/docs/docs/zh/config/README.md b/packages/docs/docs/zh/config/README.md index 9a39d0af31..319a3e2d25 100644 --- a/packages/docs/docs/zh/config/README.md +++ b/packages/docs/docs/zh/config/README.md @@ -232,6 +232,38 @@ VuePress 提供了一种添加额外样式的简便方法。你可以创建一 此外,我们还提供了[全局组件 TOC](../guide/using-vue.md#toc),可以通过直接向 `` 传递属性实现更加自由的控制。 +### markdown.plugins + +你可以使用 `markdown.plugins` 来安装 markdown-it 插件。它的使用方法与[安装一个 VuePress 插件](../plugin/using-a-plugin.html#using-a-plugin)类似。你可以使用 Babel 语法或对象语法。`markdown-it-` 前缀同样是可以忽略的。 + +``` js +module.exports = { + markdown: { + plugins: [ + '@org/foo', // 等价于 @org/markdown-it-foo,如果对应的包存在 + ['markdown-it-bar', { + // 提供你的选项 + }] + ] + } +} +``` + +or + +``` js +module.exports = { + markdown: { + plugins: { + '@org/foo': {} + 'markdown-it-bar': { + // 提供你的选项 + } + } + } +} +``` + ### markdown.extendMarkdown - 类型: `Function`