Webpack processAssets hook and asset source
Asked Answered
O

1

6

I'm in the middle of upgrading my personal plugins to Webpack5, and while things are going smooth; I've been trying to wrap my head around how to properly change the source of a asset mid build.

I'm aware of Webpack5's changes to asset hooks, and needing to be in the processAssets hook / appropriate stage to do changes.

compilation.hooks.processAssets.tap(
  {
    name: 'BobRoss',
    stage: compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
    additionalAssets: true          
  },
  (assets) => {
    // ... logic here ...
  }
);

What I don't understand however is the actual asset's source prop, function or cached string?

For instance, to alter the source of a un-minified JS asset, I only find success with:

assets[i] = {
  source: () => 'the change';
};

However if that asset is minified, I only find success with:

assets[i]._chachedSource = 'the change';

which is kind of weird, but I guess we can work with that..

But then in walks HTML assets, which regardless of being minified or not, only works if I:

assets[i]._value = 'the change';

So, I'm increasingly feeling like I'm missing some obvious API method used to change an asset's source consistently and I'm adding points of failure not solutions. Can anyone point me in the right direction or give me an idea of better approach?

Thank you!

Olsewski answered 2/1, 2021 at 0:37 Comment(0)
O
9

As suspected, I was indeed missing compilation.getAsset(), compilation.updateAsset() methods and webpack's { sources } class API here to make my life easier.

First, you need to bring in the { sources } class from webpack, which will aid us in crafting raw source changes to an asset (regardless of its optimization or asset type):

const { sources } = require('webpack');

Then, when looping over assets (provided from processAsset's callback), we can use the compilation object's compilation.getAsset() and compilation.updateAsset() methods to use a standardized approach in getting, updating and saving asset source code:

compilation.hooks.processAssets.tap(
  {
    name: 'BobRoss',
    stage: compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
    additionalAssets: true          
  },
  (assets) => {
    for (let i in assets) {
      const asset = compilation.getAsset(i);  // <- standardized version of asset object
      const contents = asset.source.source(); // <- standardized way of getting asset source

      // standardized way of updating asset source
      compilation.updateAsset(                
        i,
        new sources.RawSource(contents + 'new stuff')
      );                                     
    }
  }
);

Hope this helps others!

Olsewski answered 2/1, 2021 at 1:38 Comment(2)
This is helpful, but for some reason my callback function, the second argument to processAssets.tap() never gets called. Not sure if I'm doing something fundamentally wrong. Any ideas?Boardman
try having (assets, callback) and then calling callback() after you do your thingsShabuoth

© 2022 - 2024 — McMap. All rights reserved.