feat: better log (#506)

This commit is contained in:
ULIVZ
2018-05-26 18:04:48 +08:00
committed by GitHub
parent d531073c4f
commit d53807ea1e
6 changed files with 124 additions and 35 deletions
+7 -6
View File
@@ -8,13 +8,14 @@ module.exports = async function build (sourceDir, cliOptions = {}) {
const readline = require('readline')
const escape = require('escape-html')
const logger = require('./util/logger')
const prepare = require('./prepare')
const createClientConfig = require('./webpack/createClientConfig')
const createServerConfig = require('./webpack/createServerConfig')
const { createBundleRenderer } = require('vue-server-renderer')
const { normalizeHeadTag, applyUserWebpackConfig } = require('./util')
process.stdout.write('Extracting site metadata...')
logger.wait('\nExtracting site metadata...')
const options = await prepare(sourceDir)
if (cliOptions.outDir) {
options.outDir = cliOptions.outDir
@@ -22,7 +23,7 @@ module.exports = async function build (sourceDir, cliOptions = {}) {
const { outDir } = options
if (path.resolve() === outDir) {
return console.error(chalk.red('Unexpected option: outDir cannot be set to the current working directory.\n'))
return console.error(logger.error(chalk.red('Unexpected option: outDir cannot be set to the current working directory.\n'), false))
}
await fs.remove(outDir)
@@ -64,7 +65,7 @@ module.exports = async function build (sourceDir, cliOptions = {}) {
.join('\n ')
// render pages
console.log('Rendering static HTML...')
logger.wait('Rendering static HTML...')
for (const page of options.siteData.pages) {
await renderPage(page)
}
@@ -78,7 +79,7 @@ module.exports = async function build (sourceDir, cliOptions = {}) {
readline.cursorTo(process.stdout, 0)
if (options.siteConfig.serviceWorker) {
console.log('Generating service worker...')
logger.wait('\nGenerating service worker...')
const wbb = require('workbox-build')
wbb.generateSW({
swDest: path.resolve(outDir, 'service-worker.js'),
@@ -89,7 +90,7 @@ module.exports = async function build (sourceDir, cliOptions = {}) {
// DONE.
const relativeDir = path.relative(process.cwd(), outDir)
console.log(`\n${chalk.green('Success!')} Generated static files in ${chalk.cyan(relativeDir)}.`)
logger.success(`\n${chalk.green('Success!')} Generated static files in ${chalk.cyan(relativeDir)}.\n`)
// --- helpers ---
@@ -150,7 +151,7 @@ module.exports = async function build (sourceDir, cliOptions = {}) {
try {
html = await renderer.renderToString(context)
} catch (e) {
console.error(chalk.red(`Error rendering ${pagePath}:`))
console.error(logger.error(chalk.red(`Error rendering ${pagePath}:`), false))
throw e
}
const filename = decodeURIComponent(pagePath.replace(/\/$/, '/index.html').replace(/^\//, ''))
+36 -27
View File
@@ -9,21 +9,22 @@ module.exports = async function dev (sourceDir, cliOptions = {}) {
const mount = require('koa-mount')
const serveStatic = require('koa-static')
const history = require('connect-history-api-fallback')
const portfinder = require('portfinder')
const prepare = require('./prepare')
const logger = require('./util/logger')
const HeadPlugin = require('./webpack/HeadPlugin')
const DevLogPlugin = require('./webpack/DevLogPlugin')
const createClientConfig = require('./webpack/createClientConfig')
const { applyUserWebpackConfig } = require('./util')
const { frontmatterEmitter } = require('./webpack/markdownLoader')
process.stdout.write('Extracting site metadata...')
logger.wait('\nExtracting site metadata...')
const options = await prepare(sourceDir)
// setup watchers to update options and dynamically generated files
const update = () => {
prepare(sourceDir).catch(err => {
console.error(chalk.red(err.stack))
console.error(logger.error(chalk.red(err.stack), false))
})
}
@@ -67,6 +68,17 @@ module.exports = async function dev (sourceDir, cliOptions = {}) {
tags: options.siteConfig.head || []
}])
const port = await resolvePort(cliOptions.port || options.siteConfig.port)
const { host, displayHost } = await resolveHost(cliOptions.host || options.siteConfig.host)
config
.plugin('vuepress-log')
.use(DevLogPlugin, [{
port,
displayHost,
publicPath: options.publicPath
}])
config = config.toConfig()
const userConfig = options.siteConfig.configureWebpack
if (userConfig) {
@@ -74,30 +86,6 @@ module.exports = async function dev (sourceDir, cliOptions = {}) {
}
const compiler = webpack(config)
// webpack-serve hot updates doesn't work properly over 0.0.0.0 on Windows,
// but localhost does not allow visiting over network :/
const defaultHost = process.platform === 'win32' ? 'localhost' : '0.0.0.0'
const host = cliOptions.host || options.siteConfig.host || defaultHost
const displayHost = host === defaultHost && process.platform !== 'win32'
? 'localhost'
: host
portfinder.basePort = cliOptions.port || options.siteConfig.port || 8080
const port = await portfinder.getPortPromise()
let isFirst = true
compiler.hooks.done.tap('vuepress', () => {
if (isFirst) {
isFirst = false
console.log(
`\n VuePress dev server listening at ${
chalk.cyan(`http://${displayHost}:${port}${options.publicPath}`)
}\n`
)
} else {
const time = new Date().toTimeString().match(/^[\d:]+/)[0]
console.log(` ${chalk.gray(`[${time}]`)} ${chalk.green('✔')} successfully compiled.`)
}
})
const nonExistentDir = path.resolve(__dirname, 'non-existent')
await serve({
@@ -128,3 +116,24 @@ module.exports = async function dev (sourceDir, cliOptions = {}) {
}
})
}
function resolveHost (host) {
// webpack-serve hot updates doesn't work properly over 0.0.0.0 on Windows,
// but localhost does not allow visiting over network :/
const defaultHost = process.platform === 'win32' ? 'localhost' : '0.0.0.0'
host = host || defaultHost
const displayHost = host === defaultHost && process.platform !== 'win32'
? 'localhost'
: host
return {
displayHost,
host
}
}
async function resolvePort (port) {
const portfinder = require('portfinder')
portfinder.basePort = port || 8080
port = await portfinder.getPortPromise()
return port
}
+2 -1
View File
@@ -1,6 +1,7 @@
const fs = require('fs-extra')
const path = require('path')
const chalk = require('chalk')
const logger = require('./util/logger')
module.exports = async (dir) => {
const source = path.resolve(__dirname, 'default-theme')
@@ -11,5 +12,5 @@ module.exports = async (dir) => {
const content = await fs.readFile(styleConfig, 'utf-8')
const transformed = content.split('\n').slice(0, -2).join('\n')
await fs.writeFile(styleConfig, transformed)
console.log(`Copied default theme into ${chalk.cyan(target)}.`)
logger.success(`\nCopied default theme into ${chalk.cyan(target)}.\n`)
}
+2 -1
View File
@@ -2,6 +2,7 @@ const chalk = require('chalk')
const prism = require('prismjs')
const loadLanguages = require('prismjs/components/index')
const escapeHtml = require('escape-html')
const logger = require('../util/logger')
// required to make embedded highlighting work...
loadLanguages(['markup', 'css', 'javascript'])
@@ -32,7 +33,7 @@ module.exports = (str, lang) => {
try {
loadLanguages([lang])
} catch (e) {
console.log(chalk.yellow(`[vuepress] Syntax highlight for language "${lang}" is not supported.`))
logger.warn(chalk.yellow(`[vuepress] Syntax highlight for language "${lang}" is not supported.`))
}
}
if (prism.languages[lang]) {
+48
View File
@@ -0,0 +1,48 @@
const chalk = require('chalk')
const logger = {}
const logTypes = {
success: {
color: 'green',
label: 'DONE'
},
error: {
color: 'red',
label: 'FAIL'
},
warn: {
color: 'yellow',
label: 'WARN'
},
tip: {
color: 'cyan',
label: 'TIP'
},
wait: {
color: 'blue',
label: 'WAIT'
}
}
const getLoggerFn = (color, label) => (msg, log = true) => {
let newLine = false
if (msg.startsWith('\n')) {
if (log) msg = msg.slice(1)
newLine = true
}
msg = chalk.reset.inverse.bold[color](` ${label} `) + ' ' + msg
if (log) {
console.log(newLine ? '\n' + msg : msg)
} else {
return msg
}
}
for (const type in logTypes) {
const { color, label } = logTypes[type]
logger[type] = getLoggerFn(color, label)
}
module.exports = logger
module.exports.getLoggerFn = getLoggerFn
+29
View File
@@ -0,0 +1,29 @@
const chalk = require('chalk')
const logger = require('../util/logger')
module.exports = class DevLogPlugin {
constructor (options) {
this.options = options
}
apply (compiler) {
let isFirst = true
compiler.hooks.done.tap('vuepress-log', stats => {
clearScreen()
const { displayHost, port, publicPath } = this.options
const time = new Date().toTimeString().match(/^[\d:]+/)[0]
logger.success(`\n${chalk.gray(`[${time}]`)} Build ${chalk.italic(stats.hash.slice(0, 6))} finished in ${stats.endTime - stats.startTime} ms!`)
if (isFirst) {
isFirst = false
console.log(`\n${chalk.gray('>')} VuePress dev server listening at ${chalk.cyan(`http://${displayHost}:${port}${publicPath}`)}`)
}
})
compiler.hooks.invalid.tap('vuepress-log', clearScreen)
}
}
function clearScreen () {
process.stdout.write('\x1Bc')
}