preprocessor-loader
preprocessor-loader copied to clipboard
Doesn't work with cache in webpack 5
When cache
is enabled with webpack 5, modifying the preprocessor options will not trigger a cache bust and thus will use the cached version of the last compiled file as if the options were not changed
This might help maybe? https://webpack.js.org/configuration/other-options/#cachebuilddependencies
It's recommended to set cache.buildDependencies.config: [__filename] in your webpack configuration to get the latest configuration and all dependencies.
BTW, I built a minimal example and found it actually works. Did i miss something?
./src/index.js
window.a = 1;
// #!debug
export const a = 1;
// #!if a === 1
export const b = 2;
// #!endif
webpack.config.js
module.exports = {
mode: 'development',
entry: './src/index.js',
cache: true,
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'webpack-preprocessor-loader',
options: {
params: { a: 2 },
debug: false,
},
},
],
},
],
},
};
package.json
"dependencies": {
"webpack": "^5.36.0",
"webpack-cli": "^4.6.0",
"webpack-preprocessor-loader": "^1.1.4"
}
Change the config value params: { a: 2 }
to params: { a: 1 }
does update the packed result in ./dist/main.js
based upon the setup above.
Modifying webpack.config.js
invalidates the cache (as it is itself a build deps) try using an env variable and the filesystem
Try this
console.log(process.env.TEST);
module.exports = {
mode: 'development',
entry: './src/index.js',
cache: {
type: 'filesystem',
},
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'webpack-preprocessor-loader',
options: {
params: { a: parseInt(process.env.TEST) },
debug: false,
},
},
],
},
],
},
};
Then run
TEST=1 webpack
TEST=2 webpack
Output will still be the one of 1
It seems it's possible to use something of the like to get the correct behavior
cache: {
type: 'filesystem',
version: process.env.TEST // Should create a hash of the env variables that modify the build
},
const hash = require('object-hash');
const options = {
params: { a: parseInt(process.env.TEST) },
debug: false,
};
module.exports = {
mode: 'development',
entry: './src/index.js',
cache: {
type: 'filesystem',
version: hash(options),
},
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'webpack-preprocessor-loader',
options,
},
],
},
],
},
};
It doesn't seem to be possible to use variables directly into the loader cache deps to calculate the cache only files, this seems like a good feature request for webpack
https://webpack.js.org/api/loaders/#thisadddependency
https://github.com/webpack/webpack/issues/13249
It seems it possible to hack this somehow! https://github.com/webpack/webpack/blob/00f4a82903d99502ffa1eee5c0bfd2fa405d04b8/lib/NormalModule.js#L842
~~Just need to add the options to this buildMeta variable~~ :( This doesn't rerun on rebuild if the file is already cached, so dead end
I see the pain here...
JUST FOR FUN, try this perhaps?
package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
// Write your env param to a temp file
"build1": "echo 1>foo&& TEST=1 webpack",
"build2": "echo 2>foo&& TEST=2 webpack"
},
webpack.config.js
cache: {
type: 'filesystem',
buildDependencies: {
// Add the `foo` to the list. You get the dependency changes, and reuse the cache to its best.
// Modify the `version` may break the actual cache control strategy.
config: [__filename, 'foo'],
},
},
That works with config: [__filename, './foo'],
but it's so hackish :face_with_head_bandage: I'll keep the hash-object-version workaround in the meantime
It's technically possible to write a file inside the package and add this as dep of the loader until the feature comes along, except this would have the same problem, the loader function doesn't run again if it's cached... So a bit of a dead end (It's possible to hook into webpack when the loader is imported, but that always ends up in a lot of ugly hacks). This needs to be fixed upstream.