Problem
👋 noticed an issue with @unocss/webpack and Webpack 5's new persistent caching feature. It looks like @unocss/webpack's approach of using loaders to extract code for class parsing can break with persistent caching - when a module is considered a cache hit, loaders are skipped entirely. This has the end result of subsequent builds having a potentially incomplete set of unocss classes included.
I've created a minimal reproduction repo to help isolate this issue - instructions are included in the README.
Potential solution
One approach could be to perform the code extraction (i.e. pushing to tasks) in the NormalModuleFactory stage as all modules (cached or otherwise) pass through this hook when being added to the dependency tree. Unfortunately, this requires manually reading the file contents rather than pulling what the loader has already read. Fortunately, compiler.inputFileSystem.readFile can be used which (from what I can tell) has internal caching to make the impact of repeated reads fairly negligable.
I've loosely tested this approach and it seems to solve the original issue - the second cached build succeeds and produces the same output. It's unfortunately a bit hacky and doesn't compose cleanly with unplugin but could at least be used as a starting point for a cache-friendly setup. Happy to post a snippet or open a rough PR.
However, for some reason the third (also cached) build seems to crash with or without the fix:
Build output
➜ unocss-bug-persistent-caching git:(main) ✗ yarn build
yarn run v1.22.11
warning package.json: No license field
$ webpack
assets by status 131 KiB [cached] 3 assets
Entrypoint main = main.css main.js
cached modules 134 KiB (javascript) 238 bytes (css/mini-extract) [cached] 13 modules
orphan modules 39 bytes [orphan] 1 module
./_virtual_uno.css 39 bytes [built] [1 error]
ERROR in ./_virtual_uno.css (./_virtual_uno.css.webpack[javascript/auto]!=!./node_modules/css-loader/dist/cjs.js!./_virtual_uno.css)
Module build failed (from ./node_modules/css-loader/dist/cjs.js):
Error: ENOENT: no such file or directory, open '/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/_virtual_uno.css'
@ ./_virtual_uno.css
@ ./src/index.js 3:0-17
ERROR in ./_virtual_uno.css
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
HookWebpackError: Module build failed (from ./node_modules/css-loader/dist/cjs.js):
Error: ENOENT: no such file or directory, open '/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/_virtual_uno.css'
at tryRunOrWebpackError (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/webpack/lib/HookWebpackError.js:88:9)
at __webpack_require_module__ (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/webpack/lib/Compilation.js:4979:12)
at __webpack_require__ (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/webpack/lib/Compilation.js:4936:18)
at /Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/webpack/lib/Compilation.js:5007:20
at symbolIterator (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/neo-async/async.js:3485:9)
at done (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/neo-async/async.js:3527:9)
at Hook.eval [as callAsync] (eval at create (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:15:1)
at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/tapable/lib/Hook.js:18:14)
at /Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/webpack/lib/Compilation.js:4914:43
at symbolIterator (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/neo-async/async.js:3482:9)
-- inner error --
Error: Module build failed (from ./node_modules/css-loader/dist/cjs.js):
Error: ENOENT: no such file or directory, open '/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/_virtual_uno.css'
at Object.<anonymous> (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/css-loader/dist/cjs.js!/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/_virtual_uno.css:1:7)
at /Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/webpack/lib/javascript/JavascriptModulesPlugin.js:432:11
at Hook.eval [as call] (eval at create (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/tapable/lib/HookCodeFactory.js:19:10), <anonymous>:7:1)
at Hook.CALL_DELEGATE [as _call] (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/tapable/lib/Hook.js:14:14)
at /Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/webpack/lib/Compilation.js:4981:39
at tryRunOrWebpackError (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/webpack/lib/HookWebpackError.js:83:7)
at __webpack_require_module__ (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/webpack/lib/Compilation.js:4979:12)
at __webpack_require__ (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/webpack/lib/Compilation.js:4936:18)
at /Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/webpack/lib/Compilation.js:5007:20
at symbolIterator (/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/neo-async/async.js:3485:9)
Generated code for /Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/node_modules/css-loader/dist/cjs.js!/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/_virtual_uno.css
1 | throw new Error("Module build failed (from ./node_modules/css-loader/dist/cjs.js):\nError: ENOENT: no such file or directory, open '/Users/chrissantamaria/Desktop/unocss-bug-persistent-caching/_virtual_uno.css'");
@ ./src/index.js 3:0-17
webpack 5.65.0 compiled with 2 errors in 522 ms
I haven't had much time to debug this, though it seems to be unrelated from the loader issue. Definitely still worth addressing, can open a second issue if you'd like.
Problem
👋 noticed an issue with
@unocss/webpackand Webpack 5's new persistent caching feature. It looks like@unocss/webpack's approach of using loaders to extract code for class parsing can break with persistent caching - when a module is considered a cache hit, loaders are skipped entirely. This has the end result of subsequent builds having a potentially incomplete set of unocss classes included.I've created a minimal reproduction repo to help isolate this issue - instructions are included in the README.
Potential solution
One approach could be to perform the code extraction (i.e. pushing to
tasks) in theNormalModuleFactorystage as all modules (cached or otherwise) pass through this hook when being added to the dependency tree. Unfortunately, this requires manually reading the file contents rather than pulling what the loader has already read. Fortunately,compiler.inputFileSystem.readFilecan be used which (from what I can tell) has internal caching to make the impact of repeated reads fairly negligable.I've loosely tested this approach and it seems to solve the original issue - the second cached build succeeds and produces the same output. It's unfortunately a bit hacky and doesn't compose cleanly with
unpluginbut could at least be used as a starting point for a cache-friendly setup. Happy to post a snippet or open a rough PR.However, for some reason the third (also cached) build seems to crash with or without the fix:
Build output
I haven't had much time to debug this, though it seems to be unrelated from the loader issue. Definitely still worth addressing, can open a second issue if you'd like.