Skip to content

Commit 0dccc4a

Browse files
authored
feat!: update copy & terser plugin, move more legacy code to webpack-4 plugin (#6279)
1 parent 4ce7edd commit 0dccc4a

File tree

9 files changed

+156
-114
lines changed

9 files changed

+156
-114
lines changed

docs/migrations/migrate-from-v4.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ No longer supports generating project with `node-sass`. It has been [deprecated]
8181
* `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).
8282
* `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).
8383
* `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).
84-
* `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).
84+
* `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).
8585
* `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)
86-
* `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).
86+
* `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).
8787

8888
### ESLint Plugin
8989

packages/@vue/cli-plugin-webpack-4/index.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
const fs = require('fs')
12
const path = require('path')
23
const moduleAlias = require('module-alias')
34

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

1112
/** @type {import('@vue/cli-service').ServicePlugin} */
1213
module.exports = (api, options) => {
14+
api.chainWebpack(config => {
15+
// Node.js polyfills
16+
// They are not polyfilled by default in webpack 5
17+
// <https://github.com/webpack/webpack/pull/8460>
18+
// In webpack 4, we used to disabled many of the core module polyfills too
19+
config.node
20+
.merge({
21+
// prevent webpack from injecting useless setImmediate polyfill because Vue
22+
// source contains it (although only uses it if it's native).
23+
setImmediate: false,
24+
// process is injected via DefinePlugin, although some 3rd party
25+
// libraries may require a mock to work properly (#934)
26+
process: 'mock',
27+
// prevent webpack from injecting mocks to Node native modules
28+
// that does not make sense for the client
29+
dgram: 'empty',
30+
fs: 'empty',
31+
net: 'empty',
32+
tls: 'empty',
33+
child_process: 'empty'
34+
})
35+
36+
// Yarn PnP / Yarn 2 support
37+
config.resolve
38+
.plugin('pnp')
39+
.use({ ...require('pnp-webpack-plugin') })
40+
.end()
41+
42+
config.resolveLoader
43+
.plugin('pnp-loaders')
44+
.use({ ...require('pnp-webpack-plugin').topLevelLoader })
45+
.end()
46+
47+
if (!process.env.VUE_CLI_BUILD_TARGET || process.env.VUE_CLI_BUILD_TARGET === 'app') {
48+
const isLegacyBundle = process.env.VUE_CLI_MODERN_MODE && !process.env.VUE_CLI_MODERN_BUILD
49+
const publicDir = api.resolve('public')
50+
if (!isLegacyBundle && fs.existsSync(publicDir)) {
51+
const CopyWebpackPluginV6 = require('copy-webpack-plugin')
52+
config
53+
.plugin('copy')
54+
.init((Plugin, args) => new CopyWebpackPluginV6(...args))
55+
}
56+
57+
if (process.env.NODE_ENV === 'production') {
58+
// In webpack 5, optimization.chunkIds is set to `deterministic` by default in production
59+
// In webpack 4, we use the following trick to keep chunk ids stable so async chunks have consistent hash (#1916)
60+
config
61+
.plugin('named-chunks')
62+
.use(require('webpack').NamedChunksPlugin, [chunk => {
63+
if (chunk.name) {
64+
return chunk.name
65+
}
66+
67+
const hash = require('hash-sum')
68+
const joinedHash = hash(
69+
Array.from(chunk.modulesIterable, m => m.id).join('_')
70+
)
71+
return `chunk-` + joinedHash
72+
}])
73+
}
74+
75+
if (process.env.NODE_ENV !== 'test') {
76+
config.optimization.splitChunks({
77+
cacheGroups: {
78+
vendors: {
79+
name: `chunk-vendors`,
80+
test: /[\\/]node_modules[\\/]/,
81+
priority: -10,
82+
chunks: 'initial'
83+
},
84+
common: {
85+
name: `chunk-common`,
86+
minChunks: 2,
87+
priority: -20,
88+
chunks: 'initial',
89+
reuseExistingChunk: true
90+
}
91+
}
92+
})
93+
}
94+
}
95+
96+
if (process.env.NODE_ENV === 'production') {
97+
const TerserPluginV4 = require('terser-webpack-plugin')
98+
config.optimization.minimizer('terser').init(
99+
(Plugin, [terserPluginOptions]) =>
100+
new TerserPluginV4({
101+
sourceMap: options.productionSourceMap,
102+
cache: true,
103+
...terserPluginOptions
104+
})
105+
)
106+
107+
// DeterministicModuleIdsPlugin is only available in webpack 5
108+
// (and enabled by default in production mode).
109+
110+
// In webpack 4, we need HashedModuleIdsPlugin
111+
// to keep module.id stable when vendor modules does not change.
112+
// It is "the second best solution for long term caching".
113+
// <https://github.com/webpack/webpack/pull/7399#discussion_r193970769>
114+
config.optimization.set('hashedModuleIds', true)
115+
}
116+
})
13117
}

