diff --git a/packages/@vuepress/core/lib/node/loadTheme.js b/packages/@vuepress/core/lib/node/loadTheme.js index 3cba5c0dbe..2ad934e276 100755 --- a/packages/@vuepress/core/lib/node/loadTheme.js +++ b/packages/@vuepress/core/lib/node/loadTheme.js @@ -93,11 +93,10 @@ function resolveTheme (ctx, resolver, ignoreLocal, theme) { path = localThemePath name = shortcut = 'local' logger.tip(`Apply local theme at ${chalk.gray(path)}...`) - - // 2. From dep } else if (isString(theme)) { + // 2. From dep const resolved = resolver.resolve(theme, sourceDir) - if (resolved.entry === null) { + if (!resolved.entry) { throw new Error(`Cannot resolve theme: ${theme}.`) } path = normalizeThemePath(resolved) @@ -108,7 +107,7 @@ function resolveTheme (ctx, resolver, ignoreLocal, theme) { } try { - entry = pluginAPI.normalizePlugin(path, ctx.themeConfig) + entry = pluginAPI.normalizePlugin('theme', path, ctx.themeConfig) } catch (error) { entry = {} } diff --git a/packages/@vuepress/core/lib/node/plugin-api/index.js b/packages/@vuepress/core/lib/node/plugin-api/index.js index 5a9da13a36..b2b31d6bfc 100644 --- a/packages/@vuepress/core/lib/node/plugin-api/index.js +++ b/packages/@vuepress/core/lib/node/plugin-api/index.js @@ -85,7 +85,7 @@ module.exports = class PluginAPI { plugin = pluginRaw } else { try { - plugin = this.normalizePlugin(pluginRaw, pluginOptions) + plugin = this.normalizePlugin('plugin', pluginRaw, pluginOptions) } catch (e) { logger.warn(e.message) return this @@ -116,10 +116,14 @@ module.exports = class PluginAPI { * @api public */ - normalizePlugin (pluginRaw, pluginOptions = {}) { + normalizePlugin (type, pluginRaw, pluginOptions = {}) { let plugin = this._pluginResolver.resolve(pluginRaw) if (!plugin.entry) { - throw new Error(`[vuepress] cannot resolve plugin "${pluginRaw}"`) + if (plugin.error) { + throw new Error(`[vuepress] An error was encounted in ${type} "${pluginRaw}"`) + } else { + throw new Error(`[vuepress] Cannot resolve ${type} "${pluginRaw}"`) + } } plugin = flattenPlugin(plugin, pluginOptions, this._pluginContext, this) plugin.$$normalized = true diff --git a/packages/@vuepress/shared-utils/src/moduleResolver.ts b/packages/@vuepress/shared-utils/src/moduleResolver.ts index ecab531b3f..c41e8b334d 100644 --- a/packages/@vuepress/shared-utils/src/moduleResolver.ts +++ b/packages/@vuepress/shared-utils/src/moduleResolver.ts @@ -24,22 +24,17 @@ const SCOPE_PACKAGE_RE = /^@(.*)\/(.*)/ */ export class CommonModule { - name: string | null - entry: string | null - shortcut: string | null - fromDep: boolean | null - constructor ( - entry: string | null, - name: string | null, - shortcut: string | null, - fromDep: boolean | null, - ) { - this.entry = entry - this.shortcut = shortcut - this.name = name - this.fromDep = fromDep - } + public entry: string | null, + public name: string | null, + public shortcut: string | null, + public fromDep: boolean | null, + public error?: Error + ) {} +} + +function getNoopModule(error?: Error) { + return new CommonModule(null, null, null, null, error) } export interface NormalizedModuleRequest { @@ -99,17 +94,15 @@ class ModuleResolver { } const isStringRequest = isString(req) - const isAbsolutePath = isStringRequest && path.isAbsolute(req) const resolved = tryChain<string, CommonModule>([ [this.resolveNonStringPackage.bind(this), !isStringRequest], - [this.resolveAbsolutePathPackage.bind(this), isStringRequest && isAbsolutePath], - [this.resolveRelativePathPackage.bind(this), isStringRequest && !isAbsolutePath], + [this.resolvePathPackage.bind(this), isStringRequest], [this.resolveDepPackage.bind(this), isStringRequest] ], req) if (!resolved) { - return new CommonModule(null, null, null, null /* fromDep */) + return getNoopModule() } return resolved @@ -128,16 +121,20 @@ class ModuleResolver { * Resolve non-string package, return directly. */ - private resolveNonStringPackage (req: string) { - const { shortcut, name } = <NormalizedModuleRequest>this.normalizeRequest(req) + private resolveNonStringPackage (req: any) { + const { shortcut, name } = this.normalizeRequest(req) return new CommonModule(req, name, shortcut, false /* fromDep */) } /** - * Resolve module with absolute path. + * Resolve module with absolute/relative path. */ - resolveAbsolutePathPackage (req: string) { + resolvePathPackage (req: string) { + if (!path.isAbsolute(req)) { + req = path.resolve(this.cwd, req) + } + const normalized = fsExistsFallback([ req, req + '.js', @@ -149,18 +146,13 @@ class ModuleResolver { } const dirname = path.parse(normalized).name - const { shortcut, name } = this.normalizeRequest(dirname) - const module = this.load ? require(normalized) : normalized - return new CommonModule(module, name, shortcut, false /* fromDep */) - } - - /** - * Resolve module with absolute path. - */ - - private resolveRelativePathPackage (req: string) { - req = path.resolve(process.cwd(), req) - return this.resolveAbsolutePathPackage(req) + const { shortcut, name } = this.normalizeName(dirname) + try { + const module = this.load ? require(normalized) : normalized + return new CommonModule(module, name, shortcut, false /* fromDep */) + } catch (error) { + return getNoopModule(error) + } } /** @@ -168,11 +160,15 @@ class ModuleResolver { */ private resolveDepPackage (req: string) { - const { shortcut, name } = this.normalizeRequest(req) - const entry = this.load - ? loadModule(<string>name, this.cwd) - : resolveModule(<string>name, this.cwd) - return new CommonModule(entry, name, shortcut, true /* fromDep */) + const { shortcut, name } = this.normalizeName(req) + try { + const entry = this.load + ? loadModule(<string>name, this.cwd) + : resolveModule(<string>name, this.cwd) + return new CommonModule(entry, name, shortcut, true /* fromDep */) + } catch (error) { + return getNoopModule(error) + } } /** @@ -190,8 +186,8 @@ class ModuleResolver { */ normalizeName (req: string): NormalizedModuleRequest { - let name - let shortcut + let name = null + let shortcut = null if (req.startsWith('@')) { const pkg = resolveScopePackage(req) @@ -213,7 +209,6 @@ class ModuleResolver { name = `${this.nonScopePrefix}${shortcut}` } - // @ts-ignore return { name, shortcut } }