Skip to content

feat: use html-webpack-plugin v5 by default #6269

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 10 commits into from
Feb 10, 2021
2 changes: 1 addition & 1 deletion docs/migrations/migrate-from-v4.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ No longer supports generating project with `node-sass`. It has been [deprecated]

#### Underlying Loaders and Plugins

* `html-webpack-plugin` is upgraded from v3 to v4, see more details in the [release announcement](https://dev.to/jantimon/html-webpack-plugin-4-has-been-released-125d).
* `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).
Expand Down
5 changes: 5 additions & 0 deletions packages/@vue/cli-plugin-babel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ module.exports = (api, options) => {
.test(/\.m?jsx?$/)
.exclude
.add(filepath => {
// With data URI support in webpack 5, filepath could be undefined
if (!filepath) {
return true
}

// always transpile js in vue files
if (/\.vue\.jsx?$/.test(filepath)) {
return false
Expand Down
2 changes: 1 addition & 1 deletion packages/@vue/cli-plugin-pwa/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
},
"dependencies": {
"@vue/cli-shared-utils": "^5.0.0-alpha.3",
"html-webpack-plugin": "^4.5.0",
"html-webpack-plugin": "^5.0.0",
"webpack": "^5.10.0",
"workbox-webpack-plugin": "^6.0.2"
},
Expand Down
5 changes: 4 additions & 1 deletion packages/@vue/cli-plugin-webpack-4/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ module.exports = (api) => {
// Yarn and PNPM 5.10+ support this feature
// So we'll try to use that whenever possible
resolutions: {
'@vue/cli-*/webpack': '^4.0.0'
'@vue/cli-*/webpack': '^4.0.0',
'html-webpack-plugin': '^4.5.1'
}
})

// TODO: if uses sass, replace sass-loader@11 with sass-loader@10
}
17 changes: 11 additions & 6 deletions packages/@vue/cli-plugin-webpack-4/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
const path = require('path')
const moduleAlias = require('module-alias')

const htmlWebpackPlugin4Path = path.dirname(require.resolve('html-webpack-plugin/package.json'))
// We have to use module-alias for html-webpack-plguin, as it is required by many other plugins
// as peer dependency for its `getHooks` API.
// Should add the alias as early as possible to avoid problems
// TODO: add debugging log here
moduleAlias.addAlias('html-webpack-plugin', htmlWebpackPlugin4Path)

/** @type {import('@vue/cli-service').ServicePlugin} */
module.exports = () => {
// TODO:
// terser-webpack-plugin v4
// copy-webpack-plugin v6
// html-webpack-plugin v4
// css-minimizer-webpack-plugin v1
module.exports = (api, options) => {
}
2 changes: 2 additions & 0 deletions packages/@vue/cli-plugin-webpack-4/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
"access": "public"
},
"dependencies": {
"html-webpack-plugin": "^4.5.1",
"module-alias": "^2.2.2",
"webpack": "^4.44.2"
},
"peerDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions packages/@vue/cli-service/__tests__/build.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ test('build', async () => {
// expect(index).toMatch(/<link [^>]+app[^>]+\.css" rel="preload" as="style">/)

// should inject scripts
expect(index).toMatch(/<script src="\/js\/chunk-vendors\.\w{8}\.js">/)
expect(index).toMatch(/<script src="\/js\/app\.\w{8}\.js">/)
expect(index).toMatch(/<script defer="defer" src="\/js\/chunk-vendors\.\w{8}\.js">/)
expect(index).toMatch(/<script defer="defer" src="\/js\/app\.\w{8}\.js">/)
// should inject css
expect(index).toMatch(/<link href="\/css\/app\.\w{8}\.css" rel="stylesheet">/)

Expand Down
4 changes: 2 additions & 2 deletions packages/@vue/cli-service/__tests__/cors.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ test('build', async () => {
// expect(index).toMatch(/<link [^>]+app[^>]+\.css rel=preload as=style crossorigin>/)

// should apply crossorigin and add integrity to scripts and css
expect(index).toMatch(/<script src="\/js\/chunk-vendors\.\w{8}\.js" crossorigin integrity="sha384-.{64}\s?">/)
expect(index).toMatch(/<script src="\/js\/app\.\w{8}\.js" crossorigin integrity="sha384-.{64}\s?">/)
expect(index).toMatch(/<script defer="defer" src="\/js\/chunk-vendors\.\w{8}\.js" crossorigin integrity="sha384-.{64}\s?">/)
expect(index).toMatch(/<script defer="defer" src="\/js\/app\.\w{8}\.js" crossorigin integrity="sha384-.{64}\s?">/)
expect(index).toMatch(/<link href="\/css\/app\.\w{8}\.css" rel="stylesheet" crossorigin integrity="sha384-.{64}\s?">/)

// verify integrity is correct by actually running it
Expand Down
12 changes: 6 additions & 6 deletions packages/@vue/cli-service/__tests__/modernMode.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ test('modern mode', async () => {
const index = await project.read('dist/index.html')

// should use <script type="module" crossorigin="use-credentials"> for modern bundle
expect(index).toMatch(/<script src="\/js\/chunk-vendors\.\w{8}\.js" type="module">/)
expect(index).toMatch(/<script src="\/js\/app\.\w{8}\.js" type="module">/)
expect(index).toMatch(/<script defer="defer" src="\/js\/chunk-vendors\.\w{8}\.js" type="module">/)
expect(index).toMatch(/<script defer="defer" src="\/js\/app\.\w{8}\.js" type="module">/)

// should use <link rel="modulepreload" crossorigin="use-credentials"> for modern bundle
// expect(index).toMatch(/<link [^>]*js\/chunk-vendors\.\w{8}\.js" rel="modulepreload" as="script">/)
// expect(index).toMatch(/<link [^>]*js\/app\.\w{8}\.js" rel="modulepreload" as="script">/)

// should use <script nomodule> for legacy bundle
expect(index).toMatch(/<script src="\/js\/chunk-vendors-legacy\.\w{8}\.js" nomodule>/)
expect(index).toMatch(/<script src="\/js\/app-legacy\.\w{8}\.js" nomodule>/)
expect(index).toMatch(/<script defer="defer" src="\/js\/chunk-vendors-legacy\.\w{8}\.js" nomodule>/)
expect(index).toMatch(/<script defer="defer" src="\/js\/app-legacy\.\w{8}\.js" nomodule>/)

// should inject Safari 10 nomodule fix
const { safariFix } = require('../lib/webpack/ModernModePlugin')
Expand All @@ -53,8 +53,8 @@ test('modern mode', async () => {
expect(stdout2).toMatch('Build complete.')
const index2 = await project.read('dist/index.html')
// should use <script type="module" crossorigin="use-credentials"> for modern bundle
expect(index2).toMatch(/<script src="\/js\/chunk-vendors\.\w{8}\.js" crossorigin="use-credentials" type="module">/)
expect(index2).toMatch(/<script src="\/js\/app\.\w{8}\.js" crossorigin="use-credentials" type="module">/)
expect(index2).toMatch(/<script defer="defer" src="\/js\/chunk-vendors\.\w{8}\.js" crossorigin="use-credentials" type="module">/)
expect(index2).toMatch(/<script defer="defer" src="\/js\/app\.\w{8}\.js" crossorigin="use-credentials" type="module">/)
// should use <link rel="modulepreload" crossorigin="use-credentials"> for modern bundle
// expect(index2).toMatch(/<link [^>]*js\/chunk-vendors\.\w{8}\.js" rel="modulepreload" as="script" crossorigin="use-credentials">/)
// expect(index2).toMatch(/<link [^>]*js\/app\.\w{8}\.js" rel="modulepreload" as="script" crossorigin="use-credentials">/)
Expand Down
12 changes: 12 additions & 0 deletions packages/@vue/cli-service/lib/Service.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,18 @@ module.exports = class Service {
return idToPlugin(id, resolveModule(id, this.pkgContext))
}
})

// Add the plugin automatically to simplify the webpack-4 tests
// so that a simple Jest alias would suffice, avoid changing every
// preset used in the tests
if (
process.env.VUE_CLI_TEST &&
process.env.VUE_CLI_USE_WEBPACK4 &&
!projectPlugins.some((p) => p.id === '@vue/cli-plugin-webpack-4')
) {
builtInPlugins.push(idToPlugin('@vue/cli-plugin-webpack-4'))
}

plugins = builtInPlugins.concat(projectPlugins)
}

Expand Down
1 change: 1 addition & 0 deletions packages/@vue/cli-service/lib/config/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ module.exports = (api, options) => {

const htmlOptions = {
title: api.service.pkg.name,
scriptLoading: 'defer',
templateParameters: (compilation, assets, assetTags, pluginOptions) => {
// enhance html-webpack-plugin's built in template params
let stats
Expand Down
19 changes: 14 additions & 5 deletions packages/@vue/cli-service/lib/webpack/ModernModePlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ class ModernModePlugin {
const htmlPath = path.dirname(data.plugin.options.filename)
const tempFilename = path.join(this.targetDir, htmlPath, `legacy-assets-${htmlName}.json`)
await fs.mkdirp(path.dirname(tempFilename))
await fs.writeFile(tempFilename, JSON.stringify(data.bodyTags))

let tags = data.bodyTags
if (data.plugin.options.scriptLoading === 'defer') {
tags = data.headTags
}
await fs.writeFile(tempFilename, JSON.stringify(tags))
cb()
})
})
Expand All @@ -42,8 +47,12 @@ class ModernModePlugin {
const ID = `vue-cli-modern-bundle`
compiler.hooks.compilation.tap(ID, compilation => {
HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync(ID, async (data, cb) => {
let tags = data.bodyTags
if (data.plugin.options.scriptLoading === 'defer') {
tags = data.headTags
}
// use <script type="module"> for modern assets
data.bodyTags.forEach(tag => {
tags.forEach(tag => {
if (tag.tagName === 'script' && tag.attributes) {
tag.attributes.type = 'module'
}
Expand All @@ -70,7 +79,7 @@ class ModernModePlugin {

if (this.unsafeInline) {
// inject inline Safari 10 nomodule fix
data.bodyTags.push({
tags.push({
tagName: 'script',
closeTag: true,
innerHTML: safariFix
Expand All @@ -87,7 +96,7 @@ class ModernModePlugin {
return Buffer.byteLength(safariFix)
}
}
data.bodyTags.push({
tags.push({
tagName: 'script',
closeTag: true,
attributes: {
Expand All @@ -96,7 +105,7 @@ class ModernModePlugin {
})
}

data.bodyTags.push(...legacyAssets)
tags.push(...legacyAssets)
await fs.remove(tempFilename)
cb()
})
Expand Down
6 changes: 3 additions & 3 deletions packages/@vue/cli-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
"fs-extra": "^9.0.1",
"globby": "^11.0.1",
"hash-sum": "^2.0.0",
"html-webpack-plugin": "^4.5.0",
"html-webpack-plugin": "^5.0.0",
"launch-editor-middleware": "^2.2.1",
"lodash.defaultsdeep": "^4.6.1",
"lodash.mapvalues": "^4.6.0",
Expand All @@ -71,8 +71,8 @@
"terser-webpack-plugin": "^4.2.3",
"thread-loader": "^3.0.0",
"url-loader": "^4.1.1",
"vue-loader": "^16.1.0",
"vue-loader-v15": "npm:vue-loader@^15.9.5",
"vue-loader": "^16.1.2",
"vue-loader-v15": "npm:vue-loader@^15.9.6",
"vue-style-loader": "^4.1.2",
"webpack": "^5.4.0",
"webpack-bundle-analyzer": "^4.1.0",
Expand Down
2 changes: 1 addition & 1 deletion scripts/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ if (args.p) {
rawArgs.splice(i, 2)
}

const e2ePathPattern = 'Migrator|Vue3|mochaPlugin|MochaPlugin'
const e2ePathPattern = 'Migrator|Vue3|mochaPlugin|MochaPlugin|cli-plugin-webpack-4'

if (args['e2e-only']) {
regex = e2ePathPattern
Expand Down
43 changes: 33 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11906,21 +11906,33 @@ html-tags@^3.1.0:
resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140"
integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==

html-webpack-plugin@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.5.0.tgz#625097650886b97ea5dae331c320e3238f6c121c"
integrity sha512-MouoXEYSjTzCrjIxWwg8gxL5fE2X2WZJLmBYXlaJhQUH5K/b5OrqmV7T4dB7iu0xkmJ6JlUuV6fFVtnqbPopZw==
html-webpack-plugin@^4.5.1:
version "4.5.1"
resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.5.1.tgz#40aaf1b5cb78f2f23a83333999625c20929cda65"
integrity sha512-yzK7RQZwv9xB+pcdHNTjcqbaaDZ+5L0zJHXfi89iWIZmb/FtzxhLk0635rmJihcQbs3ZUF27Xp4oWGx6EK56zg==
dependencies:
"@types/html-minifier-terser" "^5.0.0"
"@types/tapable" "^1.0.5"
"@types/webpack" "^4.41.8"
html-minifier-terser "^5.0.1"
loader-utils "^1.2.3"
lodash "^4.17.15"
lodash "^4.17.20"
pretty-error "^2.1.1"
tapable "^1.1.3"
util.promisify "1.0.0"

html-webpack-plugin@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.0.0.tgz#457a9defb33ce368135078b4e0387a27f3fe244d"
integrity sha512-kxTyb8cyZwEyUqXTgdHRUOF4C7uCrquzw2T+YTudehm/yspodgCkREjdmc4dXI8k2P4NEjqOVbnOOlPZg4TKJA==
dependencies:
"@types/html-minifier-terser" "^5.0.0"
html-minifier-terser "^5.0.1"
loader-utils "^2.0.0"
lodash "^4.17.20"
pretty-error "^2.1.1"
tapable "^2.0.0"

htmlparser2@^3.3.0:
version "3.10.1"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
Expand Down Expand Up @@ -21445,7 +21457,18 @@ vue-jest@^3.0.5:
tsconfig "^7.0.0"
vue-template-es2015-compiler "^1.6.0"

"vue-loader-v15@npm:vue-loader@^15.9.5", vue-loader@^15.7.1:
"vue-loader-v15@npm:vue-loader@^15.9.6":
version "15.9.6"
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.6.tgz#f4bb9ae20c3a8370af3ecf09b8126d38ffdb6b8b"
integrity sha512-j0cqiLzwbeImIC6nVIby2o/ABAWhlppyL/m5oJ67R5MloP0hj/DtFgb0Zmq3J9CG7AJ+AXIvHVnJAPBvrLyuDg==
dependencies:
"@vue/component-compiler-utils" "^3.1.0"
hash-sum "^1.0.2"
loader-utils "^1.1.0"
vue-hot-reload-api "^2.3.0"
vue-style-loader "^4.1.0"

vue-loader@^15.7.1:
version "15.9.5"
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.5.tgz#7a960dc420a3439deaacdda038fdcdbf7c432706"
integrity sha512-oeMOs2b5o5gRqkxfds10bCx6JeXYTwivRgbb8hzOrcThD2z1+GqEKE3EX9A2SGbsYDf4rXwRg6D5n1w0jO5SwA==
Expand All @@ -21456,10 +21479,10 @@ vue-jest@^3.0.5:
vue-hot-reload-api "^2.3.0"
vue-style-loader "^4.1.0"

vue-loader@^16.1.0:
version "16.1.1"
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-16.1.1.tgz#f5b286d60ac6886684c63a17a184391cc9e0199a"
integrity sha512-wz/+HFg/3SBayHWAlZXARcnDTl3VOChrfW9YnxvAweiuyKX/7IGx1ad/4yJHmwhgWlOVYMAbTiI7GV8G33PfGQ==
vue-loader@^16.1.2:
version "16.1.2"
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-16.1.2.tgz#5c03b6c50d2a5f983c7ceba15c50d78ca2b298f4"
integrity sha512-8QTxh+Fd+HB6fiL52iEVLKqE9N1JSlMXLR92Ijm6g8PZrwIxckgpqjPDWRP5TWxdiPaHR+alUWsnu1ShQOwt+Q==
dependencies:
chalk "^4.1.0"
hash-sum "^2.0.0"
Expand Down