diff --git a/packages/core/src/core/rsbuild.ts b/packages/core/src/core/rsbuild.ts index b69620c7f..97d15d16b 100644 --- a/packages/core/src/core/rsbuild.ts +++ b/packages/core/src/core/rsbuild.ts @@ -1,5 +1,6 @@ import fs from 'node:fs'; import { + type ManifestData, type RsbuildInstance, logger as RsbuildLogger, type RsbuildPlugin, @@ -108,6 +109,8 @@ export const prepareRsbuild = async ( }, }, output: { + // Pass resources to the worker on demand according to entry + manifest: true, sourceMap: { js: 'source-map', }, @@ -141,6 +144,11 @@ export const prepareRsbuild = async ( ...(config.optimization || {}), moduleIds: 'named', chunkIds: 'named', + splitChunks: { + chunks: 'all', + minSize: 0, + maxInitialRequests: Number.POSITIVE_INFINITY, + }, }; }, }, @@ -213,15 +221,21 @@ export const createRsbuildServer = async ({ const getRsbuildStats = async () => { const stats = await devServer.environments[name]!.getStats(); + const manifest = devServer.environments[name]!.context + .manifest as ManifestData; + const { entrypoints, outputPath, assets, time: buildTime, } = stats.toJson({ + all: false, entrypoints: true, outputPath: true, assets: true, + relatedAssets: true, + cachedAssets: true, // get the compilation time timings: true, }); @@ -237,6 +251,21 @@ export const createRsbuildServer = async ({ }); }; + const getEntryFiles = async () => { + const entryFiles: Record = {}; + + const entries = Object.keys(manifest!.entries!); + + for (const entry of entries) { + const data = manifest!.entries[entry]; + entryFiles[entry] = ( + (data?.initial?.js || []).concat(data?.async?.js || []) || [] + ).map((file: string) => path.join(outputPath!, file)); + } + return entryFiles; + }; + + const entryFiles = await getEntryFiles(); const entries: EntryInfo[] = []; const setupEntries: EntryInfo[] = []; const sourceEntries = await globTestSourceEntries(); @@ -253,11 +282,13 @@ export const createRsbuildServer = async ({ setupEntries.push({ distPath, testPath: setupFiles[entry], + files: entryFiles[entry], }); } else if (sourceEntries[entry]) { entries.push({ distPath, testPath: sourceEntries[entry], + files: entryFiles[entry], }); } } diff --git a/packages/core/src/pool/index.ts b/packages/core/src/pool/index.ts index a65d72cd7..c3d8bb5cc 100644 --- a/packages/core/src/pool/index.ts +++ b/packages/core/src/pool/index.ts @@ -164,11 +164,34 @@ export const createPool = async ({ }, }; + const setupAssets = setupEntries.flatMap((entry) => entry.files); + + const filterAssetsByEntry = (entryInfo: EntryInfo) => { + const neededFiles = entryInfo.files + ? Object.fromEntries( + Object.entries(assetFiles).filter( + ([key]) => + entryInfo.files!.includes(key) || setupAssets.includes(key), + ), + ) + : assetFiles; + + const neededSourceMaps = + Object.keys(entries).length > 1 + ? Object.fromEntries( + Object.entries(sourceMaps).filter(([key]) => neededFiles[key]), + ) + : sourceMaps; + + return { assetFiles: neededFiles, sourceMaps: neededSourceMaps }; + }; return { runTests: async () => { const results = await Promise.all( - entries.map((entryInfo) => - pool.runTest({ + entries.map((entryInfo) => { + const { assetFiles, sourceMaps } = filterAssetsByEntry(entryInfo); + + return pool.runTest({ options: { entryInfo, assetFiles, @@ -182,8 +205,8 @@ export const createPool = async ({ updateSnapshot, }, rpcMethods, - }), - ), + }); + }), ); for (const result of results) { @@ -198,8 +221,10 @@ export const createPool = async ({ }, collectTests: async () => { return Promise.all( - entries.map((entryInfo) => - pool.collectTests({ + entries.map((entryInfo) => { + const { assetFiles, sourceMaps } = filterAssetsByEntry(entryInfo); + + return pool.collectTests({ options: { entryInfo, assetFiles, @@ -213,8 +238,8 @@ export const createPool = async ({ updateSnapshot, }, rpcMethods, - }), - ), + }); + }), ); }, close: () => pool.close(), diff --git a/packages/core/src/types/worker.ts b/packages/core/src/types/worker.ts index fdd79023a..55b72a98f 100644 --- a/packages/core/src/types/worker.ts +++ b/packages/core/src/types/worker.ts @@ -13,6 +13,7 @@ import type { DistPath, TestPath } from './utils'; export type EntryInfo = { distPath: DistPath; testPath: TestPath; + files?: string[]; }; /** Server to Runtime */ diff --git a/packages/core/tests/core/__snapshots__/rsbuild.test.ts.snap b/packages/core/tests/core/__snapshots__/rsbuild.test.ts.snap index 868a3c99a..7368acc96 100644 --- a/packages/core/tests/core/__snapshots__/rsbuild.test.ts.snap +++ b/packages/core/tests/core/__snapshots__/rsbuild.test.ts.snap @@ -332,7 +332,11 @@ exports[`prepareRsbuild > should generate rspack config correctly 1`] = ` "emitOnErrors": true, "minimize": false, "moduleIds": "named", - "splitChunks": false, + "splitChunks": { + "chunks": "all", + "maxInitialRequests": Infinity, + "minSize": 0, + }, }, "output": { "assetModuleFilename": "static/assets/[name].[contenthash:8][ext]", @@ -374,6 +378,25 @@ exports[`prepareRsbuild > should generate rspack config correctly 1`] = ` "affectedHooks": "compilation", "name": "DefinePlugin", }, + WebpackManifestPlugin { + "options": { + "assetHookStage": Infinity, + "basePath": "", + "fileName": "manifest.json", + "filter": [Function], + "generate": [Function], + "map": null, + "publicPath": null, + "removeKeyHash": /\\(\\[a-f0-9\\]\\{16,32\\}\\\\\\.\\?\\)/gi, + "seed": undefined, + "serialize": [Function], + "sort": null, + "transformExtensions": /\\^\\(gz\\|map\\)\\$/i, + "useEntryKeys": false, + "useLegacyEmit": false, + "writeToFileEmit": false, + }, + }, IgnoreModuleNotFoundErrorPlugin {}, ], "resolve": {