mirror of
https://github.com/vuejs/vue-cli.git
synced 2026-03-20 18:11:07 -05:00
feat: build --target lib/wc
This commit is contained in:
@@ -97,7 +97,8 @@ module.exports = class Service {
|
||||
'./config/base',
|
||||
'./config/css',
|
||||
'./config/dev',
|
||||
'./config/prod'
|
||||
'./config/prod',
|
||||
'./config/app'
|
||||
].map(idToPlugin)
|
||||
|
||||
if (inlinePlugins) {
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import Component from '~entry'
|
||||
|
||||
export default Component
|
||||
@@ -0,0 +1,6 @@
|
||||
// TODO
|
||||
|
||||
import Vue from 'vue'
|
||||
import Component from '~entry'
|
||||
|
||||
new Vue(Component)
|
||||
@@ -1,6 +1,7 @@
|
||||
const defaults = {
|
||||
mode: 'production',
|
||||
target: 'app'
|
||||
target: 'app',
|
||||
entry: 'src/App.vue'
|
||||
}
|
||||
|
||||
module.exports = (api, options) => {
|
||||
@@ -8,27 +9,37 @@ module.exports = (api, options) => {
|
||||
description: 'build for production',
|
||||
usage: 'vue-cli-service build [options]',
|
||||
options: {
|
||||
'--mode': `specify env mode (default: ${defaults.mode})`
|
||||
// TODO build target
|
||||
// '--target': `app | lib | web-component (default: ${defaults.target})`,
|
||||
// '--format': `How the lib is exposed (esm, umd, cjs, amd). Default: esm`
|
||||
// '--name': `Library name for umd/iife export`
|
||||
'--mode': `specify env mode (default: ${defaults.mode})`,
|
||||
'--target': `app | lib | web-component (default: ${defaults.target})`,
|
||||
'--entry': `entry for lib or web-component (default: ${defaults.entry})`,
|
||||
'--name': `name for lib or web-component (default: "name" in package.json)`
|
||||
}
|
||||
}, args => {
|
||||
api.setMode(args.mode || defaults.mode)
|
||||
args = Object.assign({}, defaults, args)
|
||||
api.setMode(args.mode)
|
||||
|
||||
const chalk = require('chalk')
|
||||
const rimraf = require('rimraf')
|
||||
const webpack = require('webpack')
|
||||
const {
|
||||
log,
|
||||
done,
|
||||
info,
|
||||
logWithSpinner,
|
||||
stopSpinner
|
||||
} = require('@vue/cli-shared-utils')
|
||||
|
||||
console.log()
|
||||
logWithSpinner(`Building for production...`)
|
||||
log()
|
||||
if (args.target === 'app') {
|
||||
logWithSpinner(`Building for production...`)
|
||||
} else {
|
||||
// setting this disables app-only configs
|
||||
process.env.VUE_CLI_TARGET = args.target
|
||||
// when building as a lib, inline all static asset files
|
||||
// since there is no publicPath handling
|
||||
process.env.VUE_CLI_INLINE_LIMIT = Infinity
|
||||
logWithSpinner(`Building for production as ${args.target}...`)
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const targetDir = api.resolve(options.outputDir)
|
||||
@@ -36,7 +47,14 @@ module.exports = (api, options) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
const webpackConfig = api.resolveWebpackConfig()
|
||||
let webpackConfig
|
||||
if (args.target === 'lib') {
|
||||
webpackConfig = require('./resolveLibConfig')(api, args)
|
||||
} else if (args.target === 'web-component') {
|
||||
webpackConfig = require('./resolveWebComponentConfig')(api, args)
|
||||
} else {
|
||||
webpackConfig = api.resolveWebpackConfig()
|
||||
}
|
||||
webpack(webpackConfig, (err, stats) => {
|
||||
stopSpinner(false)
|
||||
if (err) {
|
||||
@@ -57,7 +75,7 @@ module.exports = (api, options) => {
|
||||
return reject(`Build failed with errors.`)
|
||||
}
|
||||
|
||||
if (!args.silent) {
|
||||
if (!args.silent && args.target === 'app') {
|
||||
done(`Build complete. The ${chalk.cyan(options.outputDir)} directory is ready to be deployed.\n`)
|
||||
if (options.baseUrl === '/') {
|
||||
info(`The app is built assuming that it will be deployed at the root of a domain.`)
|
||||
@@ -0,0 +1,62 @@
|
||||
module.exports = (api, { entry, name }) => {
|
||||
const genConfig = (format, postfix = format) => {
|
||||
api.chainWebpack(config => {
|
||||
const libName = name || api.service.pkg.name
|
||||
|
||||
config.entryPoints.clear()
|
||||
// set proxy entry for *.vue files
|
||||
if (/\.vue$/.test(entry)) {
|
||||
config
|
||||
.entry(`${libName}.${postfix}`)
|
||||
.add(require.resolve('./entry-lib.js'))
|
||||
config.resolve
|
||||
.alias
|
||||
.set('~entry', api.resolve(entry))
|
||||
} else {
|
||||
config
|
||||
.entry(`${libName}.${postfix}`)
|
||||
.add(api.resolve(entry))
|
||||
}
|
||||
|
||||
config.output
|
||||
.filename(`[name].js`)
|
||||
.library(libName)
|
||||
.libraryExport('default')
|
||||
.libraryTarget(format)
|
||||
|
||||
// adjust css output name
|
||||
config
|
||||
.plugin('extract-css')
|
||||
.tap(args => {
|
||||
args[0].filename = `${libName}.css`
|
||||
return args
|
||||
})
|
||||
|
||||
// only minify min entry
|
||||
config
|
||||
.plugin('uglify')
|
||||
.tap(args => {
|
||||
args[0].include = /\.min\.js$/
|
||||
return args
|
||||
})
|
||||
|
||||
// externalize Vue in case user imports it
|
||||
config
|
||||
.externals({
|
||||
vue: {
|
||||
commonjs: 'vue',
|
||||
commonjs2: 'vue',
|
||||
root: 'Vue'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return api.resolveWebpackConfig()
|
||||
}
|
||||
|
||||
return [
|
||||
genConfig('commonjs2', 'common'),
|
||||
genConfig('umd'),
|
||||
genConfig('umd', 'umd.min')
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
module.exports = (api, { entry, name }) => {
|
||||
const genConfig = postfix => {
|
||||
api.chainWebpack(config => {
|
||||
const libName = name || api.service.pkg.name
|
||||
|
||||
config.entryPoints.clear()
|
||||
// set proxy entry for *.vue files
|
||||
if (/\.vue$/.test(entry)) {
|
||||
config
|
||||
.entry(`${libName}.${postfix}`)
|
||||
.add(require.resolve('./entry-web-component.js'))
|
||||
config.resolve
|
||||
.alias
|
||||
.set('~entry', api.resolve(entry))
|
||||
} else {
|
||||
config
|
||||
.entry(`${libName}.${postfix}`)
|
||||
.add(api.resolve(entry))
|
||||
}
|
||||
|
||||
config.output
|
||||
.filename(`[name].js`)
|
||||
|
||||
// only minify min entry
|
||||
config
|
||||
.plugin('uglify')
|
||||
.tap(args => {
|
||||
args[0].include = /\.min\.js$/
|
||||
return args
|
||||
})
|
||||
|
||||
// externalize Vue in case user imports it
|
||||
config
|
||||
.externals({
|
||||
vue: 'Vue'
|
||||
})
|
||||
|
||||
// TODO handle CSS (insert in shadow DOM)
|
||||
})
|
||||
|
||||
return api.resolveWebpackConfig()
|
||||
}
|
||||
|
||||
return [
|
||||
genConfig('web-component'),
|
||||
genConfig('web-component.min')
|
||||
]
|
||||
}
|
||||
156
packages/@vue/cli-service/lib/config/app.js
Normal file
156
packages/@vue/cli-service/lib/config/app.js
Normal file
@@ -0,0 +1,156 @@
|
||||
// config that are specific to --target app
|
||||
|
||||
module.exports = (api, options) => {
|
||||
api.chainWebpack(webpackConfig => {
|
||||
// only apply when there's no alternative target
|
||||
if (process.env.VUE_CLI_TARGET) {
|
||||
return
|
||||
}
|
||||
|
||||
// inject preload/prefetch to HTML
|
||||
const PreloadPlugin = require('../webpack/PreloadPlugin')
|
||||
webpackConfig
|
||||
.plugin('preload')
|
||||
.use(PreloadPlugin, [{
|
||||
rel: 'preload',
|
||||
include: 'initial',
|
||||
fileBlacklist: [/\.map$/, /hot-update\.js$/]
|
||||
}])
|
||||
|
||||
webpackConfig
|
||||
.plugin('prefetch')
|
||||
.use(PreloadPlugin, [{
|
||||
rel: 'prefetch',
|
||||
include: 'asyncChunks'
|
||||
}])
|
||||
|
||||
// HTML plugin
|
||||
const fs = require('fs')
|
||||
const htmlPath = api.resolve('public/index.html')
|
||||
const resolveClientEnv = require('../util/resolveClientEnv')
|
||||
webpackConfig
|
||||
.plugin('html')
|
||||
.use(require('html-webpack-plugin'), [
|
||||
Object.assign(
|
||||
fs.existsSync(htmlPath) ? { template: htmlPath } : {},
|
||||
// expose client env to html template
|
||||
{ env: resolveClientEnv(options.baseUrl, true /* raw */) }
|
||||
)
|
||||
])
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
// minify HTML
|
||||
webpackConfig
|
||||
.plugin('html')
|
||||
.tap(([options]) => [Object.assign(options, {
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true
|
||||
// more options:
|
||||
// https://github.com/kangax/html-minifier#options-quick-reference
|
||||
},
|
||||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
||||
chunksSortMode: 'dependency'
|
||||
})])
|
||||
|
||||
// Code splitting configs for better long-term caching
|
||||
// This needs to be updated when upgrading to webpack 4
|
||||
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin')
|
||||
|
||||
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
|
||||
}])
|
||||
|
||||
// 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]
|
||||
})
|
||||
}
|
||||
|
||||
// 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')
|
||||
.use(CommonsChunkPlugin, [{
|
||||
name: 'app',
|
||||
async: 'vendor-async',
|
||||
children: true,
|
||||
minChunks: 3
|
||||
}])
|
||||
|
||||
// DLL
|
||||
if (options.dll) {
|
||||
const webpack = require('webpack')
|
||||
const UglifyPlugin = require('uglifyjs-webpack-plugin')
|
||||
const getUglifyOptions = require('./uglifyOptions')
|
||||
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(getUglifyOptions(options))
|
||||
]
|
||||
}])
|
||||
.after('preload')
|
||||
}
|
||||
|
||||
// copy static assets in public/
|
||||
webpackConfig
|
||||
.plugin('copy')
|
||||
.use(require('copy-webpack-plugin'), [[{
|
||||
from: api.resolve('public'),
|
||||
to: api.resolve(options.outputDir),
|
||||
ignore: ['index.html', '.*']
|
||||
}]])
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
module.exports = (api, options) => {
|
||||
api.chainWebpack(webpackConfig => {
|
||||
const fs = require('fs')
|
||||
const resolveLocal = require('../util/resolveLocal')
|
||||
const resolveClientEnv = require('../util/resolveClientEnv')
|
||||
const inlineLimit = process.env.VUE_CLI_INLINE_LIMIT || 1000
|
||||
|
||||
webpackConfig
|
||||
.context(api.service.context)
|
||||
@@ -53,7 +52,7 @@ module.exports = (api, options) => {
|
||||
.use('url-loader')
|
||||
.loader('url-loader')
|
||||
.options({
|
||||
limit: 10000,
|
||||
limit: inlineLimit,
|
||||
name: `img/[name].[hash:8].[ext]`
|
||||
})
|
||||
|
||||
@@ -74,7 +73,7 @@ module.exports = (api, options) => {
|
||||
.use('url-loader')
|
||||
.loader('url-loader')
|
||||
.options({
|
||||
limit: 10000,
|
||||
limit: inlineLimit,
|
||||
name: `media/[name].[hash:8].[ext]`
|
||||
})
|
||||
|
||||
@@ -84,7 +83,7 @@ module.exports = (api, options) => {
|
||||
.use('url-loader')
|
||||
.loader('url-loader')
|
||||
.options({
|
||||
limit: 10000,
|
||||
limit: inlineLimit,
|
||||
name: `fonts/[name].[hash:8].[ext]`
|
||||
})
|
||||
|
||||
@@ -102,34 +101,7 @@ module.exports = (api, options) => {
|
||||
child_process: 'empty'
|
||||
})
|
||||
|
||||
// inject preload/prefetch to HTML
|
||||
const PreloadPlugin = require('../webpack/PreloadPlugin')
|
||||
webpackConfig
|
||||
.plugin('preload')
|
||||
.use(PreloadPlugin, [{
|
||||
rel: 'preload',
|
||||
include: 'initial',
|
||||
fileBlacklist: [/\.map$/, /hot-update\.js$/]
|
||||
}])
|
||||
|
||||
webpackConfig
|
||||
.plugin('prefetch')
|
||||
.use(PreloadPlugin, [{
|
||||
rel: 'prefetch',
|
||||
include: 'asyncChunks'
|
||||
}])
|
||||
|
||||
const htmlPath = api.resolve('public/index.html')
|
||||
webpackConfig
|
||||
.plugin('html')
|
||||
.use(require('html-webpack-plugin'), [
|
||||
Object.assign(
|
||||
fs.existsSync(htmlPath) ? { template: htmlPath } : {},
|
||||
// expose client env to html template
|
||||
{ env: resolveClientEnv(options.baseUrl, true /* raw */) }
|
||||
)
|
||||
])
|
||||
|
||||
const resolveClientEnv = require('../util/resolveClientEnv')
|
||||
webpackConfig
|
||||
.plugin('define')
|
||||
.use(require('webpack/lib/DefinePlugin'), [
|
||||
@@ -143,5 +115,15 @@ module.exports = (api, options) => {
|
||||
webpackConfig
|
||||
.plugin('case-sensitive-paths')
|
||||
.use(require('case-sensitive-paths-webpack-plugin'))
|
||||
|
||||
// friendly error plugin displays very confusing errors when webpack
|
||||
// fails to resolve a loader, so we provide custom handlers to improve it
|
||||
const { transformer, formatter } = require('../webpack/resolveLoaderError')
|
||||
webpackConfig
|
||||
.plugin('firendly-errors')
|
||||
.use(require('friendly-errors-webpack-plugin'), [{
|
||||
additionalTransformers: [transformer],
|
||||
additionalFormatters: [formatter]
|
||||
}])
|
||||
})
|
||||
}
|
||||
|
||||
@@ -18,16 +18,6 @@ module.exports = api => {
|
||||
.plugin('no-emit-on-errors')
|
||||
.use(require('webpack/lib/NoEmitOnErrorsPlugin'))
|
||||
|
||||
// friendly error plugin displays very confusing errors when webpack
|
||||
// fails to resolve a loader, so we provide custom handlers to improve it
|
||||
const { transformer, formatter } = require('../webpack/resolveLoaderError')
|
||||
webpackConfig
|
||||
.plugin('firendly-errors')
|
||||
.use(require('friendly-errors-webpack-plugin'), [{
|
||||
additionalTransformers: [transformer],
|
||||
additionalFormatters: [formatter]
|
||||
}])
|
||||
|
||||
webpackConfig
|
||||
.plugin('watch-missing')
|
||||
.use(
|
||||
|
||||
@@ -17,21 +17,6 @@ module.exports = (api, options) => {
|
||||
.plugin('module-concatenation')
|
||||
.use(require('webpack/lib/optimize/ModuleConcatenationPlugin'))
|
||||
|
||||
// minify HTML
|
||||
webpackConfig
|
||||
.plugin('html')
|
||||
.tap(([options]) => [Object.assign(options, {
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true
|
||||
// more options:
|
||||
// https://github.com/kangax/html-minifier#options-quick-reference
|
||||
},
|
||||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
||||
chunksSortMode: 'dependency'
|
||||
})])
|
||||
|
||||
// optimize CSS (dedupe)
|
||||
webpackConfig
|
||||
.plugin('optimize-css')
|
||||
@@ -43,159 +28,13 @@ 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
|
||||
}
|
||||
const getUglifyOptions = require('./uglifyOptions')
|
||||
// disable during tests to speed things up
|
||||
if (!process.env.VUE_CLI_TEST) {
|
||||
webpackConfig
|
||||
.plugin('uglify')
|
||||
.use(UglifyPlugin, [uglifyPluginOptions])
|
||||
.use(UglifyPlugin, [getUglifyOptions(options)])
|
||||
}
|
||||
|
||||
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin')
|
||||
|
||||
// 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
|
||||
}])
|
||||
|
||||
// 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]
|
||||
})
|
||||
}
|
||||
|
||||
// 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')
|
||||
.use(CommonsChunkPlugin, [{
|
||||
name: 'app',
|
||||
async: 'vendor-async',
|
||||
children: true,
|
||||
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')
|
||||
.use(require('copy-webpack-plugin'), [[{
|
||||
from: api.resolve('public'),
|
||||
to: api.resolve(options.outputDir),
|
||||
ignore: ['index.html', '.*']
|
||||
}]])
|
||||
|
||||
// TODO parallelazation
|
||||
// thread-loader doesn't seem to have obvious effect because vue-loader
|
||||
// offloads most of the work to other loaders. We may need to re-think
|
||||
// vue-loader implementation in order to better take advantage of
|
||||
// parallelazation
|
||||
|
||||
// webpackConfig.module
|
||||
// .rule('vue')
|
||||
// .use('thread-loader')
|
||||
// .before('vue-loader')
|
||||
// .loader('thread-loader')
|
||||
// .options({ name: 'vue' })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
38
packages/@vue/cli-service/lib/config/uglifyOptions.js
Normal file
38
packages/@vue/cli-service/lib/config/uglifyOptions.js
Normal file
@@ -0,0 +1,38 @@
|
||||
module.exports = options => ({
|
||||
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
|
||||
})
|
||||
Reference in New Issue
Block a user