diff --git a/e2e/cases/cache/index.test.ts b/e2e/cases/cache/index.test.ts index 7ef2e4ba25..82ee875d0f 100644 --- a/e2e/cases/cache/index.test.ts +++ b/e2e/cases/cache/index.test.ts @@ -1,108 +1,97 @@ import fs from 'node:fs'; import path from 'node:path'; -import { build, webpackOnlyTest } from '@e2e/helper'; -import { expect } from '@playwright/test'; +import { build } from '@e2e/helper'; +import { expect, test } from '@playwright/test'; +import type { RsbuildConfig } from '@rsbuild/core'; import fse from 'fs-extra'; -webpackOnlyTest( - 'should save the buildDependencies to cache directory and hit cache', - async () => { - const cacheDirectory = path.resolve( - __dirname, - './node_modules/.cache/webpack', - ); - - process.env.TEST_ENV = undefined; - - const buildConfig = { - cwd: __dirname, - rsbuildConfig: { - tools: { - bundlerChain: (chain: any) => { - if (process.env.TEST_ENV === 'a') { - chain.resolve.extensions.prepend('.a.js'); - } - }, +test('should save the buildDependencies to cache directory and hit cache', async () => { + const cacheDirectory = path.resolve( + __dirname, + './node_modules/.cache/test-build-dependencies', + ); + + process.env.TEST_ENV = undefined; + + const buildConfig = { + cwd: __dirname, + rsbuildConfig: { + tools: { + bundlerChain: (chain) => { + if (process.env.TEST_ENV === 'a') { + chain.resolve.extensions.prepend('.test.js'); + } }, - performance: { - buildCache: { - cacheDirectory, - }, + }, + performance: { + buildCache: { + cacheDirectory, }, }, - }; + } as RsbuildConfig, + }; - const configFile = path.resolve(cacheDirectory, 'buildDependencies.json'); + const configFile = path.resolve(cacheDirectory, 'buildDependencies.json'); - fs.rmSync(cacheDirectory, { recursive: true, force: true }); + fs.rmSync(cacheDirectory, { recursive: true, force: true }); - // first build no cache - let rsbuild = await build(buildConfig); + // first build without cache + let rsbuild = await build(buildConfig); - expect( - (await rsbuild.getIndexFile()).content.includes('222222'), - ).toBeTruthy(); + expect( + (await rsbuild.getIndexFile()).content.includes('222222'), + ).toBeTruthy(); - const buildDependencies = await fse.readJSON(configFile); - expect(Object.keys(buildDependencies)).toEqual(['tsconfig']); + const buildDependencies = await fse.readJSON(configFile); + expect(Object.keys(buildDependencies)).toEqual(['tsconfig']); - process.env.TEST_ENV = 'a'; + process.env.TEST_ENV = 'a'; - // hit cache => unfortunately, extension '.a.js' not work - rsbuild = await build(buildConfig); + // hit cache, so the extension '.test.js' will not work + rsbuild = await build(buildConfig); - expect( - (await rsbuild.getIndexFile()).content.includes('222222'), - ).toBeTruthy(); - }, -); + expect( + (await rsbuild.getIndexFile()).content.includes('222222'), + ).toBeTruthy(); +}); -webpackOnlyTest('cacheDigest should work', async () => { +test('cacheDigest should work', async () => { const cacheDirectory = path.resolve( __dirname, - './node_modules/.cache/webpack-1', + './node_modules/.cache/test-cache-digest', ); - process.env.TEST_ENV = undefined; + fs.rmSync(cacheDirectory, { recursive: true, force: true }); - const getBuildConfig = () => ({ + const getBuildConfig = (input: string) => ({ cwd: __dirname, rsbuildConfig: { tools: { - bundlerChain: (chain: any) => { - if (process.env.TEST_ENV === 'a') { - chain.resolve.extensions.prepend('.a.js'); + bundlerChain: (chain) => { + if (input === 'foo') { + chain.resolve.extensions.prepend('.test.js'); } }, }, performance: { buildCache: { cacheDirectory, - cacheDigest: [process.env.TEST_ENV], + cacheDigest: [input], }, }, - }, + } as RsbuildConfig, }); - const configFile = path.resolve(cacheDirectory, 'buildDependencies.json'); - - fs.rmSync(cacheDirectory, { recursive: true, force: true }); - - // first build no cache - let rsbuild = await build(getBuildConfig()); + // first build without cache + let rsbuild = await build(getBuildConfig('')); expect( (await rsbuild.getIndexFile()).content.includes('222222'), ).toBeTruthy(); - const buildDependencies = await fse.readJSON(configFile); - expect(Object.keys(buildDependencies)).toEqual(['tsconfig']); - - process.env.TEST_ENV = 'a'; - - rsbuild = await build(getBuildConfig()); + rsbuild = await build(getBuildConfig('foo')); - // extension '.a.js' should work + // extension '.test.js' should work expect( (await rsbuild.getIndexFile()).content.includes('111111'), ).toBeTruthy(); diff --git a/e2e/cases/cache/src/a.a.js b/e2e/cases/cache/src/a.test.js similarity index 100% rename from e2e/cases/cache/src/a.a.js rename to e2e/cases/cache/src/a.test.js diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index 0bfbb2cbb5..f7556cca45 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -132,7 +132,6 @@ const getDefaultToolsConfig = (): NormalizedToolsConfig => ({ const getDefaultPerformanceConfig = (): NormalizedPerformanceConfig => ({ profile: false, - buildCache: true, printFileSize: true, removeConsole: false, removeMomentLocale: false, diff --git a/packages/core/src/plugins/cache.ts b/packages/core/src/plugins/cache.ts index 3de293185e..d0c16bc226 100644 --- a/packages/core/src/plugins/cache.ts +++ b/packages/core/src/plugins/cache.ts @@ -57,7 +57,7 @@ function getCacheDirectory( } /** - * webpack can't detect the changes of framework config, tsconfig, tailwind config and browserslist config. + * Rspack can't detect the changes of framework config, tsconfig, tailwind config and browserslist config. * but they will affect the compilation result, so they need to be added to buildDependencies. */ async function getBuildDependencies( @@ -104,17 +104,16 @@ export const pluginCache = (): RsbuildPlugin => ({ name: 'rsbuild:cache', setup(api) { - // Rspack does not support persistent cache yet - if (api.context.bundlerType === 'rspack') { - return; - } - api.modifyBundlerChain(async (chain, { environment, env }) => { const { config } = environment; - const { buildCache } = config.performance; + const { bundlerType } = api.context; + + // Enable webpack persistent cache by default + // Rspack's persistent cache is still experimental and should be manually enabled + const buildCache = + config.performance.buildCache ?? bundlerType === 'webpack'; if (buildCache === false) { - chain.cache(false); return; } @@ -133,16 +132,30 @@ export const pluginCache = (): RsbuildPlugin => ({ Array.isArray(cacheConfig.cacheDigest) && cacheConfig.cacheDigest.length; - chain.cache({ - // The default cache name of webpack is '${name}-${env}', and the `name` is `default` by default. - // We set cache name to avoid cache conflicts of different targets. - name: useDigest - ? `${environment.name}-${env}-${getDigestHash(cacheConfig.cacheDigest!)}` - : `${environment.name}-${env}`, - type: 'filesystem', - cacheDirectory, - buildDependencies, - }); + // set cache name to avoid cache conflicts between different environments + const cacheVersion = useDigest + ? `${environment.name}-${env}-${getDigestHash(cacheConfig.cacheDigest!)}` + : `${environment.name}-${env}`; + + if (bundlerType === 'rspack') { + chain.cache(true); + chain.experiments({ + ...chain.get('experiments'), + cache: { + type: 'persistent', + version: cacheVersion, + directory: cacheDirectory, + buildDependencies: Object.values(buildDependencies).flat(), + }, + }); + } else { + chain.cache({ + name: cacheVersion, + type: 'filesystem', + cacheDirectory, + buildDependencies, + }); + } }); }, }); diff --git a/packages/core/src/types/config.ts b/packages/core/src/types/config.ts index 3bb8ee92c9..28e639d77d 100644 --- a/packages/core/src/types/config.ts +++ b/packages/core/src/types/config.ts @@ -605,7 +605,6 @@ export interface PerformanceConfig { export interface NormalizedPerformanceConfig extends PerformanceConfig { printFileSize: PrintFileSizeOptions | boolean; - buildCache: BuildCacheOptions | boolean; chunkSplit: RsbuildChunkSplit; } diff --git a/packages/core/tests/__snapshots__/cache.test.ts.snap b/packages/core/tests/__snapshots__/cache.test.ts.snap new file mode 100644 index 0000000000..aaca7d383a --- /dev/null +++ b/packages/core/tests/__snapshots__/cache.test.ts.snap @@ -0,0 +1,116 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`plugin-cache > 'should add cache config correctly' 1`] = ` +{ + "cache": true, + "experiments": { + "cache": { + "buildDependencies": [ + "/packages/core/tests/tsconfig.json", + ], + "directory": "/packages/core/tests/node_modules/.cache/rspack", + "type": "persistent", + "version": "web-test", + }, + }, + "plugins": [ + { + "name": "RsbuildCorePlugin", + }, + ], +} +`; + +exports[`plugin-cache > 'should apply cacheDigest' 1`] = ` +{ + "cache": true, + "experiments": { + "cache": { + "buildDependencies": [ + "/packages/core/tests/tsconfig.json", + ], + "directory": "/packages/core/tests/node_modules/.cache/rspack", + "type": "persistent", + "version": "web-test-c29a5747", + }, + }, + "plugins": [ + { + "name": "RsbuildCorePlugin", + }, + ], +} +`; + +exports[`plugin-cache > 'should custom cache directory by user' 1`] = ` +{ + "cache": true, + "experiments": { + "cache": { + "buildDependencies": [ + "/packages/core/tests/tsconfig.json", + ], + "directory": "/packages/core/tests/node_modules/.cache/tmp", + "type": "persistent", + "version": "web-test", + }, + }, + "plugins": [ + { + "name": "RsbuildCorePlugin", + }, + ], +} +`; + +exports[`plugin-cache > 'should disable cache' 1`] = ` +{ + "plugins": [ + { + "name": "RsbuildCorePlugin", + }, + ], +} +`; + +exports[`plugin-cache > 'should not apply cacheDigest' 1`] = ` +{ + "cache": true, + "experiments": { + "cache": { + "buildDependencies": [ + "/packages/core/tests/tsconfig.json", + ], + "directory": "/packages/core/tests/node_modules/.cache/rspack", + "type": "persistent", + "version": "web-test", + }, + }, + "plugins": [ + { + "name": "RsbuildCorePlugin", + }, + ], +} +`; + +exports[`plugin-cache > 'should watch tsconfig change' 1`] = ` +{ + "cache": true, + "experiments": { + "cache": { + "buildDependencies": [ + "/packages/core/tests/tsconfig.json", + ], + "directory": "/packages/core/tests/node_modules/.cache/rspack", + "type": "persistent", + "version": "web-test", + }, + }, + "plugins": [ + { + "name": "RsbuildCorePlugin", + }, + ], +} +`; diff --git a/packages/core/tests/__snapshots__/environments.test.ts.snap b/packages/core/tests/__snapshots__/environments.test.ts.snap index 7ffff718ad..a3640e296d 100644 --- a/packages/core/tests/__snapshots__/environments.test.ts.snap +++ b/packages/core/tests/__snapshots__/environments.test.ts.snap @@ -78,7 +78,6 @@ exports[`environment config > should normalize environment config correctly 1`] "target": "web", }, "performance": { - "buildCache": true, "chunkSplit": { "strategy": "split-by-experience", }, @@ -220,7 +219,6 @@ exports[`environment config > should normalize environment config correctly 2`] "target": "node", }, "performance": { - "buildCache": true, "chunkSplit": { "strategy": "split-by-experience", }, @@ -362,7 +360,6 @@ exports[`environment config > should print environment config when inspect confi "target": "web", }, "performance": { - "buildCache": true, "chunkSplit": { "strategy": "split-by-experience", }, @@ -500,7 +497,6 @@ exports[`environment config > should print environment config when inspect confi "target": "web", }, "performance": { - "buildCache": true, "chunkSplit": { "strategy": "split-by-experience", }, @@ -658,7 +654,6 @@ exports[`environment config > should support modify environment config by api.mo "target": "web", }, "performance": { - "buildCache": true, "chunkSplit": { "strategy": "split-by-experience", }, @@ -796,7 +791,6 @@ exports[`environment config > should support modify environment config by api.mo "target": "web", }, "performance": { - "buildCache": true, "chunkSplit": { "strategy": "split-by-experience", }, @@ -935,7 +929,6 @@ exports[`environment config > should support modify environment config by api.mo "target": "web", }, "performance": { - "buildCache": true, "chunkSplit": { "strategy": "split-by-experience", }, @@ -1077,7 +1070,6 @@ exports[`environment config > should support modify single environment config by "target": "web", }, "performance": { - "buildCache": true, "chunkSplit": { "strategy": "split-by-experience", }, @@ -1215,7 +1207,6 @@ exports[`environment config > should support modify single environment config by "target": "web", }, "performance": { - "buildCache": true, "chunkSplit": { "strategy": "split-by-experience", }, diff --git a/packages/core/tests/cache.test.ts b/packages/core/tests/cache.test.ts index a8ea39d734..684e32ba4d 100644 --- a/packages/core/tests/cache.test.ts +++ b/packages/core/tests/cache.test.ts @@ -14,8 +14,7 @@ vi.mock('../src/helpers.js', async (importOriginal) => { }; }); -// TODO: Rspack does not supports cache yet -describe.skip('plugin-cache', () => { +describe('plugin-cache', () => { const cases = [ { name: 'should add cache config correctly', diff --git a/packages/plugin-babel/src/plugin.ts b/packages/plugin-babel/src/plugin.ts index 5f6755a4e7..c43c8d3ef5 100644 --- a/packages/plugin-babel/src/plugin.ts +++ b/packages/plugin-babel/src/plugin.ts @@ -86,7 +86,7 @@ export const getDefaultBabelOptions = ( ], }; - const { buildCache } = config.performance; + const { buildCache = true } = config.performance; // Rspack does not yet support persistent cache // so we use babel-loader's cache to improve rebuild performance