packages/@vue/cli-plugin-webpack-4/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@
2323
"access": "public"
2424
},
2525
"dependencies": {
26+
"copy-webpack-plugin": "^6.4.0",
27+
"hash-sum": "^2.0.0",
2628
"html-webpack-plugin": "^4.5.1",
2729
"module-alias": "^2.2.2",
30+
"pnp-webpack-plugin": "^1.6.4",
31+
"terser-webpack-plugin": "^4.2.3",
2832
"webpack": "^4.44.2"
2933
},
3034
"peerDependencies": {

packages/@vue/cli-service/lib/config/app.js

Lines changed: 16 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// config that are specific to --target app
22
const fs = require('fs')
33
const path = require('path')
4-
const { semver } = require('@vue/cli-shared-utils')
54

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

1615
module.exports = (api, options) => {
17-
const webpack = require('webpack')
18-
const webpackMajor = semver.major(webpack.version)
19-
2016
api.chainWebpack(webpackConfig => {
2117
// only apply when there's no alternative target
2218
if (process.env.VUE_CLI_BUILD_TARGET && process.env.VUE_CLI_BUILD_TARGET !== 'app') {
@@ -39,43 +35,23 @@ module.exports = (api, options) => {
3935

4036
// code splitting
4137
if (process.env.NODE_ENV !== 'test') {
42-
if (webpackMajor === 4) {
43-
webpackConfig.optimization.splitChunks({
44-
cacheGroups: {
45-
vendors: {
46-
name: `chunk-vendors`,
47-
test: /[\\/]node_modules[\\/]/,
48-
priority: -10,
49-
chunks: 'initial'
50-
},
51-
common: {
52-
name: `chunk-common`,
53-
minChunks: 2,
54-
priority: -20,
55-
chunks: 'initial',
56-
reuseExistingChunk: true
57-
}
58-
}
59-
})
60-
} else {
61-
webpackConfig.optimization.splitChunks({
62-
cacheGroups: {
63-
defaultVendors: {
64-
name: `chunk-vendors`,
65-
test: /[\\/]node_modules[\\/]/,
66-
priority: -10,
67-
chunks: 'initial'
68-
},
69-
common: {
70-
name: `chunk-common`,
71-
minChunks: 2,
72-
priority: -20,
73-
chunks: 'initial',
74-
reuseExistingChunk: true
75-
}
38+
webpackConfig.optimization.splitChunks({
39+
cacheGroups: {
40+
defaultVendors: {
41+
name: `chunk-vendors`,
42+
test: /[\\/]node_modules[\\/]/,
43+
priority: -10,
44+
chunks: 'initial'
45+
},
46+
common: {
47+
name: `chunk-common`,
48+
minChunks: 2,
49+
priority: -20,
50+
chunks: 'initial',
51+
reuseExistingChunk: true
7652
}
77-
})
78-
}
53+
}
54+
})
7955
}
8056

8157
// HTML plugin
@@ -116,24 +92,6 @@ module.exports = (api, options) => {
11692
])
11793
}
11894

119-
if (webpackMajor === 4 && isProd) {
120-
// In webpack 5, optimization.chunkIds is set to `deterministic` by default in production
121-
// In webpack 4, we use the following trick to keep chunk ids stable so async chunks have consistent hash (#1916)
122-
webpackConfig
123-
.plugin('named-chunks')
124-
.use(webpack.NamedChunksPlugin, [chunk => {
125-
if (chunk.name) {
126-
return chunk.name
127-
}
128-
129-
const hash = require('hash-sum')
130-
const joinedHash = hash(
131-
Array.from(chunk.modulesIterable, m => m.id).join('_')
132-
)
133-
return `chunk-` + joinedHash
134-
}])
135-
}
136-
13795
// resolve HTML file(s)
13896
const HTMLPlugin = require('html-webpack-plugin')
13997
// const PreloadPlugin = require('@vue/preload-webpack-plugin')

packages/@vue/cli-service/lib/config/base.js

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,6 @@ module.exports = (api, options) => {
4444
.set('@', api.resolve('src'))
4545

4646
webpackConfig.resolveLoader
47-
.plugin('pnp-loaders')
48-
.use({ ...require('pnp-webpack-plugin').topLevelLoader })
49-
.end()
5047
.modules
5148
.add('node_modules')
5249
.add(api.resolve('node_modules'))
@@ -174,35 +171,6 @@ module.exports = (api, options) => {
174171
.end()
175172
.end()
176173

177-
if (webpackMajor === 4) {
178-
// Node.js polyfills
179-
// They are not polyfilled by default in webpack 5
180-
// <https://github.com/webpack/webpack/pull/8460>
181-
// In webpack 4, we used to disabled many of the core module polyfills too
182-
webpackConfig.node
183-
.merge({
184-
// prevent webpack from injecting useless setImmediate polyfill because Vue
185-
// source contains it (although only uses it if it's native).
186-
setImmediate: false,
187-
// process is injected via DefinePlugin, although some 3rd party
188-
// libraries may require a mock to work properly (#934)
189-
process: 'mock',
190-
// prevent webpack from injecting mocks to Node native modules
191-
// that does not make sense for the client
192-
dgram: 'empty',
193-
fs: 'empty',
194-
net: 'empty',
195-
tls: 'empty',
196-
child_process: 'empty'
197-
})
198-
199-
// Yarn PnP / Yarn 2 support
200-
webpackConfig.resolve
201-
.plugin('pnp')
202-
.use({ ...require('pnp-webpack-plugin') })
203-
.end()
204-
}
205-
206174
const resolveClientEnv = require('../util/resolveClientEnv')
207175
webpackConfig
208176
.plugin('define')

packages/@vue/cli-service/lib/config/prod.js

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,6 @@ module.exports = (api, options) => {
66
.mode('production')
77
.devtool(options.productionSourceMap ? 'source-map' : false)
88

9-
const { semver } = require('@vue/cli-shared-utils')
10-
const webpack = require('webpack')
11-
const webpackMajor = semver.major(webpack.version)
12-
13-
// DeterministicModuleIdsPlugin is only available in webpack 5
14-
// (and enabled by default in production mode).
15-
16-
// In webpack 4, we need HashedModuleIdsPlugin
17-
// to keep module.id stable when vendor modules does not change.
18-
// It is "the second best solution for long term caching".
19-
// <https://github.com/webpack/webpack/pull/7399#discussion_r193970769>
20-
if (webpackMajor === 4) {
21-
webpackConfig.optimization.set('hashedModuleIds', true)
22-
}
23-
249
// disable optimization during tests to speed things up
2510
if (process.env.VUE_CLI_TEST && !process.env.VUE_CLI_TEST_MINIMIZE) {
2611
webpackConfig.optimization.minimize(false)

packages/@vue/cli-service/lib/config/terserOptions.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ module.exports = options => ({
3535
safari10: true
3636
}
3737
},
38-
sourceMap: options.productionSourceMap,
39-
cache: true,
4038
parallel: options.parallel,
4139
extractComments: false
4240
})

packages/@vue/cli-service/package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"cli-highlight": "^2.1.9",
4545
"clipboardy": "^2.3.0",
4646
"cliui": "^7.0.4",
47-
"copy-webpack-plugin": "^6.4.0",
47+
"copy-webpack-plugin": "^7.0.0",
4848
"css-loader": "^3.5.3",
4949
"css-minimizer-webpack-plugin": "^1.1.5",
5050
"cssnano": "^4.1.10",
@@ -63,12 +63,11 @@
6363
"mini-css-extract-plugin": "^1.3.3",
6464
"minimist": "^1.2.5",
6565
"module-alias": "^2.2.2",
66-
"pnp-webpack-plugin": "^1.6.4",
6766
"portfinder": "^1.0.26",
6867
"postcss": "^8.2.1",
6968
"postcss-loader": "^4.1.0",
7069
"ssri": "^8.0.0",
71-
"terser-webpack-plugin": "^4.2.3",
70+
"terser-webpack-plugin": "^5.1.1",
7271
"thread-loader": "^3.0.0",
7372
"url-loader": "^4.1.1",
7473
"vue-loader": "^16.1.2",

yarn.lock

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7931,6 +7931,20 @@ copy-webpack-plugin@^6.4.0:
79317931
serialize-javascript "^5.0.1"
79327932
webpack-sources "^1.4.3"
79337933

7934+
copy-webpack-plugin@^7.0.0:
7935+
version "7.0.0"
7936+
resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-7.0.0.tgz#3506f867ca6e861ee2769d4deaf8fa0d2563ada9"
7937+
integrity sha512-SLjQNa5iE3BoCP76ESU9qYo9ZkEWtXoZxDurHoqPchAFRblJ9g96xTeC560UXBMre1Nx6ixIIUfiY3VcjpJw3g==
7938+
dependencies:
7939+
fast-glob "^3.2.4"
7940+
glob-parent "^5.1.1"
7941+
globby "^11.0.1"
7942+
loader-utils "^2.0.0"
7943+
normalize-path "^3.0.0"
7944+
p-limit "^3.0.2"
7945+
schema-utils "^3.0.0"
7946+
serialize-javascript "^5.0.1"
7947+
79347948
core-js-compat@^3.6.5, core-js-compat@^3.8.0, core-js-compat@^3.8.1:
79357949
version "3.8.1"
79367950
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.8.1.tgz#8d1ddd341d660ba6194cbe0ce60f4c794c87a36e"
@@ -16497,7 +16511,7 @@ p-limit@^2.0.0, p-limit@^2.2.0, p-limit@^2.2.1:
1649716511
dependencies:
1649816512
p-try "^2.0.0"
1649916513

16500-
p-limit@^3.0.2:
16514+
p-limit@^3.0.2, p-limit@^3.1.0:
1650116515
version "3.1.0"
1650216516
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
1650316517
integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
@@ -20163,6 +20177,18 @@ terser-webpack-plugin@^5.0.3:
2016320177
source-map "^0.6.1"
2016420178
terser "^5.3.8"
2016520179

20180+
terser-webpack-plugin@^5.1.1:
20181+
version "5.1.1"
20182+
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.1.1.tgz#7effadee06f7ecfa093dbbd3e9ab23f5f3ed8673"
20183+
integrity sha512-5XNNXZiR8YO6X6KhSGXfY0QrGrCRlSwAEjIIrlRQR4W8nP69TaJUlh3bkuac6zzgspiGPfKEHcY295MMVExl5Q==
20184+
dependencies:
20185+
jest-worker "^26.6.2"
20186+
p-limit "^3.1.0"
20187+
schema-utils "^3.0.0"
20188+
serialize-javascript "^5.0.1"
20189+
source-map "^0.6.1"
20190+
terser "^5.5.1"
20191+
2016620192
terser@^4.1.2, terser@^4.6.3:
2016720193
version "4.8.0"
2016820194
resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17"
@@ -20172,7 +20198,7 @@ terser@^4.1.2, terser@^4.6.3:
2017220198
source-map "~0.6.1"
2017320199
source-map-support "~0.5.12"
2017420200

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

0 commit comments

Comments
 (0)