preprocessor-loader icon indicating copy to clipboard operation
preprocessor-loader copied to clipboard

Doesn't work with cache in webpack 5

Open Tofandel opened this issue 3 years ago • 6 comments

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

Tofandel avatar Apr 27 '21 15:04 Tofandel

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.

afterwind-io avatar Apr 28 '21 01:04 afterwind-io

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

Tofandel avatar Apr 28 '21 07:04 Tofandel

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

Tofandel avatar Apr 28 '21 08:04 Tofandel

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

Tofandel avatar Apr 28 '21 09:04 Tofandel

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'],
    },
},

afterwind-io avatar Apr 28 '21 09:04 afterwind-io

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.

Tofandel avatar Apr 28 '21 09:04 Tofandel