Nuxt/packages/webpack/src/plugins/vue/server.ts
Daniel Roe 01bee2f0ea
feat(rspack,webpack): add rspack builder (#29142)
Co-authored-by: "yangjian.fe" <yangjian.fe@bytedance.com>
Co-authored-by: underfin <likui6666666@gmail.com>
2024-10-09 14:57:54 +01:00

93 lines
2.8 KiB
TypeScript

import type { Compilation, Compiler } from 'webpack'
import { extractQueryPartJS, isJS, validate } from './util'
import { webpack } from '#builder'
interface VueSSRServerPluginOptions {
filename: string
}
const JS_MAP_RE = /\.js\.map$/
export default class VueSSRServerPlugin {
options: VueSSRServerPluginOptions
constructor (options: Partial<VueSSRServerPluginOptions> = {}) {
this.options = Object.assign({
filename: null,
}, options) as VueSSRServerPluginOptions
}
apply (compiler: Compiler) {
validate(compiler)
compiler.hooks.make.tap('VueSSRServerPlugin', (compilation: Compilation) => {
compilation.hooks.processAssets.tapAsync({
name: 'VueSSRServerPlugin',
stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
}, (assets: any, cb: any) => {
const stats = compilation.getStats().toJson()
const [entryName] = Object.keys(stats.entrypoints!)
const entryInfo = stats.entrypoints![entryName!]
if (!entryInfo) {
// #5553
return cb()
}
const entryAssets = entryInfo.assets!.filter((asset: { name: string }) => isJS(asset.name))
if (entryAssets.length > 1) {
throw new Error(
'Server-side bundle should have one single entry file. ' +
'Avoid using CommonsChunkPlugin in the server config.',
)
}
const [entry] = entryAssets
if (!entry || typeof entry.name !== 'string') {
throw new Error(
`Entry "${entryName}" not found. Did you specify the correct entry option?`,
)
}
const bundle = {
entry: entry.name,
files: {} as Record<string, string>,
maps: {} as Record<string, string>,
}
stats.assets!.forEach((asset: any) => {
if (isJS(asset.name)) {
const queryPart = extractQueryPartJS(asset.name)
if (queryPart !== undefined) {
bundle.files[asset.name] = asset.name.replace(queryPart, '')
} else {
bundle.files[asset.name] = asset.name
}
} else if (JS_MAP_RE.test(asset.name)) {
bundle.maps[asset.name.replace(/\.map$/, '')] = asset.name
} else {
// Do not emit non-js assets for server
delete assets[asset.name]
}
})
const src = JSON.stringify(bundle, null, 2)
assets[this.options.filename] = {
source: () => src,
size: () => src.length,
}
const mjsSrc = 'export default ' + src
assets[this.options.filename.replace('.json', '.mjs')] = {
source: () => mjsSrc,
map: () => null,
size: () => mjsSrc.length,
}
cb()
})
})
}
}