Skip to content

Commit

Permalink
feat: pass plugins and theme via cli
Browse files Browse the repository at this point in the history
  • Loading branch information
ulivz committed Aug 11, 2018
1 parent c004fb3 commit 0d7fce7
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 94 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@
node_modules
*.log
.temp
vuepress
TODOs.md
161 changes: 82 additions & 79 deletions packages/@vuepress/cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,98 +23,101 @@ if (!semver.satisfies(process.version, requiredVersion)) {
process.exit(1)
}

const path = require('path')
const { dev, build, eject } = require('@vuepress/core')

const program = require('commander')

program
.version(pkg.version)
.usage('<command> [options]')

program
.command('dev [targetDir]')
.description('start development server')
.option('-p, --port <port>', 'use specified port (default: 8080)')
.option('-h, --host <host>', 'use specified host (default: 0.0.0.0)')
.option('--debug', 'start development server in debug mode')
.action((dir = '.', { host, port, debug }) => {
wrapCommand(dev)(path.resolve(dir), { host, port, debug })
})
exports.program = program
exports.bootstrap = function ({
plugins,
theme
} = {}) {
const path = require('path')
const { dev, build, eject } = require('@vuepress/core')

program
.version(pkg.version)
.usage('<command> [options]')

program
.command('dev [targetDir]')
.description('start development server')
.option('-p, --port <port>', 'use specified port (default: 8080)')
.option('-h, --host <host>', 'use specified host (default: 0.0.0.0)')
.option('--debug', 'start development server in debug mode')
.action((dir = '.', { host, port, debug }) => {
wrapCommand(dev)(path.resolve(dir), { host, port, debug, plugins, theme })
})

program
.command('build [targetDir]')
.description('build dir as static site')
.option('-d, --dest <outDir>', 'specify build output dir (default: .vuepress/dist)')
.option('--debug', 'build in development mode for debugging')
.action((dir = '.', { debug, dest }) => {
const outDir = dest ? path.resolve(dest) : null
wrapCommand(build)(path.resolve(dir), { debug, outDir })
})
program
.command('build [targetDir]')
.description('build dir as static site')
.option('-d, --dest <outDir>', 'specify build output dir (default: .vuepress/dist)')
.option('--debug', 'build in development mode for debugging')
.action((dir = '.', { debug, dest }) => {
const outDir = dest ? path.resolve(dest) : null
wrapCommand(build)(path.resolve(dir), { debug, outDir, plugins, theme })
})

program
.command('eject [targetDir]')
.description('copy the default theme into .vuepress/theme for customization.')
.action((dir = '.') => {
wrapCommand(eject)(path.resolve(dir))
})
program
.command('eject [targetDir]')
.description('copy the default theme into .vuepress/theme for customization.')
.action((dir = '.') => {
wrapCommand(eject)(path.resolve(dir))
})

// output help information on unknown commands
program
.arguments('<command>')
.action((cmd) => {
program.outputHelp()
console.log(` ` + chalk.red(`Unknown command ${chalk.yellow(cmd)}.`))
// output help information on unknown commands
program
.arguments('<command>')
.action((cmd) => {
program.outputHelp()
console.log(` ` + chalk.red(`Unknown command ${chalk.yellow(cmd)}.`))
console.log()
})

// add some useful info on help
program.on('--help', () => {
console.log()
console.log(` Run ${chalk.cyan(`vuepress <command> --help`)} for detailed usage of given command.`)
console.log()
})

// add some useful info on help
program.on('--help', () => {
console.log()
console.log(` Run ${chalk.cyan(`vuepress <command> --help`)} for detailed usage of given command.`)
console.log()
})

program.commands.forEach(c => c.on('--help', () => console.log()))

// enhance common error messages
const enhanceErrorMessages = (methodName, log) => {
program.Command.prototype[methodName] = function (...args) {
if (methodName === 'unknownOption' && this._allowUnknownOption) {
return
program.commands.forEach(c => c.on('--help', () => console.log()))

// enhance common error messages
const enhanceErrorMessages = (methodName, log) => {
program.Command.prototype[methodName] = function (...args) {
if (methodName === 'unknownOption' && this._allowUnknownOption) {
return
}
this.outputHelp()
console.log(` ` + chalk.red(log(...args)))
console.log()
process.exit(1)
}
this.outputHelp()
console.log(` ` + chalk.red(log(...args)))
console.log()
process.exit(1)
}
}

enhanceErrorMessages('missingArgument', argName => {
return `Missing required argument ${chalk.yellow(`<${argName}>`)}.`
})

enhanceErrorMessages('unknownOption', optionName => {
return `Unknown option ${chalk.yellow(optionName)}.`
})

enhanceErrorMessages('optionMissingArgument', (option, flag) => {
return `Missing required argument for option ${chalk.yellow(option.flags)}` + (
flag ? `, got ${chalk.yellow(flag)}` : ``
)
})

function wrapCommand (fn) {
return (...args) => {
return fn(...args).catch(err => {
console.error(chalk.red(err.stack))
process.exitCode = 1
})
enhanceErrorMessages('missingArgument', argName => {
return `Missing required argument ${chalk.yellow(`<${argName}>`)}.`
})

enhanceErrorMessages('unknownOption', optionName => {
return `Unknown option ${chalk.yellow(optionName)}.`
})

enhanceErrorMessages('optionMissingArgument', (option, flag) => {
return `Missing required argument for option ${chalk.yellow(option.flags)}` + (
flag ? `, got ${chalk.yellow(flag)}` : ``
)
})

function wrapCommand (fn) {
return (...args) => {
return fn(...args).catch(err => {
console.error(chalk.red(err.stack))
process.exitCode = 1
})
}
}
}

exports.program = program
exports.bootstrap = function () {
program.parse(process.argv)
if (!process.argv.slice(2).length) {
program.outputHelp()
Expand Down
2 changes: 1 addition & 1 deletion packages/@vuepress/core/lib/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module.exports = async function build (sourceDir, cliOptions = {}) {
const { normalizeHeadTag, applyUserWebpackConfig } = require('./util/index')

logger.wait('\nExtracting site metadata...')
const options = await prepare(sourceDir, true /* isProd */)
const options = await prepare({ sourceDir, cliOptions, isProd: true })
if (cliOptions.outDir) {
options.outDir = cliOptions.outDir
}
Expand Down
2 changes: 1 addition & 1 deletion packages/@vuepress/core/lib/dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module.exports = async function dev (sourceDir, cliOptions = {}) {
const { frontmatterEmitter } = require('./webpack/markdownLoader')

logger.wait('\nExtracting site metadata...')
const options = await prepare(sourceDir, false /* isProd */)
const options = await prepare({ sourceDir, cliOptions, isProd: false })

// setup watchers to update options and dynamically generated files
const update = () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/@vuepress/core/lib/plugin-api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ module.exports = class Plugin {
clientRootMixin,
additionalPages
}) {
logger.tip(`\nApply plugin ${chalk.cyan(name)}...`)
logger.tip(`\nApply plugin ${chalk.gray(name)}...`)

this
.registerHook(HOOK.READY, ready, name, [Function])
Expand Down
8 changes: 6 additions & 2 deletions packages/@vuepress/core/lib/prepare/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ const { writeTemp } = require('./util')
const logger = require('../util/logger')
const chalk = require('chalk')

module.exports = async function prepare (sourceDir, isProd) {
module.exports = async function prepare ({
sourceDir,
isProd,
cliOptions
}) {
// 1. load options
const options = await resolveOptions(sourceDir)
const options = await resolveOptions(sourceDir, cliOptions)
options.isProd = isProd
const { markdown } = options

Expand Down
1 change: 0 additions & 1 deletion packages/@vuepress/core/lib/prepare/loadConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const yamlParser = require('js-yaml')
const tomlParser = require('toml')

module.exports = function loadConfig (vuepressDir, bustCache = true) {
console.log(vuepressDir)
const configPath = path.resolve(vuepressDir, 'config.js')
const configYmlPath = path.resolve(vuepressDir, 'config.yml')
const configTomlPath = path.resolve(vuepressDir, 'config.toml')
Expand Down
22 changes: 15 additions & 7 deletions packages/@vuepress/core/lib/prepare/resolveOptions.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
const fs = require('fs-extra')
const path = require('path')
const chalk = require('chalk')
const fs = require('fs-extra')
const globby = require('globby')
const createMarkdown = require('../markdown/index')
const loadConfig = require('./loadConfig')
const { sort } = require('./util')
const logger = require('../util/logger')

module.exports = async function resolveOptions (sourceDir) {
module.exports = async function resolveOptions (sourceDir, cliOptions) {
function requireResolve (target) {
return require.resolve(target, {
paths: [
Expand Down Expand Up @@ -44,13 +46,17 @@ module.exports = async function resolveOptions (sourceDir) {
// 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')
Expand All @@ -61,29 +67,30 @@ module.exports = async function resolveOptions (sourceDir) {
if (!fs.existsSync(themeNotFoundPath)) {
throw new Error(`[vuepress] Cannot resolve NotFound.vue file in .vuepress/theme.`)
}
} else if (siteConfig.theme) {
} else if (theme) {
// use external theme
try {
// backward-compatible 0.x.x.
themeLayoutPath = requireResolve(`vuepress-theme-${siteConfig.theme}/Layout.vue`)
themeLayoutPath = requireResolve(`vuepress-theme-${theme}/Layout.vue`)
themePath = path.dirname(themeLayoutPath)
themeNotFoundPath = path.resolve(themeLayoutPath, 'NotFound.vue')
} catch (e) {
try {
themeIndexFile = requireResolve(`vuepress-theme-${siteConfig.theme}/index.js`)
themeIndexFile = requireResolve(`vuepress-theme-${theme}/index.js`)
} catch (e) {
try {
themeIndexFile = requireResolve(`@vuepress/theme-${siteConfig.theme}`)
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 "${siteConfig.theme}". File vuepress-theme-${siteConfig.theme}/Layout.vue does not exist.`)
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`)
}
Expand Down Expand Up @@ -117,6 +124,7 @@ module.exports = async function resolveOptions (sourceDir) {
themeLayoutPath,
themeNotFoundPath,
themePlugins,
cliPlugins: cliOptions.plugins || [],
markdown
}

Expand Down
3 changes: 2 additions & 1 deletion packages/@vuepress/core/lib/prepare/resolvePlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ const enhanceAppPlugin = require('@vuepress/plugin-enhance-app')
const registerGlobalComponentsPlugin = require('@vuepress/plugin-register-global-components')

module.exports = function (options) {
const { siteConfig, themeConfig, sourceDir, themePath, themePlugins } = options
const { siteConfig, themeConfig, sourceDir, themePath, themePlugins, cliPlugins } = options
const pluginContext = new PluginContext(options)
const plugin = new Plugin(pluginContext)

plugin
// user plugin
.useByConfigs(cliPlugins)
.useByConfigs(siteConfig.plugins)
.useByConfigs(themePlugins)
// built-in plugins
Expand Down
40 changes: 40 additions & 0 deletions packages/vuepress/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "vuepress",
"version": "1.0.0",
"description": "Minimalistic doc generator with Vue component based layout system",
"main": "index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/vuejs/vuepress.git"
},
"keywords": [
"documentation",
"vue",
"generator"
],
"bin": {
"vuepress": "vuepress.js"
},
"author": "Evan You",
"license": "MIT",
"bugs": {
"url": "https://github.com/vuejs/vuepress/issues"
},
"homepage": "https://github.com/vuejs/vuepress#readme",
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.{js,vue}": [
"eslint --fix",
"git add"
]
},
"dependencies": {
"@vuepress/core": "^1.0.0",
"@vuepress/cli": "^1.0.0",
"@vuepress/theme-default": "^1.0.0",
"@vuepress/plugin-test": "^1.0.0",
"@vuepress/plugin-translation-ui": "^1.0.0"
}
}
9 changes: 9 additions & 0 deletions packages/vuepress/vuepress.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env node

require('@vuepress/cli').bootstrap({
theme: 'default',
plugins: [
'test',
'translation-ui'
]
})

0 comments on commit 0d7fce7

Please sign in to comment.