mirror of
https://github.com/vuejs/vue-cli.git
synced 2026-04-21 11:58:36 -05:00
feat: auto DLL
This commit is contained in:
@@ -102,13 +102,6 @@ module.exports = (api, options) => {
|
||||
child_process: 'empty'
|
||||
})
|
||||
|
||||
const htmlPath = api.resolve('public/index.html')
|
||||
webpackConfig
|
||||
.plugin('html')
|
||||
.use(require('html-webpack-plugin'), [
|
||||
fs.existsSync(htmlPath) ? { template: htmlPath } : {}
|
||||
])
|
||||
|
||||
// inject preload/prefetch to HTML
|
||||
const PreloadPlugin = require('../webpack/PreloadPlugin')
|
||||
webpackConfig
|
||||
@@ -126,6 +119,13 @@ module.exports = (api, options) => {
|
||||
include: 'asyncChunks'
|
||||
}])
|
||||
|
||||
const htmlPath = api.resolve('public/index.html')
|
||||
webpackConfig
|
||||
.plugin('html')
|
||||
.use(require('html-webpack-plugin'), [
|
||||
fs.existsSync(htmlPath) ? { template: htmlPath } : {}
|
||||
])
|
||||
|
||||
webpackConfig
|
||||
.plugin('define')
|
||||
.use(require('webpack/lib/DefinePlugin'), [
|
||||
|
||||
@@ -42,95 +42,99 @@ module.exports = (api, options) => {
|
||||
])
|
||||
|
||||
// minify JS
|
||||
const UglifyPlugin = require('uglifyjs-webpack-plugin')
|
||||
const uglifyPluginOptions = {
|
||||
uglifyOptions: {
|
||||
compress: {
|
||||
// turn off flags with small gains to speed up minification
|
||||
arrows: false,
|
||||
collapse_vars: false, // 0.3kb
|
||||
comparisons: false,
|
||||
computed_props: false,
|
||||
hoist_funs: false,
|
||||
hoist_props: false,
|
||||
hoist_vars: false,
|
||||
inline: false,
|
||||
loops: false,
|
||||
negate_iife: false,
|
||||
properties: false,
|
||||
reduce_funcs: false,
|
||||
reduce_vars: false,
|
||||
switches: false,
|
||||
toplevel: false,
|
||||
typeofs: false,
|
||||
|
||||
// a few flags with noticable gains/speed ratio
|
||||
// numbers based on out of the box vendor bundle
|
||||
booleans: true, // 0.7kb
|
||||
if_return: true, // 0.4kb
|
||||
sequences: true, // 0.7kb
|
||||
unused: true, // 2.3kb
|
||||
|
||||
// required features to drop conditional branches
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true
|
||||
}
|
||||
},
|
||||
sourceMap: options.productionSourceMap,
|
||||
cache: true,
|
||||
parallel: true
|
||||
}
|
||||
// disable during tests to speed things up
|
||||
if (!process.env.VUE_CLI_TEST) {
|
||||
webpackConfig
|
||||
.plugin('uglifyjs')
|
||||
.use(require('uglifyjs-webpack-plugin'), [{
|
||||
uglifyOptions: {
|
||||
compress: {
|
||||
// turn off flags with small gains to speed up minification
|
||||
arrows: false,
|
||||
collapse_vars: false, // 0.3kb
|
||||
comparisons: false,
|
||||
computed_props: false,
|
||||
hoist_funs: false,
|
||||
hoist_props: false,
|
||||
hoist_vars: false,
|
||||
inline: false,
|
||||
loops: false,
|
||||
negate_iife: false,
|
||||
properties: false,
|
||||
reduce_funcs: false,
|
||||
reduce_vars: false,
|
||||
switches: false,
|
||||
toplevel: false,
|
||||
typeofs: false,
|
||||
|
||||
// a few flags with noticable gains/speed ratio
|
||||
// numbers based on out of the box vendor bundle
|
||||
booleans: true, // 0.7kb
|
||||
if_return: true, // 0.4kb
|
||||
sequences: true, // 0.7kb
|
||||
unused: true, // 2.3kb
|
||||
|
||||
// required features to drop conditional branches
|
||||
conditionals: true,
|
||||
dead_code: true,
|
||||
evaluate: true
|
||||
}
|
||||
},
|
||||
sourceMap: options.productionSourceMap,
|
||||
cache: true,
|
||||
parallel: true
|
||||
}])
|
||||
.plugin('uglify')
|
||||
.use(UglifyPlugin, [uglifyPluginOptions])
|
||||
}
|
||||
|
||||
// Chunk splits
|
||||
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin')
|
||||
|
||||
// extract vendor libs into its own chunk for better caching, since they
|
||||
// are more likely to stay the same.
|
||||
webpackConfig
|
||||
.plugin('split-vendor')
|
||||
.use(CommonsChunkPlugin, [{
|
||||
name: 'vendor',
|
||||
minChunks (module) {
|
||||
// any required modules inside node_modules are extracted to vendor
|
||||
return (
|
||||
module.resource &&
|
||||
/\.js$/.test(module.resource) &&
|
||||
module.resource.indexOf(`node_modules`) > -1
|
||||
)
|
||||
}
|
||||
}])
|
||||
// Chunk splits
|
||||
if (!options.dll) {
|
||||
// extract vendor libs into its own chunk for better caching, since they
|
||||
// are more likely to stay the same.
|
||||
webpackConfig
|
||||
.plugin('split-vendor')
|
||||
.use(CommonsChunkPlugin, [{
|
||||
name: 'vendor',
|
||||
minChunks (module) {
|
||||
// any required modules inside node_modules are extracted to vendor
|
||||
return (
|
||||
module.resource &&
|
||||
/\.js$/.test(module.resource) &&
|
||||
module.resource.indexOf(`node_modules`) > -1
|
||||
)
|
||||
}
|
||||
}])
|
||||
|
||||
// extract webpack runtime and module manifest to its own file in order to
|
||||
// prevent vendor hash from being updated whenever app bundle is updated
|
||||
webpackConfig
|
||||
.plugin('split-manifest')
|
||||
.use(CommonsChunkPlugin, [{
|
||||
name: 'manifest',
|
||||
minChunks: Infinity
|
||||
}])
|
||||
// extract webpack runtime and module manifest to its own file in order to
|
||||
// prevent vendor hash from being updated whenever app bundle is updated
|
||||
webpackConfig
|
||||
.plugin('split-manifest')
|
||||
.use(CommonsChunkPlugin, [{
|
||||
name: 'manifest',
|
||||
minChunks: Infinity
|
||||
}])
|
||||
|
||||
// inline the manifest chunk into HTML
|
||||
webpackConfig
|
||||
.plugin('inline-manifest')
|
||||
.use(require('../webpack/InlineSourcePlugin'), [{
|
||||
include: /manifest\..*\.js$/
|
||||
}])
|
||||
// inline the manifest chunk into HTML
|
||||
webpackConfig
|
||||
.plugin('inline-manifest')
|
||||
.use(require('../webpack/InlineSourcePlugin'), [{
|
||||
include: /manifest\..*\.js$/
|
||||
}])
|
||||
|
||||
// since manifest is inlined, don't preload it anymore
|
||||
webpackConfig
|
||||
.plugin('preload')
|
||||
.tap(([options]) => {
|
||||
options.fileBlacklist.push(/manifest\..*\.js$/)
|
||||
return [options]
|
||||
})
|
||||
// since manifest is inlined, don't preload it anymore
|
||||
webpackConfig
|
||||
.plugin('preload')
|
||||
.tap(([options]) => {
|
||||
options.fileBlacklist.push(/manifest\..*\.js$/)
|
||||
return [options]
|
||||
})
|
||||
}
|
||||
|
||||
// This instance extracts shared chunks from code splitted chunks and bundles them
|
||||
// in a separate chunk, similar to the vendor chunk
|
||||
// This CommonsChunkPlugin instance extracts shared chunks from async
|
||||
// chunks and bundles them in a separate chunk, similar to the vendor chunk
|
||||
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
|
||||
webpackConfig
|
||||
.plugin('split-vendor-async')
|
||||
@@ -141,6 +145,36 @@ module.exports = (api, options) => {
|
||||
minChunks: 3
|
||||
}])
|
||||
|
||||
// DLL
|
||||
if (options.dll) {
|
||||
const webpack = require('webpack')
|
||||
const resolveClientEnv = require('../util/resolveClientEnv')
|
||||
const dllEntries = Array.isArray(options.dll)
|
||||
? options.dll
|
||||
: Object.keys(api.service.pkg.dependencies)
|
||||
|
||||
webpackConfig
|
||||
.plugin('dll')
|
||||
.use(require('autodll-webpack-plugin'), [{
|
||||
inject: true,
|
||||
inherit: true,
|
||||
path: 'js/',
|
||||
context: api.resolve('.'),
|
||||
filename: '[name].[hash:8].js',
|
||||
entry: {
|
||||
'vendor': [
|
||||
...dllEntries,
|
||||
'vue-loader/lib/component-normalizer'
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin(resolveClientEnv(options.baseUrl)),
|
||||
new UglifyPlugin(uglifyPluginOptions)
|
||||
]
|
||||
}])
|
||||
.after('preload')
|
||||
}
|
||||
|
||||
// copy static assets in public/
|
||||
webpackConfig
|
||||
.plugin('copy')
|
||||
@@ -162,8 +196,6 @@ module.exports = (api, options) => {
|
||||
// .before('vue-loader')
|
||||
// .loader('thread-loader')
|
||||
// .options({ name: 'vue' })
|
||||
|
||||
// TODO DLL
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,6 +6,10 @@ const schema = createSchema(joi => joi.object({
|
||||
compiler: joi.boolean(),
|
||||
productionSourceMap: joi.boolean(),
|
||||
vueLoader: joi.object(),
|
||||
dll: joi.alternatives().try(
|
||||
joi.boolean(),
|
||||
joi.array().items(joi.string())
|
||||
),
|
||||
css: joi.object({
|
||||
modules: joi.boolean(),
|
||||
extract: joi.boolean(),
|
||||
|
||||
@@ -57,6 +57,18 @@ module.exports = class PreloadPlugin {
|
||||
apply (compiler) {
|
||||
const options = this.options
|
||||
compiler.plugin('compilation', compilation => {
|
||||
// Auto DLL plugin injects assets by mutating html plugin data, so the only
|
||||
// way to get a hold of those is by saving the pre-mutated assets and
|
||||
// comparing them later.
|
||||
let originalAssets
|
||||
compilation.plugin('html-webpack-plugin-before-html-generation', (htmlPluginData, cb) => {
|
||||
originalAssets = [
|
||||
...htmlPluginData.assets.js,
|
||||
...htmlPluginData.assets.css
|
||||
]
|
||||
cb(null, htmlPluginData)
|
||||
})
|
||||
|
||||
compilation.plugin('html-webpack-plugin-before-html-processing', (htmlPluginData, cb) => {
|
||||
let filesToInclude = ''
|
||||
let extractedChunks = []
|
||||
@@ -95,11 +107,22 @@ module.exports = class PreloadPlugin {
|
||||
|
||||
const publicPath = compilation.outputOptions.publicPath || ''
|
||||
|
||||
// Only handle the chunk import by the htmlWebpackPlugin
|
||||
// Only handle the chunk imported by the htmlWebpackPlugin
|
||||
extractedChunks = extractedChunks.filter(chunk => doesChunkBelongToHTML(
|
||||
chunk, getValues(htmlPluginData.assets.chunks), {}))
|
||||
|
||||
flatten(extractedChunks.map(chunk => chunk.files)).filter(entry => {
|
||||
let files = flatten(extractedChunks.map(chunk => chunk.files))
|
||||
|
||||
// if handling initial or all chunks, also include assets injected by
|
||||
// Auto DLL plugin.
|
||||
if (options.include === 'initial' || options.include === 'all') {
|
||||
files = [...htmlPluginData.assets.js, ...htmlPluginData.assets.css]
|
||||
.filter(file => !originalAssets.includes(file))
|
||||
.map(file => file.replace(publicPath, ''))
|
||||
.concat(files)
|
||||
}
|
||||
|
||||
Array.from(new Set(files)).filter(entry => {
|
||||
return this.options.fileBlacklist.every(regex => regex.test(entry) === false)
|
||||
}).forEach(entry => {
|
||||
entry = `${publicPath}${entry}`
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"@vue/cli-overlay": "^3.0.0-alpha.1",
|
||||
"@vue/cli-shared-utils": "^3.0.0-alpha.1",
|
||||
"address": "^1.0.3",
|
||||
"autodll-webpack-plugin": "^0.3.8",
|
||||
"autoprefixer": "^7.2.5",
|
||||
"case-sensitive-paths-webpack-plugin": "^2.1.1",
|
||||
"chalk": "^2.3.0",
|
||||
|
||||
@@ -1003,6 +1003,21 @@ atob@^2.0.0:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d"
|
||||
|
||||
autodll-webpack-plugin@^0.3.8:
|
||||
version "0.3.8"
|
||||
resolved "https://registry.yarnpkg.com/autodll-webpack-plugin/-/autodll-webpack-plugin-0.3.8.tgz#d087dda8ca3f9e3231a15df3d42d1efde73c5777"
|
||||
dependencies:
|
||||
bluebird "^3.5.0"
|
||||
del "^3.0.0"
|
||||
find-cache-dir "^1.0.0"
|
||||
lodash "^4.17.4"
|
||||
make-dir "^1.0.0"
|
||||
memory-fs "^0.4.1"
|
||||
mkdirp "^0.5.1"
|
||||
read-pkg "^2.0.0"
|
||||
webpack-merge "^4.1.0"
|
||||
webpack-sources "^1.0.1"
|
||||
|
||||
autoprefixer@^6.3.1:
|
||||
version "6.7.7"
|
||||
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
|
||||
@@ -9796,7 +9811,7 @@ webpack-dev-server@^2.11.0:
|
||||
webpack-dev-middleware "1.12.2"
|
||||
yargs "6.6.0"
|
||||
|
||||
webpack-merge@^4.1.1:
|
||||
webpack-merge@^4.1.0, webpack-merge@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.1.tgz#f1197a0a973e69c6fbeeb6d658219aa8c0c13555"
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user