UNPKG

zoro-cli

Version:

https://github.com/vuejs/vue-cli

261 lines (231 loc) 7.64 kB
const url = require('url') const path = require('path') const fs = require('fs-extra') const { importFrom } = require('zoro-cli-util/import') const chalk = require('chalk') const webpack = require('webpack') const WebpackDevServer = require('webpack-dev-server') const portfinder = require('portfinder') const args = require('minimist')(process.argv.slice(2)) const Configurator = require('./Configurator.js') const prepareURLs = require('./util/prepareURLs') const prepareProxy = require('./util/prepareProxy') const envUtil = require('./env') const { writePortSync } = require('./port') // const launchEditorMiddleware = require('launch-editor-middleware') // const { openBrowser } = require('@vue/cli-shared-utils'); console.info('Starting development server...') // 设置默认的 NODE_ENV if (!process.env.NODE_ENV) { process.env.NODE_ENV = 'development' } const isProduction = envUtil.isProduction() const defaults = { mode: 'development', host: '0.0.0.0', port: 9000, https: false, } // resolve webpack config const configurator = new Configurator({ args }) const options = configurator.projectOptions const webpackConfig = configurator.resolveWebpackConfig() // load user devServer options with higher priority than devServer // in webpck config const projectDevServerOptions = Object.assign( webpackConfig.devServer || {}, options.devServer, ) // resolve server options const useHttps = args.https || projectDevServerOptions.https || defaults.https const protocol = useHttps ? 'https' : 'http' const host = args.host || projectDevServerOptions.host || defaults.host portfinder.basePort = args.port || projectDevServerOptions.port || defaults.port function addDevClientToEntry(config, devClient) { const { entry } = config if (typeof entry === 'object' && !Array.isArray(entry)) { Object.keys(entry).forEach(key => { entry[key] = devClient.concat(entry[key]) }) } else if (typeof entry === 'function') { config.entry = entry(devClient) } else { config.entry = devClient.concat(entry) } } function forEachPlugin(category, cb) { const pluginDir = path.join(__dirname, `plugin/${category}`) if (fs.existsSync(pluginDir)) { const idToPlugin = (dir, id) => ({ id: id.replace(/^\.\//, 'built-in:'), dir, apply: importFrom(path.join(dir, id), './index'), }) fs.readdirSync(pluginDir) .filter(name => name.charAt(0) !== '.') .map(name => idToPlugin(pluginDir, name)) .forEach(({ apply }) => { if (apply) { cb(apply) } }) } } function applyServePlugins(obj) { forEachPlugin('serve', apply => { apply({ addDevClientToEntry, ...obj }) }) } function applyServeDonePlugins(obj) { forEachPlugin('serve-done', apply => { apply({ options, ...obj }) }) } portfinder .getPortPromise() .then(port => { writePortSync(port) // do not remove .port, anyproxy need it (it has been added to .gitignore) // process.on('exit', () => fs.removeSync(portFile)) const rawPublicUrl = args.public || projectDevServerOptions.public let publicUrl if (rawPublicUrl) { publicUrl = /^[a-zA-Z]+:\/\//.test(rawPublicUrl) ? rawPublicUrl : `${protocol}://${rawPublicUrl}` } const urls = prepareURLs(protocol, host, port, options.baseUrl) const proxySettings = prepareProxy( projectDevServerOptions.proxy, path.resolve('public'), ) // inject dev & hot-reload middleware entries if (!isProduction) { const sockjsUrl = publicUrl ? // explicitly configured via devServer.public `?${publicUrl}/sockjs-node` : '?' + url.format({ protocol, port, hostname: urls.lanUrlForConfig || 'localhost', pathname: '/sockjs-node', }) // console.log(sockjsUrl) const devClients = [ // dev server client require.resolve('webpack-dev-server/client') + sockjsUrl, ] if (!args.nohmr) { devClients.push( // hmr client require.resolve( projectDevServerOptions.hotOnly ? 'webpack/hot/only-dev-server' : 'webpack/hot/dev-server', ), ) } // inject dev/hot client addDevClientToEntry(webpackConfig, devClients) // load plugins applyServePlugins({ webpackConfig }) } // inspect webpackConfig if (args.inspect || configurator.projectOptions.inspect) { require('./util/inspectWebpackConfig')(webpackConfig) } // create compiler const compiler = webpack(webpackConfig) // create server const server = new WebpackDevServer(compiler, { clientLogLevel: 'none', historyApiFallback: { disableDotRule: true, rewrites: [ { from: /./, to: path.posix.join(options.baseUrl, 'index.html'), }, ], }, contentBase: path.resolve('public'), watchContentBase: !isProduction, hot: !isProduction && !args.nohmr, quiet: true, compress: isProduction, publicPath: options.baseUrl, overlay: isProduction // TODO disable this ? false : { warnings: false, errors: true }, disableHostCheck: true, ...projectDevServerOptions, https: useHttps, // https://stackoverflow.com/questions/10175812/how-to-create-a-self-signed-certificate-with-openssl key: fs.readFileSync(path.resolve(__dirname, './server.key')), cert: fs.readFileSync(path.resolve(__dirname, './server.crt')), proxy: proxySettings, before(app) { // allow other plugins to register middlewares, e.g. PWA // api.service.devServerConfigFns.forEach(fn => fn(app)); // apply in project middlewares projectDevServerOptions.before && projectDevServerOptions.before(app) }, }) ;['SIGINT', 'SIGTERM'].forEach(signal => { process.on(signal, () => { server.close(() => { process.exit(0) }) }) }) // log instructions & open browser on first compilation complete let isFirstCompile = true compiler.hooks.done.tap('cli serve', stats => { if (stats.hasErrors()) { return } let copied = '' if (isFirstCompile && args.copy) { require('clipboardy').write(urls.localUrlForBrowser) copied = chalk.dim('(copied to clipboard)') } console.log() console.log( [ ' App running at:', ` - Local: ${chalk.cyan(urls.localUrlForTerminal)} ${copied}`, ` - Network: ${chalk.cyan(urls.lanUrlForTerminal)}`, ].join('\n'), ) applyServeDonePlugins({ port, https: useHttps, stats }) if (isFirstCompile) { isFirstCompile = false if (!isProduction) { const buildCommand = 'npm run build' console.log() console.log(' Note that the development build is not optimized.') console.log( ` To create a production build, run ${chalk.cyan(buildCommand)}.`, ) } else { console.log() console.log(' App is served in production mode.') console.log(' Note this is for preview or E2E testing only.') } if (args.open || projectDevServerOptions.open) { // openBrowser(urls.localUrlForBrowser); } } }) server.listen(port, host, err => { if (err) { console.error(err) throw err } }) }) .catch(err => { console.error(err) throw err })