2020-07-02 13:02:35 +00:00
|
|
|
import pify from 'pify'
|
|
|
|
import webpack from 'webpack'
|
2022-12-11 21:44:52 +00:00
|
|
|
import type { NodeMiddleware } from 'h3'
|
2023-04-07 16:02:47 +00:00
|
|
|
import { defineEventHandler, fromNodeMiddleware } from 'h3'
|
2022-12-11 21:44:52 +00:00
|
|
|
import type { OutputFileSystem } from 'webpack-dev-middleware'
|
|
|
|
import webpackDevMiddleware from 'webpack-dev-middleware'
|
2020-07-02 13:02:35 +00:00
|
|
|
import webpackHotMiddleware from 'webpack-hot-middleware'
|
2021-03-05 18:17:05 +00:00
|
|
|
import type { Compiler, Watching } from 'webpack'
|
|
|
|
|
2021-11-21 16:14:46 +00:00
|
|
|
import type { Nuxt } from '@nuxt/schema'
|
2022-01-18 16:59:14 +00:00
|
|
|
import { joinURL } from 'ufo'
|
2022-02-25 19:11:01 +00:00
|
|
|
import { logger, useNuxt } from '@nuxt/kit'
|
2022-07-07 16:26:04 +00:00
|
|
|
import { composableKeysPlugin } from '../../vite/src/plugins/composable-keys'
|
2022-07-21 10:44:33 +00:00
|
|
|
import { DynamicBasePlugin } from './plugins/dynamic-base'
|
2023-02-16 12:43:58 +00:00
|
|
|
import { ChunkErrorPlugin } from './plugins/chunk'
|
2021-05-24 11:14:10 +00:00
|
|
|
import { createMFS } from './utils/mfs'
|
2022-02-25 19:11:01 +00:00
|
|
|
import { registerVirtualModules } from './virtual-modules'
|
2021-05-24 11:14:10 +00:00
|
|
|
import { client, server } from './configs'
|
2023-04-07 16:02:47 +00:00
|
|
|
import { applyPresets, createWebpackConfigContext, getWebpackConfig } from './utils/config'
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
// TODO: Support plugins
|
|
|
|
// const plugins: string[] = []
|
2021-07-15 10:18:34 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
export async function bundle (nuxt: Nuxt) {
|
2022-06-08 19:49:11 +00:00
|
|
|
registerVirtualModules()
|
2020-09-02 12:27:27 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
const webpackConfigs = [client, ...nuxt.options.ssr ? [server] : []].map((preset) => {
|
|
|
|
const ctx = createWebpackConfigContext(nuxt)
|
|
|
|
applyPresets(ctx, preset)
|
2020-09-02 12:27:27 +00:00
|
|
|
return getWebpackConfig(ctx)
|
2022-02-25 19:11:01 +00:00
|
|
|
})
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
await nuxt.callHook('webpack:config', webpackConfigs)
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
// Initialize shared MFS for dev
|
|
|
|
const mfs = nuxt.options.dev ? createMFS() : null
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
// Configure compilers
|
|
|
|
const compilers = webpackConfigs.map((config) => {
|
2022-08-26 15:47:29 +00:00
|
|
|
config.plugins!.push(DynamicBasePlugin.webpack({
|
2022-09-07 11:32:10 +00:00
|
|
|
sourcemap: nuxt.options.sourcemap[config.name as 'client' | 'server']
|
2022-02-25 19:11:01 +00:00
|
|
|
}))
|
2023-02-16 12:43:58 +00:00
|
|
|
// 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())
|
|
|
|
}
|
2022-08-26 15:47:29 +00:00
|
|
|
config.plugins!.push(composableKeysPlugin.webpack({
|
2022-09-07 11:32:10 +00:00
|
|
|
sourcemap: nuxt.options.sourcemap[config.name as 'client' | 'server'],
|
2023-03-07 21:06:15 +00:00
|
|
|
rootDir: nuxt.options.rootDir,
|
|
|
|
composables: nuxt.options.optimization.keyedComposables
|
2022-07-07 16:26:04 +00:00
|
|
|
}))
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
// Create compiler
|
|
|
|
const compiler = webpack(config)
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
// In dev, write files in memory FS
|
|
|
|
if (nuxt.options.dev) {
|
2022-08-26 15:47:29 +00:00
|
|
|
compiler.outputFileSystem = mfs as unknown as OutputFileSystem
|
2021-04-02 19:38:11 +00:00
|
|
|
}
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
return compiler
|
|
|
|
})
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
nuxt.hook('close', async () => {
|
|
|
|
for (const compiler of compilers) {
|
|
|
|
await new Promise(resolve => compiler.close(resolve))
|
2020-07-02 13:02:35 +00:00
|
|
|
}
|
2022-02-25 19:11:01 +00:00
|
|
|
})
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
// Start Builds
|
|
|
|
if (nuxt.options.dev) {
|
|
|
|
return Promise.all(compilers.map(c => compile(c)))
|
2020-07-02 13:02:35 +00:00
|
|
|
}
|
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
for (const c of compilers) {
|
|
|
|
await compile(c)
|
2020-07-02 13:02:35 +00:00
|
|
|
}
|
2022-02-25 19:11:01 +00:00
|
|
|
}
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
async function createDevMiddleware (compiler: Compiler) {
|
|
|
|
const nuxt = useNuxt()
|
|
|
|
|
|
|
|
logger.debug('Creating webpack middleware...')
|
|
|
|
|
|
|
|
// Create webpack dev middleware
|
2022-10-15 18:42:57 +00:00
|
|
|
const devMiddleware = webpackDevMiddleware(compiler, {
|
2022-02-25 19:11:01 +00:00
|
|
|
publicPath: joinURL(nuxt.options.app.baseURL, nuxt.options.app.buildAssetsDir),
|
|
|
|
outputFileSystem: compiler.outputFileSystem as any,
|
|
|
|
stats: 'none',
|
|
|
|
...nuxt.options.webpack.devMiddleware
|
2022-10-15 18:42:57 +00:00
|
|
|
})
|
2022-02-25 19:11:01 +00:00
|
|
|
|
2023-04-14 12:53:21 +00:00
|
|
|
// @ts-expect-error need better types for `pify`
|
2022-02-25 19:11:01 +00:00
|
|
|
nuxt.hook('close', () => pify(devMiddleware.close.bind(devMiddleware))())
|
|
|
|
|
|
|
|
const { client: _client, ...hotMiddlewareOptions } = nuxt.options.webpack.hotMiddleware || {}
|
2022-10-15 18:42:57 +00:00
|
|
|
const hotMiddleware = webpackHotMiddleware(compiler, {
|
2022-02-25 19:11:01 +00:00
|
|
|
log: false,
|
|
|
|
heartbeat: 10000,
|
2022-08-26 15:47:29 +00:00
|
|
|
path: joinURL(nuxt.options.app.baseURL, '__webpack_hmr', compiler.options.name!),
|
2022-02-25 19:11:01 +00:00
|
|
|
...hotMiddlewareOptions
|
2022-10-15 18:42:57 +00:00
|
|
|
})
|
2022-02-25 19:11:01 +00:00
|
|
|
|
|
|
|
// Register devMiddleware on server
|
2022-10-15 18:42:57 +00:00
|
|
|
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)
|
|
|
|
}))
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
return devMiddleware
|
|
|
|
}
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
async function compile (compiler: Compiler) {
|
|
|
|
const nuxt = useNuxt()
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
const { name } = compiler.options
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-10-27 10:36:37 +00:00
|
|
|
await nuxt.callHook('webpack:compile', { name: name!, compiler })
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
// Load renderer resources after build
|
|
|
|
compiler.hooks.done.tap('load-resources', async (stats) => {
|
2022-10-27 10:36:37 +00:00
|
|
|
await nuxt.callHook('webpack:compiled', { name: name!, compiler, stats })
|
2022-02-25 19:11:01 +00:00
|
|
|
})
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
// --- Dev Build ---
|
|
|
|
if (nuxt.options.dev) {
|
|
|
|
const compilersWatching: Watching[] = []
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
nuxt.hook('close', async () => {
|
|
|
|
await Promise.all(compilersWatching.map(watching => pify(watching.close.bind(watching))()))
|
|
|
|
})
|
2020-07-02 13:02:35 +00:00
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
// 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)
|
|
|
|
})
|
|
|
|
})
|
2020-07-02 13:02:35 +00:00
|
|
|
}
|
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
// 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)
|
|
|
|
})
|
2020-07-02 13:02:35 +00:00
|
|
|
}
|
|
|
|
|
2022-02-25 19:11:01 +00:00
|
|
|
// --- Production Build ---
|
2022-08-26 15:47:29 +00:00
|
|
|
const stats = await new Promise<webpack.Stats>((resolve, reject) => compiler.run((err, stats) => err ? reject(err) : resolve(stats!)))
|
2022-02-25 19:11:01 +00:00
|
|
|
|
|
|
|
if (stats.hasErrors()) {
|
|
|
|
const error = new Error('Nuxt build error')
|
2022-10-24 08:44:19 +00:00
|
|
|
error.stack = stats.toString('errors-only')
|
2022-02-25 19:11:01 +00:00
|
|
|
throw error
|
2020-07-02 13:02:35 +00:00
|
|
|
}
|
2021-01-22 22:02:33 +00:00
|
|
|
}
|