Home > other >  How to change file reference strings to use generated hashes from copy file webpack plugin
How to change file reference strings to use generated hashes from copy file webpack plugin

Time:01-23

I'm copying all my assets to my build directory using copy webpack plugin. It generates all the files with the hashes properly but is there a simple way of changing any of these file references in code with the new hashed filename?

    new CopyWebpackPlugin({
      patterns: [
        { from: 'src/assets', to: '[path][name].[contenthash][ext]' },
      ],
    }),

Im currently using strings like below to load assets into phaser, using a query param to break the cache but i want the url to be updated with the new hash filename so I don't need to use the query param to bust the server cache and can take advantage of server caching.

{
   key: 'atlas',
   url: `assets/img/atlas.json?t=${new Date().getTime().toString()}`,
   path: './assets/img/'
},
{
   key: 'atlas',
   url: `assets/img/atlas.json`,
   path: './assets/img/'
},

so Im hoping the above will look like this in the output after webpack has run

{
   key: 'atlas',
   url: `assets/img/atlas.{generatedHash}.json`,
   path: './assets/img/'
},

Edit:

Okay so I accomplished the above by using webpack-asset-manifest

    new ManifestPlugin({
      // publicPath: 'assets/',
    }),

and then having a function for getting my urls from the generated json after it is loaded

 protected getAssetFromKey(key: string | Array<string>): string | Array<string> {
        if (Array.isArray(key)) {
            let urls = new Array<string>();
            key.forEach((urlKey: string) => {
                urls.push(this.assetKeys[urlKey]);
            });
            return urls;
        } else {
            return this.assetKeys[key];
        }
    }

But now I have hit an issue where the json atlas files are pointing to the old images and there seems to be no easy way to edit these. Im thinking of something like string replace loader but Im wondering if there is a better way and I am unsure of how to replace the string with a value from the manifest.json that is exported by webpack.

CodePudding user response:

Okay So I figured this out by adding the manifest plugin to my webpack config which generates a json file with all the original file names as keys and all the new hashed filenames as values.

    new ManifestPlugin({
    }),

and then I added in a compiler hook in the plugins area that does reads all the atlas files and replaces the strings in them, as well as any references to the assets in the compiled code.

https://webpack.js.org/api/compiler-hooks/

{
      apply: (compiler) => {
        compiler.hooks.done.tap("update links", (stats) => {
          Fs.readJson('dist/assets-manifest.json').then( (value) => {

            let keys = Object.keys(value)
            let files = Object.values(value);

            files.forEach( (file, index) => {
              if( file.includes('json')) {

                let splitString = keys[index].split('/');
                let findFile = splitString[splitString.length-1].replace('.json', '');
                console.log(`find file- ${findFile}`);

                let replaceWithString = '';
                let replaceString = ''

                for( let i =0 ; i < keys.length; i  ) {
                  if( keys[i].includes(`${findFile}`) && keys[i].includes('.webp') ) {
                    console.log(keys[i]);
                    let splitFiles = files[i].split('/');
                    let splitKeys = keys[i].split('/');
                    replaceWithString = splitFiles[splitFiles.length-1];
                    replaceString = splitKeys[splitKeys.length-1];

                    break;
                  }
                }
                console.log( `REPLACE WITH STRING = ${replaceWithString}`)
                console.log(`reading file-${file}`);

                Fs.readJson(`dist/${file}`).then( (val) => {                  
                  let stringJson = JSON.stringify(val);

                  console.log(`replacing ${replaceString} with ${replaceWithString}`);
                  let result = stringJson.replace(replaceString, replaceWithString);
                  let outputJson = JSON.parse(result);
                  Fs.writeJson(`dist/${file}`, outputJson, 'utf8').then( () => {
                    console.log( `!!!!! SUCCESS !!!!!`);
                  });
                });
              }
            });

            files.forEach( (file) => {
              if( file.includes('.js') && !file.includes('json') ) {
                console.log('FILE: '   file)
                Fs.content(`dist/${file}`).then( ( val) => {
                  keys.forEach( (key,index) => {
                    if( key.includes('assets/')) {
                      val = val.replaceAll(key, files[index]);
                      console.log(`REPLACING: ${key} with ${files[index]} in ${file}`)
                    }
                  });

                  Fs.writeFile(`dist/${file}`, val).then( () => {
                    console.log("--SUCCESS---")
                  });
                });
              }
            })
          }).catch( (err) => {
            console.log(`error ${err}`);
          })
        });
      }
    },
  • Related