UNPKG

@esmx/rspack

Version:

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

142 lines (141 loc) 4.2 kB
import upath from "upath"; export const RSPACK_PLUGIN_NAME = "rspack-module-link-plugin"; export class ManifestPlugin { constructor(opts) { this.opts = opts; } apply(compiler) { const opts = this.opts; const { Compilation } = compiler.rspack; compiler.hooks.thisCompilation.tap( RSPACK_PLUGIN_NAME, (compilation) => { let manifestJson = { name: opts.name, exports: {}, scopes: opts.scopes, files: [], chunks: {} }; compilation.hooks.processAssets.tap( { name: RSPACK_PLUGIN_NAME, stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL }, (assets) => { const stats = compilation.getStats().toJson({ hash: true, entrypoints: true }); const exports = getExports(opts, stats); const resources = Object.keys(assets).map(transFileName).filter((file) => !file.includes("hot-update")); manifestJson = { name: opts.name, exports, scopes: opts.scopes, files: resources, chunks: getChunks(opts, compilation) }; const { RawSource } = compiler.rspack.sources; compilation.emitAsset( "manifest.json", new RawSource(JSON.stringify(manifestJson, null, 4)) ); } ); if (opts.injectChunkName) { compilation.hooks.processAssets.tap( { name: RSPACK_PLUGIN_NAME, stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS }, (assets) => { const { RawSource } = compiler.rspack.sources; for (const [key, value] of Object.entries( manifestJson.chunks )) { const asset = assets[value.js]; if (!asset) { return; } const source = new RawSource( `import.meta.chunkName = import.meta.chunkName ?? ${JSON.stringify(key)}; ${asset.source()}` ); compilation.updateAsset(value.js, source); } } ); } } ); } } function transFileName(fileName) { return fileName.replace(/^.\//, ""); } export function getExports(opts, stats) { const entrypoints = stats.entrypoints || {}; const exports = {}; for (const [key, value] of Object.entries(entrypoints)) { const asset = value.assets?.find((item) => { return item.name.endsWith(opts.ext) && item.name.startsWith(key) && !item.name.includes("hot-update"); }); if (!asset) continue; if (key in opts.exports) { exports[key] = { ...opts.exports[key], file: asset.name }; } } return exports; } function getChunks(opts, compilation) { const stats = compilation.getStats().toJson({ all: false, chunks: true, modules: true, chunkModules: true, ids: true }); const buildChunks = {}; if (!stats.chunks) return buildChunks; for (const chunk of stats.chunks) { const module = chunk.modules?.sort((a, b) => { return (a.index ?? -1) - (b?.index ?? -1); })?.find((module2) => { return module2.moduleType?.includes("javascript/"); }); if (!module?.nameForCondition) continue; const js = chunk.files?.find((file) => file.endsWith(opts.ext)); if (!js) continue; const root = compilation.options.context ?? process.cwd(); const name = generateIdentifier({ root, name: opts.name, filePath: module.nameForCondition }); const css = chunk.files?.filter((file) => file.endsWith(".css")) ?? []; const resources = chunk.auxiliaryFiles ?? []; buildChunks[name] = { name, js, css, resources }; } return buildChunks; } export function generateIdentifier({ root, name, filePath }) { const unixFilePath = upath.toUnix(filePath); if (!root) { return `${name}@${unixFilePath}`; } const file = upath.relative(upath.toUnix(root), unixFilePath); return `${name}@${file}`; }