Skip to content

Commit 80e7730

Browse files
authored
feat(ssr): vue-ssr-webpack-plugin compatible with webpack 5 (vuejs#12002)
* feat(ssr): vue-ssr-webpack-plugin compatible with webpack 5 * chore(ssr): remove webpack from peerDependencies
1 parent 38f71de commit 80e7730

File tree

3 files changed

+61
-17
lines changed

3 files changed

+61
-17
lines changed

src/server/webpack-plugin/client.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const hash = require('hash-sum')
22
const uniq = require('lodash.uniq')
3-
import { isJS, isCSS, onEmit } from './util'
3+
import { isJS, isCSS, getAssetName, onEmit, stripModuleIdHash } from './util'
44

55
export default class VueSSRClientPlugin {
66
constructor (options = {}) {
@@ -10,7 +10,8 @@ export default class VueSSRClientPlugin {
1010
}
1111

1212
apply (compiler) {
13-
onEmit(compiler, 'vue-client-plugin', (compilation, cb) => {
13+
const stage = 'PROCESS_ASSETS_STAGE_ADDITIONAL'
14+
onEmit(compiler, 'vue-client-plugin', stage, (compilation, cb) => {
1415
const stats = compilation.getStats().toJson()
1516

1617
const allFiles = uniq(stats.assets
@@ -19,6 +20,7 @@ export default class VueSSRClientPlugin {
1920
const initialFiles = uniq(Object.keys(stats.entrypoints)
2021
.map(name => stats.entrypoints[name].assets)
2122
.reduce((assets, all) => all.concat(assets), [])
23+
.map(getAssetName)
2224
.filter((file) => isJS(file) || isCSS(file)))
2325

2426
const asyncFiles = allFiles
@@ -34,7 +36,7 @@ export default class VueSSRClientPlugin {
3436
}
3537

3638
const assetModules = stats.modules.filter(m => m.assets.length)
37-
const fileToIndex = file => manifest.all.indexOf(file)
39+
const fileToIndex = asset => manifest.all.indexOf(getAssetName(asset))
3840
stats.modules.forEach(m => {
3941
// ignore modules duplicated in multiple chunks
4042
if (m.chunks.length === 1) {
@@ -43,7 +45,7 @@ export default class VueSSRClientPlugin {
4345
if (!chunk || !chunk.files) {
4446
return
4547
}
46-
const id = m.identifier.replace(/\s\w+$/, '') // remove appended hash
48+
const id = stripModuleIdHash(m.identifier)
4749
const files = manifest.modules[hash(id)] = chunk.files.map(fileToIndex)
4850
// find all asset modules associated with the same chunk
4951
assetModules.forEach(m => {

src/server/webpack-plugin/server.js

+12-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { validate, isJS, onEmit } from './util'
1+
import { validate, isJS, getAssetName, onEmit } from './util'
22

33
export default class VueSSRServerPlugin {
44
constructor (options = {}) {
@@ -10,7 +10,8 @@ export default class VueSSRServerPlugin {
1010
apply (compiler) {
1111
validate(compiler)
1212

13-
onEmit(compiler, 'vue-server-plugin', (compilation, cb) => {
13+
const stage = 'PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER'
14+
onEmit(compiler, 'vue-server-plugin', stage, (compilation, cb) => {
1415
const stats = compilation.getStats().toJson()
1516
const entryName = Object.keys(stats.entrypoints)[0]
1617
const entryInfo = stats.entrypoints[entryName]
@@ -20,7 +21,9 @@ export default class VueSSRServerPlugin {
2021
return cb()
2122
}
2223

23-
const entryAssets = entryInfo.assets.filter(isJS)
24+
const entryAssets = entryInfo.assets
25+
.map(getAssetName)
26+
.filter(isJS)
2427

2528
if (entryAssets.length > 1) {
2629
throw new Error(
@@ -42,14 +45,14 @@ export default class VueSSRServerPlugin {
4245
maps: {}
4346
}
4447

45-
stats.assets.forEach(asset => {
46-
if (isJS(asset.name)) {
47-
bundle.files[asset.name] = compilation.assets[asset.name].source()
48-
} else if (asset.name.match(/\.js\.map$/)) {
49-
bundle.maps[asset.name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[asset.name].source())
48+
Object.keys(compilation.assets).forEach(name => {
49+
if (isJS(name)) {
50+
bundle.files[name] = compilation.assets[name].source()
51+
} else if (name.match(/\.js\.map$/)) {
52+
bundle.maps[name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[name].source())
5053
}
5154
// do not emit anything else for server
52-
delete compilation.assets[asset.name]
55+
delete compilation.assets[name]
5356
})
5457

5558
const json = JSON.stringify(bundle, null, 2)

src/server/webpack-plugin/util.js

+43-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,27 @@
11
const { red, yellow } = require('chalk')
2+
const webpack = require('webpack')
23

34
const prefix = `[vue-server-renderer-webpack-plugin]`
45
const warn = exports.warn = msg => console.error(red(`${prefix} ${msg}\n`))
56
const tip = exports.tip = msg => console.log(yellow(`${prefix} ${msg}\n`))
67

8+
const isWebpack5 = !!(webpack.version && webpack.version[0] > 4)
9+
710
export const validate = compiler => {
811
if (compiler.options.target !== 'node') {
912
warn('webpack config `target` should be "node".')
1013
}
1114

12-
if (compiler.options.output && compiler.options.output.libraryTarget !== 'commonjs2') {
13-
warn('webpack config `output.libraryTarget` should be "commonjs2".')
15+
if (compiler.options.output) {
16+
if (compiler.options.output.library) {
17+
// Webpack >= 5.0.0
18+
if (compiler.options.output.library.type !== 'commonjs2') {
19+
warn('webpack config `output.library.type` should be "commonjs2".')
20+
}
21+
} else if (compiler.options.output.libraryTarget !== 'commonjs2') {
22+
// Webpack < 5.0.0
23+
warn('webpack config `output.libraryTarget` should be "commonjs2".')
24+
}
1425
}
1526

1627
if (!compiler.options.externals) {
@@ -21,8 +32,20 @@ export const validate = compiler => {
2132
}
2233
}
2334

24-
export const onEmit = (compiler, name, hook) => {
25-
if (compiler.hooks) {
35+
export const onEmit = (compiler, name, stageName, hook) => {
36+
if (isWebpack5) {
37+
// Webpack >= 5.0.0
38+
compiler.hooks.compilation.tap(name, compilation => {
39+
if (compilation.compiler !== compiler) {
40+
// Ignore child compilers
41+
return
42+
}
43+
const stage = webpack.Compilation[stageName]
44+
compilation.hooks.processAssets.tapAsync({ name, stage }, (assets, cb) => {
45+
hook(compilation, cb)
46+
})
47+
})
48+
} else if (compiler.hooks) {
2649
// Webpack >= 4.0.0
2750
compiler.hooks.emit.tapAsync(name, hook)
2851
} else {
@@ -31,4 +54,20 @@ export const onEmit = (compiler, name, hook) => {
3154
}
3255
}
3356

57+
export const stripModuleIdHash = id => {
58+
if (isWebpack5) {
59+
// Webpack >= 5.0.0
60+
return id.replace(/\|\w+$/, '')
61+
}
62+
// Webpack < 5.0.0
63+
return id.replace(/\s\w+$/, '')
64+
}
65+
66+
export const getAssetName = asset => {
67+
if (typeof asset === 'string') {
68+
return asset
69+
}
70+
return asset.name
71+
}
72+
3473
export { isJS, isCSS } from '../util'

0 commit comments

Comments
 (0)