From 37783473e416798c8896904d0206ce1cac0b8a99 Mon Sep 17 00:00:00 2001 From: Linzp Date: Mon, 17 Aug 2026 18:15:32 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=B0=86=20webpack/babel=20cache=20?= =?UTF-8?q?=E9=9A=94=E7=A6=BB=E5=88=B0=E9=A1=B9=E7=9B=AE=20.cache?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit workplace 软链 node_modules 时不能共用原仓 node_modules/.cache,webpack pack 记的是绝对路径。 Co-authored-by: Cursor --- lib/craco-fix-plugin.js | 46 +++++++++++++++++++++++++++++++++++ package.json | 2 +- test/craco-fix-plugin.test.js | 30 +++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/lib/craco-fix-plugin.js b/lib/craco-fix-plugin.js index aff8306..9bbe7c6 100644 --- a/lib/craco-fix-plugin.js +++ b/lib/craco-fix-plugin.js @@ -1,6 +1,51 @@ +const path = require('path'); const {when} = require("@kne/craco"); const env = require("./env"); +const appCacheDir = path.resolve(env.appDir, '.cache'); + +const collectLoaderUses = (rule) => { + const uses = []; + if (rule.loader || (rule.options && !rule.use)) { + uses.push(rule); + } + if (Array.isArray(rule.use)) { + uses.push(...rule.use); + } else if (rule.use && typeof rule.use === 'object') { + uses.push(rule.use); + } + return uses; +}; + +const visitRules = (rules, visit) => { + (rules || []).forEach((rule) => { + if (!rule) { + return; + } + if (rule.oneOf) { + visitRules(rule.oneOf, visit); + } + visit(rule); + }); +}; + +// node_modules 被软链到其它 checkout 时,不能共用 node_modules/.cache(webpack pack 记绝对路径) +const isolateAppCache = (webpackConfig) => { + if (webpackConfig.cache && typeof webpackConfig.cache === 'object') { + webpackConfig.cache.cacheDirectory = path.join(appCacheDir, 'webpack'); + } + visitRules(webpackConfig.module && webpackConfig.module.rules, (rule) => { + collectLoaderUses(rule).forEach((use) => { + if (!use || typeof use !== 'object' || !use.options) { + return; + } + if (String(use.loader || '').includes('babel-loader')) { + use.options.cacheDirectory = path.join(appCacheDir, 'babel-loader'); + } + }); + }); +}; + // alias 到绝对路径时,即便落在 node_modules 下,ModuleScopePlugin 仍按 src 外拦截 const allowReadmeOutsideSrc = (webpackConfig) => { const plugins = webpackConfig.resolve && webpackConfig.resolve.plugins; @@ -53,6 +98,7 @@ module.exports = { "fs": false }; allowReadmeOutsideSrc(webpackConfig); + isolateAppCache(webpackConfig); return webpackConfig; } }; diff --git a/package.json b/package.json index a0294ab..5d9896d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kne/modules-dev", - "version": "2.4.12", + "version": "2.4.13", "description": "用于辅助在项目内启动一个规范化组件开发的环境", "publishConfig": { "access": "public", diff --git a/test/craco-fix-plugin.test.js b/test/craco-fix-plugin.test.js index d79f63f..967dbbf 100644 --- a/test/craco-fix-plugin.test.js +++ b/test/craco-fix-plugin.test.js @@ -1,3 +1,4 @@ +const path = require('path'); const { expect } = require('chai'); const plugin = require('../lib/craco-fix-plugin'); const env = require('../lib/env'); @@ -41,3 +42,32 @@ describe('craco-fix-plugin readme alias', () => { }); }); +describe('craco-fix-plugin app cache isolation', () => { + it('应将 webpack filesystem cache 指到项目 .cache/webpack', () => { + const webpackConfig = createConfig(true); + webpackConfig.cache = { type: 'filesystem', cacheDirectory: '/tmp/shared-cache' }; + plugin.overrideWebpackConfig({ webpackConfig, context: { env: 'development' } }); + expect(webpackConfig.cache.cacheDirectory).to.equal(path.resolve(env.appDir, '.cache/webpack')); + }); + + it('应将 babel-loader cacheDirectory 指到项目 .cache/babel-loader', () => { + const webpackConfig = createConfig(true); + webpackConfig.module = { + rules: [ + { + oneOf: [ + { + loader: '/fake/babel-loader/lib/index.js', + options: { cacheDirectory: true } + } + ] + } + ] + }; + plugin.overrideWebpackConfig({ webpackConfig, context: { env: 'development' } }); + expect(webpackConfig.module.rules[0].oneOf[0].options.cacheDirectory).to.equal( + path.resolve(env.appDir, '.cache/babel-loader') + ); + }); +}); +