Skip to content

Commit 204d8f0

Browse files
committed
feat: modern mode
1 parent e15fa20 commit 204d8f0

File tree

9 files changed

+350
-213
lines changed

9 files changed

+350
-213
lines changed

packages/@vue/babel-preset-app/index.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,22 @@ module.exports = (context, options = {}) => {
5050

5151
const targets = process.env.VUE_CLI_BABEL_TARGET_NODE
5252
? { node: 'current' }
53-
: rawTargets
53+
: process.env.VUE_CLI_MODERN_BUILD
54+
? { esmodules: true }
55+
: rawTargets
5456

5557
// included-by-default polyfills. These are common polyfills that 3rd party
5658
// dependencies may rely on (e.g. Vuex relies on Promise), but since with
5759
// useBuiltIns: 'usage' we won't be running Babel on these deps, they need to
5860
// be force-included.
5961
let polyfills
6062
const buildTarget = process.env.VUE_CLI_TARGET || 'app'
61-
if (buildTarget === 'app' && useBuiltIns === 'usage' && !process.env.VUE_CLI_BABEL_TARGET_NODE) {
63+
if (
64+
buildTarget === 'app' &&
65+
useBuiltIns === 'usage' &&
66+
!process.env.VUE_CLI_BABEL_TARGET_NODE &&
67+
!process.env.VUE_CLI_MODERN_BUILD
68+
) {
6269
polyfills = getPolyfills(targets, userPolyfills || defaultPolyfills, {
6370
ignoreBrowserslistConfig,
6471
configPath

packages/@vue/cli-plugin-babel/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ module.exports = (api, options) => {
2929
.options(api.genCacheConfig('babel-loader', {
3030
'@babel/core': require('@babel/core/package.json').version,
3131
'@vue/babel-preset-app': require('@vue/babel-preset-app').version,
32-
'babel-loader': require('babel-loader/package.json').version
32+
'babel-loader': require('babel-loader/package.json').version,
33+
modern: !!process.env.VUE_CLI_MODERN_BUILD
3334
}, 'babel.config.js'))
3435
.end()
3536

packages/@vue/cli-service/lib/commands/build/index.js

Lines changed: 150 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ module.exports = (api, options) => {
2121
'--no-clean': `do not remove the dist directory before building the project`,
2222
'--watch': `watch for changes`
2323
}
24-
}, async function build (args) {
24+
}, async (args) => {
2525
for (const key in defaults) {
2626
if (args[key] == null) {
2727
args[key] = defaults[key]
@@ -32,161 +32,168 @@ module.exports = (api, options) => {
3232
args.entry = args.entry || 'src/App.vue'
3333
}
3434

35-
const fs = require('fs-extra')
36-
const path = require('path')
37-
const chalk = require('chalk')
38-
const webpack = require('webpack')
39-
const formatStats = require('./formatStats')
40-
const {
41-
log,
42-
done,
43-
info,
44-
logWithSpinner,
45-
stopSpinner
46-
} = require('@vue/cli-shared-utils')
47-
48-
log()
49-
const mode = api.service.mode
50-
if (args.target === 'app') {
51-
logWithSpinner(`Building for ${mode}...`)
35+
if (options.modernMode && args.target === 'app') {
36+
delete process.env.VUE_CLI_MODERN_BUILD
37+
await build(Object.assign({}, args, {
38+
modern: false
39+
}), api, options)
40+
41+
process.env.VUE_CLI_MODERN_BUILD = true
42+
await build(Object.assign({}, args, {
43+
modern: true,
44+
clean: false
45+
}), api, options)
5246
} else {
53-
const buildMode = buildModes[args.target]
54-
if (buildMode) {
55-
logWithSpinner(`Building for ${mode} as ${buildMode}...`)
56-
} else {
57-
throw new Error(`Unknown build target: ${args.target}`)
58-
}
59-
}
60-
61-
const targetDir = api.resolve(args.dest || options.outputDir)
62-
63-
// respect inline build destination in copy plugin
64-
if (args.dest) {
65-
api.chainWebpack(config => {
66-
if (config.plugins.has('copy')) {
67-
config.plugin('copy').tap(args => {
68-
args[0][0].to = targetDir
69-
return args
70-
})
71-
}
72-
})
47+
return build(args, api, options)
7348
}
49+
})
50+
}
7451

75-
// resolve raw webpack config
76-
process.env.VUE_CLI_BUILD_TARGET = args.target
77-
let webpackConfig
78-
if (args.target === 'lib') {
79-
webpackConfig = require('./resolveLibConfig')(api, args, options)
80-
} else if (
81-
args.target === 'wc' ||
82-
args.target === 'wc-async'
83-
) {
84-
webpackConfig = require('./resolveWcConfig')(api, args, options)
52+
async function build (args, api, options) {
53+
const fs = require('fs-extra')
54+
const path = require('path')
55+
const chalk = require('chalk')
56+
const webpack = require('webpack')
57+
const formatStats = require('./formatStats')
58+
const {
59+
log,
60+
done,
61+
info,
62+
logWithSpinner,
63+
stopSpinner
64+
} = require('@vue/cli-shared-utils')
65+
66+
log()
67+
const mode = api.service.mode
68+
if (args.target === 'app') {
69+
const bundleTag = options.modernMode
70+
? args.modern
71+
? `modern bundle `
72+
: `legacy bundle `
73+
: ``
74+
logWithSpinner(`Building ${bundleTag}for ${mode}...`)
75+
} else {
76+
const buildMode = buildModes[args.target]
77+
if (buildMode) {
78+
logWithSpinner(`Building for ${mode} as ${buildMode}...`)
8579
} else {
86-
webpackConfig = api.resolveWebpackConfig()
87-
if (args.entry && !options.pages) {
88-
webpackConfig.entry = { app: api.resolve(args.entry) }
89-
}
80+
throw new Error(`Unknown build target: ${args.target}`)
9081
}
91-
92-
// apply inline dest path after user configureWebpack hooks
93-
// so it takes higher priority
94-
if (args.dest) {
95-
const applyDest = config => {
96-
config.output.path = targetDir
97-
}
98-
if (Array.isArray(webpackConfig)) {
99-
webpackConfig.forEach(applyDest)
100-
} else {
101-
applyDest(webpackConfig)
102-
}
103-
}
104-
105-
// grab the actual output path and check for common mis-configuration
106-
const actualTargetDir = (
107-
Array.isArray(webpackConfig)
108-
? webpackConfig[0]
109-
: webpackConfig
110-
).output.path
111-
112-
if (args.watch) {
113-
webpackConfig.watch = true
114-
}
115-
116-
if (!args.dest && actualTargetDir !== api.resolve(options.outputDir)) {
117-
// user directly modifies output.path in configureWebpack or chainWebpack.
118-
// this is not supported because there's no way for us to give copy
119-
// plugin the correct value this way.
120-
console.error(chalk.red(
121-
`\n\nConfiguration Error: ` +
122-
`Avoid modifying webpack output.path directly. ` +
123-
`Use the "outputDir" option instead.\n`
124-
))
125-
process.exit(1)
82+
}
83+
84+
const targetDir = api.resolve(args.dest || options.outputDir)
85+
86+
// resolve raw webpack config
87+
process.env.VUE_CLI_BUILD_TARGET = args.target
88+
let webpackConfig
89+
if (args.target === 'lib') {
90+
webpackConfig = require('./resolveLibConfig')(api, args, options)
91+
} else if (
92+
args.target === 'wc' ||
93+
args.target === 'wc-async'
94+
) {
95+
webpackConfig = require('./resolveWcConfig')(api, args, options)
96+
} else {
97+
webpackConfig = require('./resolveAppConfig')(api, args, options)
98+
}
99+
100+
// apply inline dest path after user configureWebpack hooks
101+
// so it takes higher priority
102+
if (args.dest) {
103+
const applyDest = config => {
104+
config.output.path = targetDir
126105
}
127-
128-
if (actualTargetDir === api.service.context) {
129-
console.error(chalk.red(
130-
`\n\nConfiguration Error: ` +
131-
`Do not set output directory to project root.\n`
132-
))
133-
process.exit(1)
134-
}
135-
136-
if (args.clean) {
137-
await fs.remove(targetDir)
138-
}
139-
140-
// Expose advanced stats
141-
if (args.dashboard) {
142-
const DashboardPlugin = require('../../webpack/DashboardPlugin')
143-
;(webpackConfig.plugins = webpackConfig.plugins || []).push(new DashboardPlugin({
144-
type: 'build'
145-
}))
106+
if (Array.isArray(webpackConfig)) {
107+
webpackConfig.forEach(applyDest)
108+
} else {
109+
applyDest(webpackConfig)
146110
}
111+
}
112+
113+
// grab the actual output path and check for common mis-configuration
114+
const actualTargetDir = (
115+
Array.isArray(webpackConfig)
116+
? webpackConfig[0]
117+
: webpackConfig
118+
).output.path
119+
120+
if (args.watch) {
121+
webpackConfig.watch = true
122+
}
123+
124+
if (!args.dest && actualTargetDir !== api.resolve(options.outputDir)) {
125+
// user directly modifies output.path in configureWebpack or chainWebpack.
126+
// this is not supported because there's no way for us to give copy
127+
// plugin the correct value this way.
128+
console.error(chalk.red(
129+
`\n\nConfiguration Error: ` +
130+
`Avoid modifying webpack output.path directly. ` +
131+
`Use the "outputDir" option instead.\n`
132+
))
133+
process.exit(1)
134+
}
135+
136+
if (actualTargetDir === api.service.context) {
137+
console.error(chalk.red(
138+
`\n\nConfiguration Error: ` +
139+
`Do not set output directory to project root.\n`
140+
))
141+
process.exit(1)
142+
}
143+
144+
if (args.clean) {
145+
await fs.remove(targetDir)
146+
}
147+
148+
// Expose advanced stats
149+
if (args.dashboard) {
150+
const DashboardPlugin = require('../../webpack/DashboardPlugin')
151+
;(webpackConfig.plugins = webpackConfig.plugins || []).push(new DashboardPlugin({
152+
type: 'build'
153+
}))
154+
}
155+
156+
return new Promise((resolve, reject) => {
157+
webpack(webpackConfig, (err, stats) => {
158+
stopSpinner(false)
159+
if (err) {
160+
return reject(err)
161+
}
147162

148-
return new Promise((resolve, reject) => {
149-
webpack(webpackConfig, (err, stats) => {
150-
stopSpinner(false)
151-
if (err) {
152-
return reject(err)
153-
}
154-
155-
if (stats.hasErrors()) {
156-
return reject(`Build failed with errors.`)
157-
}
163+
if (stats.hasErrors()) {
164+
return reject(`Build failed with errors.`)
165+
}
158166

159-
if (!args.silent) {
160-
const targetDirShort = path.relative(
161-
api.service.context,
162-
targetDir
163-
)
164-
log(formatStats(stats, targetDirShort, api))
165-
if (args.target === 'app') {
166-
if (!args.watch) {
167-
done(`Build complete. The ${chalk.cyan(targetDirShort)} directory is ready to be deployed.\n`)
168-
} else {
169-
done(`Build complete. Watching for changes...`)
170-
}
171-
if (
172-
options.baseUrl === '/' &&
173-
// only log the tips if this is the first build
174-
!fs.existsSync(api.resolve('node_modules/.cache'))
175-
) {
176-
info(`The app is built assuming that it will be deployed at the root of a domain.`)
177-
info(`If you intend to deploy it under a subpath, update the ${chalk.green('baseUrl')} option`)
178-
info(`in your project config (${chalk.cyan(`vue.config.js`)} or ${chalk.green('"vue"')} field in ${chalk.cyan(`package.json`)}).\n`)
179-
}
167+
if (!args.silent) {
168+
const targetDirShort = path.relative(
169+
api.service.context,
170+
targetDir
171+
)
172+
log(formatStats(stats, targetDirShort, api))
173+
if (args.target === 'app' && !(options.modernMode && !args.modern)) {
174+
if (!args.watch) {
175+
done(`Build complete. The ${chalk.cyan(targetDirShort)} directory is ready to be deployed.\n`)
176+
} else {
177+
done(`Build complete. Watching for changes...`)
178+
}
179+
if (
180+
options.baseUrl === '/' &&
181+
// only log the tips if this is the first build
182+
!fs.existsSync(api.resolve('node_modules/.cache'))
183+
) {
184+
info(`The app is built assuming that it will be deployed at the root of a domain.`)
185+
info(`If you intend to deploy it under a subpath, update the ${chalk.green('baseUrl')} option`)
186+
info(`in your project config (${chalk.cyan(`vue.config.js`)} or ${chalk.green('"vue"')} field in ${chalk.cyan(`package.json`)}).\n`)
180187
}
181188
}
189+
}
182190

183-
// test-only signal
184-
if (process.env.VUE_CLI_TEST) {
185-
console.log('Build complete.')
186-
}
191+
// test-only signal
192+
if (process.env.VUE_CLI_TEST) {
193+
console.log('Build complete.')
194+
}
187195

188-
resolve()
189-
})
196+
resolve()
190197
})
191198
})
192199
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
module.exports = (api, args, options) => {
2+
const config = api.resolveChainableWebpackConfig()
3+
const targetDir = api.resolve(args.dest || options.outputDir)
4+
5+
// respect inline build destination in copy plugin
6+
if (args.dest && config.plugins.has('copy')) {
7+
config.plugin('copy').tap(args => {
8+
args[0][0].to = targetDir
9+
return args
10+
})
11+
}
12+
13+
if (options.modernMode) {
14+
const ModernModePlugin = require('../../webpack/ModernModePlugin')
15+
const isModernBuild = !!process.env.VUE_CLI_MODERN_BUILD
16+
if (!isModernBuild) {
17+
// Inject plugin to extract build stats and write to disk
18+
config
19+
.plugin('modern-mode-legacy')
20+
.use(ModernModePlugin, [targetDir, false])
21+
} else {
22+
// Inject plugin to read non-modern build stats and inject HTML
23+
config
24+
.plugin('modern-mode-modern')
25+
.use(ModernModePlugin, [targetDir, true])
26+
}
27+
}
28+
29+
const rawConfig = config.toConfig()
30+
31+
// respect inline entry
32+
if (args.entry && !options.pages) {
33+
rawConfig.entry = { app: api.resolve(args.entry) }
34+
}
35+
36+
return rawConfig
37+
}

0 commit comments

Comments
 (0)