Skip to content

Commit

Permalink
feat: modern mode
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Jun 13, 2018
1 parent e15fa20 commit 204d8f0
Show file tree
Hide file tree
Showing 9 changed files with 350 additions and 213 deletions.
11 changes: 9 additions & 2 deletions packages/@vue/babel-preset-app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,22 @@ module.exports = (context, options = {}) => {

const targets = process.env.VUE_CLI_BABEL_TARGET_NODE
? { node: 'current' }
: rawTargets
: process.env.VUE_CLI_MODERN_BUILD
? { esmodules: true }
: rawTargets

// included-by-default polyfills. These are common polyfills that 3rd party
// dependencies may rely on (e.g. Vuex relies on Promise), but since with
// useBuiltIns: 'usage' we won't be running Babel on these deps, they need to
// be force-included.
let polyfills
const buildTarget = process.env.VUE_CLI_TARGET || 'app'
if (buildTarget === 'app' && useBuiltIns === 'usage' && !process.env.VUE_CLI_BABEL_TARGET_NODE) {
if (
buildTarget === 'app' &&
useBuiltIns === 'usage' &&
!process.env.VUE_CLI_BABEL_TARGET_NODE &&
!process.env.VUE_CLI_MODERN_BUILD
) {
polyfills = getPolyfills(targets, userPolyfills || defaultPolyfills, {
ignoreBrowserslistConfig,
configPath
Expand Down
3 changes: 2 additions & 1 deletion packages/@vue/cli-plugin-babel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ module.exports = (api, options) => {
.options(api.genCacheConfig('babel-loader', {
'@babel/core': require('@babel/core/package.json').version,
'@vue/babel-preset-app': require('@vue/babel-preset-app').version,
'babel-loader': require('babel-loader/package.json').version
'babel-loader': require('babel-loader/package.json').version,
modern: !!process.env.VUE_CLI_MODERN_BUILD
}, 'babel.config.js'))
.end()

Expand Down
293 changes: 150 additions & 143 deletions packages/@vue/cli-service/lib/commands/build/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ module.exports = (api, options) => {
'--no-clean': `do not remove the dist directory before building the project`,
'--watch': `watch for changes`
}
}, async function build (args) {
}, async (args) => {
for (const key in defaults) {
if (args[key] == null) {
args[key] = defaults[key]
Expand All @@ -32,161 +32,168 @@ module.exports = (api, options) => {
args.entry = args.entry || 'src/App.vue'
}

const fs = require('fs-extra')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const formatStats = require('./formatStats')
const {
log,
done,
info,
logWithSpinner,
stopSpinner
} = require('@vue/cli-shared-utils')

log()
const mode = api.service.mode
if (args.target === 'app') {
logWithSpinner(`Building for ${mode}...`)
if (options.modernMode && args.target === 'app') {
delete process.env.VUE_CLI_MODERN_BUILD
await build(Object.assign({}, args, {
modern: false
}), api, options)

process.env.VUE_CLI_MODERN_BUILD = true
await build(Object.assign({}, args, {
modern: true,
clean: false
}), api, options)
} else {
const buildMode = buildModes[args.target]
if (buildMode) {
logWithSpinner(`Building for ${mode} as ${buildMode}...`)
} else {
throw new Error(`Unknown build target: ${args.target}`)
}
}

const targetDir = api.resolve(args.dest || options.outputDir)

// respect inline build destination in copy plugin
if (args.dest) {
api.chainWebpack(config => {
if (config.plugins.has('copy')) {
config.plugin('copy').tap(args => {
args[0][0].to = targetDir
return args
})
}
})
return build(args, api, options)
}
})
}

// resolve raw webpack config
process.env.VUE_CLI_BUILD_TARGET = args.target
let webpackConfig
if (args.target === 'lib') {
webpackConfig = require('./resolveLibConfig')(api, args, options)
} else if (
args.target === 'wc' ||
args.target === 'wc-async'
) {
webpackConfig = require('./resolveWcConfig')(api, args, options)
async function build (args, api, options) {
const fs = require('fs-extra')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const formatStats = require('./formatStats')
const {
log,
done,
info,
logWithSpinner,
stopSpinner
} = require('@vue/cli-shared-utils')

log()
const mode = api.service.mode
if (args.target === 'app') {
const bundleTag = options.modernMode
? args.modern
? `modern bundle `
: `legacy bundle `
: ``
logWithSpinner(`Building ${bundleTag}for ${mode}...`)
} else {
const buildMode = buildModes[args.target]
if (buildMode) {
logWithSpinner(`Building for ${mode} as ${buildMode}...`)
} else {
webpackConfig = api.resolveWebpackConfig()
if (args.entry && !options.pages) {
webpackConfig.entry = { app: api.resolve(args.entry) }
}
throw new Error(`Unknown build target: ${args.target}`)
}

// apply inline dest path after user configureWebpack hooks
// so it takes higher priority
if (args.dest) {
const applyDest = config => {
config.output.path = targetDir
}
if (Array.isArray(webpackConfig)) {
webpackConfig.forEach(applyDest)
} else {
applyDest(webpackConfig)
}
}

// grab the actual output path and check for common mis-configuration
const actualTargetDir = (
Array.isArray(webpackConfig)
? webpackConfig[0]
: webpackConfig
).output.path

if (args.watch) {
webpackConfig.watch = true
}

if (!args.dest && actualTargetDir !== api.resolve(options.outputDir)) {
// user directly modifies output.path in configureWebpack or chainWebpack.
// this is not supported because there's no way for us to give copy
// plugin the correct value this way.
console.error(chalk.red(
`\n\nConfiguration Error: ` +
`Avoid modifying webpack output.path directly. ` +
`Use the "outputDir" option instead.\n`
))
process.exit(1)
}

const targetDir = api.resolve(args.dest || options.outputDir)

// resolve raw webpack config
process.env.VUE_CLI_BUILD_TARGET = args.target
let webpackConfig
if (args.target === 'lib') {
webpackConfig = require('./resolveLibConfig')(api, args, options)
} else if (
args.target === 'wc' ||
args.target === 'wc-async'
) {
webpackConfig = require('./resolveWcConfig')(api, args, options)
} else {
webpackConfig = require('./resolveAppConfig')(api, args, options)
}

// apply inline dest path after user configureWebpack hooks
// so it takes higher priority
if (args.dest) {
const applyDest = config => {
config.output.path = targetDir
}

if (actualTargetDir === api.service.context) {
console.error(chalk.red(
`\n\nConfiguration Error: ` +
`Do not set output directory to project root.\n`
))
process.exit(1)
}

if (args.clean) {
await fs.remove(targetDir)
}

// Expose advanced stats
if (args.dashboard) {
const DashboardPlugin = require('../../webpack/DashboardPlugin')
;(webpackConfig.plugins = webpackConfig.plugins || []).push(new DashboardPlugin({
type: 'build'
}))
if (Array.isArray(webpackConfig)) {
webpackConfig.forEach(applyDest)
} else {
applyDest(webpackConfig)
}
}

// grab the actual output path and check for common mis-configuration
const actualTargetDir = (
Array.isArray(webpackConfig)
? webpackConfig[0]
: webpackConfig
).output.path

if (args.watch) {
webpackConfig.watch = true
}

if (!args.dest && actualTargetDir !== api.resolve(options.outputDir)) {
// user directly modifies output.path in configureWebpack or chainWebpack.
// this is not supported because there's no way for us to give copy
// plugin the correct value this way.
console.error(chalk.red(
`\n\nConfiguration Error: ` +
`Avoid modifying webpack output.path directly. ` +
`Use the "outputDir" option instead.\n`
))
process.exit(1)
}

if (actualTargetDir === api.service.context) {
console.error(chalk.red(
`\n\nConfiguration Error: ` +
`Do not set output directory to project root.\n`
))
process.exit(1)
}

if (args.clean) {
await fs.remove(targetDir)
}

// Expose advanced stats
if (args.dashboard) {
const DashboardPlugin = require('../../webpack/DashboardPlugin')
;(webpackConfig.plugins = webpackConfig.plugins || []).push(new DashboardPlugin({
type: 'build'
}))
}

return new Promise((resolve, reject) => {
webpack(webpackConfig, (err, stats) => {
stopSpinner(false)
if (err) {
return reject(err)
}

return new Promise((resolve, reject) => {
webpack(webpackConfig, (err, stats) => {
stopSpinner(false)
if (err) {
return reject(err)
}

if (stats.hasErrors()) {
return reject(`Build failed with errors.`)
}
if (stats.hasErrors()) {
return reject(`Build failed with errors.`)
}

if (!args.silent) {
const targetDirShort = path.relative(
api.service.context,
targetDir
)
log(formatStats(stats, targetDirShort, api))
if (args.target === 'app') {
if (!args.watch) {
done(`Build complete. The ${chalk.cyan(targetDirShort)} directory is ready to be deployed.\n`)
} else {
done(`Build complete. Watching for changes...`)
}
if (
options.baseUrl === '/' &&
// only log the tips if this is the first build
!fs.existsSync(api.resolve('node_modules/.cache'))
) {
info(`The app is built assuming that it will be deployed at the root of a domain.`)
info(`If you intend to deploy it under a subpath, update the ${chalk.green('baseUrl')} option`)
info(`in your project config (${chalk.cyan(`vue.config.js`)} or ${chalk.green('"vue"')} field in ${chalk.cyan(`package.json`)}).\n`)
}
if (!args.silent) {
const targetDirShort = path.relative(
api.service.context,
targetDir
)
log(formatStats(stats, targetDirShort, api))
if (args.target === 'app' && !(options.modernMode && !args.modern)) {
if (!args.watch) {
done(`Build complete. The ${chalk.cyan(targetDirShort)} directory is ready to be deployed.\n`)
} else {
done(`Build complete. Watching for changes...`)
}
if (
options.baseUrl === '/' &&
// only log the tips if this is the first build
!fs.existsSync(api.resolve('node_modules/.cache'))
) {
info(`The app is built assuming that it will be deployed at the root of a domain.`)
info(`If you intend to deploy it under a subpath, update the ${chalk.green('baseUrl')} option`)
info(`in your project config (${chalk.cyan(`vue.config.js`)} or ${chalk.green('"vue"')} field in ${chalk.cyan(`package.json`)}).\n`)
}
}
}

// test-only signal
if (process.env.VUE_CLI_TEST) {
console.log('Build complete.')
}
// test-only signal
if (process.env.VUE_CLI_TEST) {
console.log('Build complete.')
}

resolve()
})
resolve()
})
})
}
Expand Down
37 changes: 37 additions & 0 deletions packages/@vue/cli-service/lib/commands/build/resolveAppConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module.exports = (api, args, options) => {
const config = api.resolveChainableWebpackConfig()
const targetDir = api.resolve(args.dest || options.outputDir)

// respect inline build destination in copy plugin
if (args.dest && config.plugins.has('copy')) {
config.plugin('copy').tap(args => {
args[0][0].to = targetDir
return args
})
}

if (options.modernMode) {
const ModernModePlugin = require('../../webpack/ModernModePlugin')
const isModernBuild = !!process.env.VUE_CLI_MODERN_BUILD
if (!isModernBuild) {
// Inject plugin to extract build stats and write to disk
config
.plugin('modern-mode-legacy')
.use(ModernModePlugin, [targetDir, false])
} else {
// Inject plugin to read non-modern build stats and inject HTML
config
.plugin('modern-mode-modern')
.use(ModernModePlugin, [targetDir, true])
}
}

const rawConfig = config.toConfig()

// respect inline entry
if (args.entry && !options.pages) {
rawConfig.entry = { app: api.resolve(args.entry) }
}

return rawConfig
}
Loading

0 comments on commit 204d8f0

Please sign in to comment.