Skip to content

feat!: update copy & terser plugin, move more legacy code to webpack-4 plugin #6279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/migrations/migrate-from-v4.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ No longer supports generating project with `node-sass`. It has been [deprecated]
* `html-webpack-plugin` is upgraded from v3 to v5, and for webpack 4 users, v4 will be used. More details are available in the [release announcement of `html-webpack-plugin` v4](https://dev.to/jantimon/html-webpack-plugin-4-has-been-released-125d) and the [full changelog](https://github.com/jantimon/html-webpack-plugin/blob/master/CHANGELOG.md).
* `sass-loader` v7 support is dropped. See the v8 breaking changes at its [changelog](https://github.com/webpack-contrib/sass-loader/blob/master/CHANGELOG.md#800-2019-08-29).
* `postcss-loader` is upgraded from v3 to v4. Most notably, `PostCSS` options (`plugin` / `syntax` / `parser` / `stringifier`) are moved into the `postcssOptions` field. More details available at the [changelog](https://github.com/webpack-contrib/postcss-loader/blob/master/CHANGELOG.md#400-2020-09-07).
* `copy-webpack-plugin` is upgraded from v5 to v6. If you never customized its config through `config.plugin('copy')`, there should be no user-facing breaking changes. A full list of breaking changes is available at [`copy-webpack-plugin` v6.0.0 release](https://github.com/webpack-contrib/copy-webpack-plugin/releases/tag/v6.0.0).
* `copy-webpack-plugin` is upgraded from v5 to v7 (v6 if you choose to stay at webpack 4). If you never customized its config through `config.plugin('copy')`, there should be no user-facing breaking changes. A full list of breaking changes is available at [`copy-webpack-plugin` v6.0.0 release](https://github.com/webpack-contrib/copy-webpack-plugin/releases/tag/v6.0.0) and [v7.0.0 release](https://github.com/webpack-contrib/copy-webpack-plugin/releases/tag/v7.0.0).
* `file-loader` is upgraded from v4 to v6, and `url-loader` from v2 to v4. The `esModule` option is now turned on by default for non-Vue-2 projects. Full changelog available at [`file-loader` changelog](https://github.com/webpack-contrib/file-loader/blob/master/CHANGELOG.md) and [`url-loader` changelog](https://github.com/webpack-contrib/url-loader/blob/master/CHANGELOG.md)
* `terser-webpack-plugin` is upgraded from v2 to v4, using terser 5 and some there are some changes in the options format. See full details in its [changelog](https://github.com/webpack-contrib/terser-webpack-plugin/blob/master/CHANGELOG.md#400-2020-08-04).
* `terser-webpack-plugin` is upgraded from v2 to v5 (v4 if you choose to stay at webpack 4), using terser 5 and some there are some changes in the options format. See full details in its [changelog](https://github.com/webpack-contrib/terser-webpack-plugin/blob/master/CHANGELOG.md).

### ESLint Plugin

Expand Down
104 changes: 104 additions & 0 deletions packages/@vue/cli-plugin-webpack-4/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const fs = require('fs')
const path = require('path')
const moduleAlias = require('module-alias')

Expand All @@ -10,4 +11,107 @@ moduleAlias.addAlias('html-webpack-plugin', htmlWebpackPlugin4Path)

/** @type {import('@vue/cli-service').ServicePlugin} */
module.exports = (api, options) => {
api.chainWebpack(config => {
// Node.js polyfills
// They are not polyfilled by default in webpack 5
// <https://github.com/webpack/webpack/pull/8460>
// In webpack 4, we used to disabled many of the core module polyfills too
config.node
.merge({
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// process is injected via DefinePlugin, although some 3rd party
// libraries may require a mock to work properly (#934)
process: 'mock',
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
})

// Yarn PnP / Yarn 2 support
config.resolve
.plugin('pnp')
.use({ ...require('pnp-webpack-plugin') })
.end()

config.resolveLoader
.plugin('pnp-loaders')
.use({ ...require('pnp-webpack-plugin').topLevelLoader })
.end()

if (!process.env.VUE_CLI_BUILD_TARGET || process.env.VUE_CLI_BUILD_TARGET === 'app') {
const isLegacyBundle = process.env.VUE_CLI_MODERN_MODE && !process.env.VUE_CLI_MODERN_BUILD
const publicDir = api.resolve('public')
if (!isLegacyBundle && fs.existsSync(publicDir)) {
const CopyWebpackPluginV6 = require('copy-webpack-plugin')
config
.plugin('copy')
.init((Plugin, args) => new CopyWebpackPluginV6(...args))
}

if (process.env.NODE_ENV === 'production') {
// In webpack 5, optimization.chunkIds is set to `deterministic` by default in production
// In webpack 4, we use the following trick to keep chunk ids stable so async chunks have consistent hash (#1916)
config
.plugin('named-chunks')
.use(require('webpack').NamedChunksPlugin, [chunk => {
if (chunk.name) {
return chunk.name
}

const hash = require('hash-sum')
const joinedHash = hash(
Array.from(chunk.modulesIterable, m => m.id).join('_')
)
return `chunk-` + joinedHash
}])
}

if (process.env.NODE_ENV !== 'test') {
config.optimization.splitChunks({
cacheGroups: {
vendors: {
name: `chunk-vendors`,
test: /[\\/]node_modules[\\/]/,
priority: -10,
chunks: 'initial'
},
common: {
name: `chunk-common`,
minChunks: 2,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true
}
}
})
}
}

if (process.env.NODE_ENV === 'production') {
const TerserPluginV4 = require('terser-webpack-plugin')
config.optimization.minimizer('terser').init(
(Plugin, [terserPluginOptions]) =>
new TerserPluginV4({
sourceMap: options.productionSourceMap,
cache: true,
...terserPluginOptions
})
)

// DeterministicModuleIdsPlugin is only available in webpack 5
// (and enabled by default in production mode).

// In webpack 4, we need HashedModuleIdsPlugin
// to keep module.id stable when vendor modules does not change.
// It is "the second best solution for long term caching".
// <https://github.com/webpack/webpack/pull/7399#discussion_r193970769>
config.optimization.set('hashedModuleIds', true)
}
})
}
4 changes: 4 additions & 0 deletions packages/@vue/cli-plugin-webpack-4/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@
"access": "public"
},
"dependencies": {
"copy-webpack-plugin": "^6.4.0",
"hash-sum": "^2.0.0",
"html-webpack-plugin": "^4.5.1",
"module-alias": "^2.2.2",
"pnp-webpack-plugin": "^1.6.4",
"terser-webpack-plugin": "^4.2.3",
"webpack": "^4.44.2"
},
"peerDependencies": {
Expand Down
74 changes: 16 additions & 58 deletions packages/@vue/cli-service/lib/config/app.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// config that are specific to --target app
const fs = require('fs')
const path = require('path')
const { semver } = require('@vue/cli-shared-utils')

// ensure the filename passed to html-webpack-plugin is a relative path
// because it cannot correctly handle absolute paths
Expand All @@ -14,9 +13,6 @@ function ensureRelative (outputDir, _path) {
}

module.exports = (api, options) => {
const webpack = require('webpack')
const webpackMajor = semver.major(webpack.version)

api.chainWebpack(webpackConfig => {
// only apply when there's no alternative target
if (process.env.VUE_CLI_BUILD_TARGET && process.env.VUE_CLI_BUILD_TARGET !== 'app') {
Expand All @@ -39,43 +35,23 @@ module.exports = (api, options) => {

// code splitting
if (process.env.NODE_ENV !== 'test') {
if (webpackMajor === 4) {
webpackConfig.optimization.splitChunks({
cacheGroups: {
vendors: {
name: `chunk-vendors`,
test: /[\\/]node_modules[\\/]/,
priority: -10,
chunks: 'initial'
},
common: {
name: `chunk-common`,
minChunks: 2,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true
}
}
})
} else {
webpackConfig.optimization.splitChunks({
cacheGroups: {
defaultVendors: {
name: `chunk-vendors`,
test: /[\\/]node_modules[\\/]/,
priority: -10,
chunks: 'initial'
},
common: {
name: `chunk-common`,
minChunks: 2,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true
}
webpackConfig.optimization.splitChunks({
cacheGroups: {
defaultVendors: {
name: `chunk-vendors`,
test: /[\\/]node_modules[\\/]/,
priority: -10,
chunks: 'initial'
},
common: {
name: `chunk-common`,
minChunks: 2,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true
}
})
}
}
})
}

// HTML plugin
Expand Down Expand Up @@ -116,24 +92,6 @@ module.exports = (api, options) => {
])
}

if (webpackMajor === 4 && isProd) {
// In webpack 5, optimization.chunkIds is set to `deterministic` by default in production
// In webpack 4, we use the following trick to keep chunk ids stable so async chunks have consistent hash (#1916)
webpackConfig
.plugin('named-chunks')
.use(webpack.NamedChunksPlugin, [chunk => {
if (chunk.name) {
return chunk.name
}

const hash = require('hash-sum')
const joinedHash = hash(
Array.from(chunk.modulesIterable, m => m.id).join('_')
)
return `chunk-` + joinedHash
}])
}

// resolve HTML file(s)
const HTMLPlugin = require('html-webpack-plugin')
// const PreloadPlugin = require('@vue/preload-webpack-plugin')
Expand Down
32 changes: 0 additions & 32 deletions packages/@vue/cli-service/lib/config/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ module.exports = (api, options) => {
.set('@', api.resolve('src'))

webpackConfig.resolveLoader
.plugin('pnp-loaders')
.use({ ...require('pnp-webpack-plugin').topLevelLoader })
.end()
.modules
.add('node_modules')
.add(api.resolve('node_modules'))
Expand Down Expand Up @@ -174,35 +171,6 @@ module.exports = (api, options) => {
.end()
.end()

if (webpackMajor === 4) {
// Node.js polyfills
// They are not polyfilled by default in webpack 5
// <https://github.com/webpack/webpack/pull/8460>
// In webpack 4, we used to disabled many of the core module polyfills too
webpackConfig.node
.merge({
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// process is injected via DefinePlugin, although some 3rd party
// libraries may require a mock to work properly (#934)
process: 'mock',
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
})

// Yarn PnP / Yarn 2 support
webpackConfig.resolve
.plugin('pnp')
.use({ ...require('pnp-webpack-plugin') })
.end()
}

const resolveClientEnv = require('../util/resolveClientEnv')
webpackConfig
.plugin('define')
Expand Down
15 changes: 0 additions & 15 deletions packages/@vue/cli-service/lib/config/prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,6 @@ module.exports = (api, options) => {
.mode('production')
.devtool(options.productionSourceMap ? 'source-map' : false)

const { semver } = require('@vue/cli-shared-utils')
const webpack = require('webpack')
const webpackMajor = semver.major(webpack.version)

// DeterministicModuleIdsPlugin is only available in webpack 5
// (and enabled by default in production mode).

// In webpack 4, we need HashedModuleIdsPlugin
// to keep module.id stable when vendor modules does not change.
// It is "the second best solution for long term caching".
// <https://github.com/webpack/webpack/pull/7399#discussion_r193970769>
if (webpackMajor === 4) {
webpackConfig.optimization.set('hashedModuleIds', true)
}

// disable optimization during tests to speed things up
if (process.env.VUE_CLI_TEST && !process.env.VUE_CLI_TEST_MINIMIZE) {
webpackConfig.optimization.minimize(false)
Expand Down
2 changes: 0 additions & 2 deletions packages/@vue/cli-service/lib/config/terserOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ module.exports = options => ({
safari10: true
}
},
sourceMap: options.productionSourceMap,
cache: true,
parallel: options.parallel,
extractComments: false
})
5 changes: 2 additions & 3 deletions packages/@vue/cli-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"cli-highlight": "^2.1.9",
"clipboardy": "^2.3.0",
"cliui": "^7.0.4",
"copy-webpack-plugin": "^6.4.0",
"copy-webpack-plugin": "^7.0.0",
"css-loader": "^3.5.3",
"css-minimizer-webpack-plugin": "^1.1.5",
"cssnano": "^4.1.10",
Expand All @@ -63,12 +63,11 @@
"mini-css-extract-plugin": "^1.3.3",
"minimist": "^1.2.5",
"module-alias": "^2.2.2",
"pnp-webpack-plugin": "^1.6.4",
"portfinder": "^1.0.26",
"postcss": "^8.2.1",
"postcss-loader": "^4.1.0",
"ssri": "^8.0.0",
"terser-webpack-plugin": "^4.2.3",
"terser-webpack-plugin": "^5.1.1",
"thread-loader": "^3.0.0",
"url-loader": "^4.1.1",
"vue-loader": "^16.1.2",
Expand Down
30 changes: 28 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7931,6 +7931,20 @@ copy-webpack-plugin@^6.4.0:
serialize-javascript "^5.0.1"
webpack-sources "^1.4.3"

copy-webpack-plugin@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-7.0.0.tgz#3506f867ca6e861ee2769d4deaf8fa0d2563ada9"
integrity sha512-SLjQNa5iE3BoCP76ESU9qYo9ZkEWtXoZxDurHoqPchAFRblJ9g96xTeC560UXBMre1Nx6ixIIUfiY3VcjpJw3g==
dependencies:
fast-glob "^3.2.4"
glob-parent "^5.1.1"
globby "^11.0.1"
loader-utils "^2.0.0"
normalize-path "^3.0.0"
p-limit "^3.0.2"
schema-utils "^3.0.0"
serialize-javascript "^5.0.1"

core-js-compat@^3.6.5, core-js-compat@^3.8.0, core-js-compat@^3.8.1:
version "3.8.1"
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.8.1.tgz#8d1ddd341d660ba6194cbe0ce60f4c794c87a36e"
Expand Down Expand Up @@ -16497,7 +16511,7 @@ p-limit@^2.0.0, p-limit@^2.2.0, p-limit@^2.2.1:
dependencies:
p-try "^2.0.0"

p-limit@^3.0.2:
p-limit@^3.0.2, p-limit@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
Expand Down Expand Up @@ -20163,6 +20177,18 @@ terser-webpack-plugin@^5.0.3:
source-map "^0.6.1"
terser "^5.3.8"

terser-webpack-plugin@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.1.1.tgz#7effadee06f7ecfa093dbbd3e9ab23f5f3ed8673"
integrity sha512-5XNNXZiR8YO6X6KhSGXfY0QrGrCRlSwAEjIIrlRQR4W8nP69TaJUlh3bkuac6zzgspiGPfKEHcY295MMVExl5Q==
dependencies:
jest-worker "^26.6.2"
p-limit "^3.1.0"
schema-utils "^3.0.0"
serialize-javascript "^5.0.1"
source-map "^0.6.1"
terser "^5.5.1"

terser@^4.1.2, terser@^4.6.3:
version "4.8.0"
resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17"
Expand All @@ -20172,7 +20198,7 @@ terser@^4.1.2, terser@^4.6.3:
source-map "~0.6.1"
source-map-support "~0.5.12"

terser@^5.0.0, terser@^5.3.4, terser@^5.3.8:
terser@^5.0.0, terser@^5.3.4, terser@^5.3.8, terser@^5.5.1:
version "5.5.1"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.5.1.tgz#540caa25139d6f496fdea056e414284886fb2289"
integrity sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==
Expand Down