This repository has been archived by the owner on Apr 6, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 1k
/
Copy pathwebpack.ts
166 lines (135 loc) · 5.33 KB
/
webpack.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import pify from 'pify'
import webpack from 'webpack'
import type { NodeMiddleware } from 'h3'
import { fromNodeMiddleware, defineEventHandler } from 'h3'
import type { OutputFileSystem } from 'webpack-dev-middleware'
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'
import type { Compiler, Watching } from 'webpack'
import type { Nuxt } from '@nuxt/schema'
import { joinURL } from 'ufo'
import { logger, useNuxt } from '@nuxt/kit'
import { composableKeysPlugin } from '../../vite/src/plugins/composable-keys'
import { DynamicBasePlugin } from './plugins/dynamic-base'
import { ChunkErrorPlugin } from './plugins/chunk'
import { createMFS } from './utils/mfs'
import { registerVirtualModules } from './virtual-modules'
import { client, server } from './configs'
import { createWebpackConfigContext, applyPresets, getWebpackConfig } from './utils/config'
// TODO: Support plugins
// const plugins: string[] = []
export async function bundle (nuxt: Nuxt) {
registerVirtualModules()
const webpackConfigs = [client, ...nuxt.options.ssr ? [server] : []].map((preset) => {
const ctx = createWebpackConfigContext(nuxt)
applyPresets(ctx, preset)
return getWebpackConfig(ctx)
})
await nuxt.callHook('webpack:config', webpackConfigs)
// Initialize shared MFS for dev
const mfs = nuxt.options.dev ? createMFS() : null
// Configure compilers
const compilers = webpackConfigs.map((config) => {
config.plugins!.push(DynamicBasePlugin.webpack({
sourcemap: nuxt.options.sourcemap[config.name as 'client' | 'server']
}))
// Emit chunk errors if the user has opted in to `experimental.emitRouteChunkError`
if (config.name === 'client' && nuxt.options.experimental.emitRouteChunkError) {
config.plugins!.push(new ChunkErrorPlugin())
}
config.plugins!.push(composableKeysPlugin.webpack({
sourcemap: nuxt.options.sourcemap[config.name as 'client' | 'server'],
rootDir: nuxt.options.rootDir,
composables: nuxt.options.optimization.keyedComposables
}))
// Create compiler
const compiler = webpack(config)
// In dev, write files in memory FS
if (nuxt.options.dev) {
compiler.outputFileSystem = mfs as unknown as OutputFileSystem
}
return compiler
})
nuxt.hook('close', async () => {
for (const compiler of compilers) {
await new Promise(resolve => compiler.close(resolve))
}
})
// Start Builds
if (nuxt.options.dev) {
return Promise.all(compilers.map(c => compile(c)))
}
for (const c of compilers) {
await compile(c)
}
}
async function createDevMiddleware (compiler: Compiler) {
const nuxt = useNuxt()
logger.debug('Creating webpack middleware...')
// Create webpack dev middleware
const devMiddleware = webpackDevMiddleware(compiler, {
publicPath: joinURL(nuxt.options.app.baseURL, nuxt.options.app.buildAssetsDir),
outputFileSystem: compiler.outputFileSystem as any,
stats: 'none',
...nuxt.options.webpack.devMiddleware
})
// @ts-ignore
nuxt.hook('close', () => pify(devMiddleware.close.bind(devMiddleware))())
const { client: _client, ...hotMiddlewareOptions } = nuxt.options.webpack.hotMiddleware || {}
const hotMiddleware = webpackHotMiddleware(compiler, {
log: false,
heartbeat: 10000,
path: joinURL(nuxt.options.app.baseURL, '__webpack_hmr', compiler.options.name!),
...hotMiddlewareOptions
})
// Register devMiddleware on server
const devHandler = fromNodeMiddleware(devMiddleware as NodeMiddleware)
const hotHandler = fromNodeMiddleware(hotMiddleware as NodeMiddleware)
await nuxt.callHook('server:devHandler', defineEventHandler(async (event) => {
await devHandler(event)
await hotHandler(event)
}))
return devMiddleware
}
async function compile (compiler: Compiler) {
const nuxt = useNuxt()
const { name } = compiler.options
await nuxt.callHook('webpack:compile', { name: name!, compiler })
// Load renderer resources after build
compiler.hooks.done.tap('load-resources', async (stats) => {
await nuxt.callHook('webpack:compiled', { name: name!, compiler, stats })
})
// --- Dev Build ---
if (nuxt.options.dev) {
const compilersWatching: Watching[] = []
nuxt.hook('close', async () => {
await Promise.all(compilersWatching.map(watching => pify(watching.close.bind(watching))()))
})
// Client build
if (name === 'client') {
return new Promise((resolve, reject) => {
compiler.hooks.done.tap('nuxt-dev', () => { resolve(null) })
compiler.hooks.failed.tap('nuxt-errorlog', (err) => { reject(err) })
// Start watch
createDevMiddleware(compiler).then((devMiddleware) => {
compilersWatching.push(devMiddleware.context.watching)
})
})
}
// Server, build and watch for changes
return new Promise((resolve, reject) => {
const watching = compiler.watch(nuxt.options.watchers.webpack, (err) => {
if (err) { return reject(err) }
resolve(null)
})
compilersWatching.push(watching)
})
}
// --- Production Build ---
const stats = await new Promise<webpack.Stats>((resolve, reject) => compiler.run((err, stats) => err ? reject(err) : resolve(stats!)))
if (stats.hasErrors()) {
const error = new Error('Nuxt build error')
error.stack = stats.toString('errors-only')
throw error
}
}