UNPKG

@esmx/rspack

Version:

A high-performance Rspack integration for Esmx microfrontend framework, providing module federation and SSR capabilities.

194 lines (169 loc) 5.67 kB
import type { Esmx } from '@esmx/core'; import { moduleLinkPlugin } from '@esmx/rspack-module-link-plugin'; import { rspack } from '@rspack/core'; import type { RspackOptions } from '@rspack/core'; import RspackChain from 'rspack-chain'; import nodeExternals from 'webpack-node-externals'; import type { RspackAppOptions } from './app'; import type { BuildTarget } from './build-target'; import { HMR_DIR, HMR_JSONP } from './hmr-config'; export function createChainConfig( esmx: Esmx, buildTarget: BuildTarget, options: RspackAppOptions ): RspackChain { const isHot = buildTarget === 'client' && !esmx.isProd; const isClient = buildTarget === 'client'; const isServer = buildTarget === 'server'; const isNode = buildTarget === 'node'; const config = new RspackChain(); config.context(esmx.root); config.mode(esmx.isProd ? 'production' : 'development'); config.target(isClient ? 'web' : 'node24'); config.cache(!esmx.isProd); config.output .clean(esmx.isProd) .filename( !isNode && esmx.isProd ? 'exports/[name].[contenthash:8].final.mjs' : 'exports/[name].mjs' ) .chunkFilename( esmx.isProd ? 'chunks/[name].[contenthash:8].final.mjs' : 'chunks/[name].mjs' ) .publicPath( isClient ? 'auto' : `${esmx.basePathPlaceholder}${esmx.basePath}` ) .uniqueName(esmx.varName) .hotUpdateGlobal(HMR_JSONP) .chunkLoadingGlobal(`${HMR_JSONP}_chunk`) .hotUpdateChunkFilename(`${HMR_DIR}/[id].[fullhash].hot-update.mjs`) .hotUpdateMainFilename( `${HMR_DIR}/[runtime].[fullhash].hot-update.json` ); config.output.set( 'cssFilename', esmx.isProd ? 'exports/[name].[contenthash:8].final.css' : 'exports/[name].css' ); config.output.set( 'cssChunkFilename', esmx.isProd ? 'chunks/[name].[contenthash:8].final.css' : 'chunks/[name].css' ); const outputPath = (() => { switch (buildTarget) { case 'client': return esmx.resolvePath('dist/client'); case 'server': return esmx.resolvePath('dist/server'); case 'node': return esmx.resolvePath('dist/node'); } })(); config.output.path(outputPath); config.plugin('progress').use(rspack.ProgressPlugin, [ { prefix: buildTarget } ]); config .plugin('module-link') .use(moduleLinkPlugin, [createModuleLinkConfig(esmx, buildTarget)]); if (isHot) { config.plugin('hmr').use(rspack.HotModuleReplacementPlugin); } config.module.parser.set('javascript', { dynamicImportMode: 'lazy', url: isClient ? true : 'relative' }); config.module.generator.set('asset', { emit: isClient }); config.module.generator.set('asset/resource', { emit: isClient }); config.resolve.alias.set(esmx.name, esmx.root); config.optimization .minimize(options.minimize ?? esmx.isProd) .emitOnErrors(true); config.externalsPresets({ web: isClient, node: isServer || isNode }); config.externalsType('module-import'); if (isNode) { config.externals([ // @ts-ignore nodeExternals({ // @ts-ignore importType: 'module-import' }) ]); } // Temporary fix for development environment // Related issue: https://github.com/esmnext/esmx/issues/109 // TODO: Remove when Rspack officially supports these features if (!esmx.isProd) { config.optimization.splitChunks(false).runtimeChunk(false); config.module.parser.set('javascript', { ...config.module.parser.get('javascript'), dynamicImportMode: 'eager' }); } return config; } function createModuleLinkConfig(esmx: Esmx, buildTarget: BuildTarget) { const isClient = buildTarget === 'client'; const isServer = buildTarget === 'server'; const isNode = buildTarget === 'node'; if (isNode) { return { name: esmx.name, exports: { 'src/entry.node': { rewrite: false, file: './src/entry.node' } } }; } const exports: Record<string, { rewrite: boolean; file: string }> = {}; for (const [name, item] of Object.entries(esmx.moduleConfig.exports)) { if (item.inputTarget[buildTarget]) { exports[name] = { rewrite: item.rewrite, file: item.inputTarget[buildTarget] }; } } const preEntries: string[] = []; if (isClient && !esmx.isProd) { preEntries.push( `${import.meta.resolve('webpack-hot-middleware/client.js')}?path=/${esmx.name}/hot-middleware` ); } return { name: esmx.name, injectChunkName: isServer, imports: esmx.moduleConfig.imports, deps: Object.keys(esmx.moduleConfig.links), exports, preEntries }; } export function createRspackConfig( esmx: Esmx, buildTarget: BuildTarget, options: RspackAppOptions ): RspackOptions { const chain = createChainConfig(esmx, buildTarget, options); options.chain?.({ esmx, options, buildTarget, chain }); const config = chain.toConfig(); options.config?.({ esmx, options, buildTarget, config }); return config; }