# Bundled files and cache busting, lazy loading

**URL:** <https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114>\
**Category:** ionic-v3\
**Created:** [October 17, 2017, 4:39am UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114 "2017-10-17T04:39:10Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![gydev](https://avatars.discourse-cdn.com/v4/letter/g/ea5d25/32.png) [@gydev](https://forum.ionicframework.com/u/gydev)\
**Post date:** [October 17, 2017, 4:39am UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/1 "2017-10-17T04:39:10Z")

</div>

Hi all,  
looking for an elegant solution for forcing cache buster.  
Right now,I get troubles when bundled files (main.js, vendor.js & co) get an upates.  
One simple solution may be be to enable:

- on build, versioning of file, i.e. appending a unique string to filenames, e.g. main.9d20886f478d1f484d41ec3d3f7119d5.js
- changing reference in index.html file  
but seems however that there may be issues while lazy loading

I know that some other frameworks have plugins that enable this (.e.g [Laravel mix versioning](https://laracasts.com/series/whats-new-in-laravel-5-4/episodes/3) [3:14]

Anything existing, any thought ?

Cheers

---

<div class="post-metadata">

**Author:** ![yuricamara](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/yuricamara/32/94528_2.png) [@yuricamara](https://forum.ionicframework.com/u/yuricamara)\
**Post date:** [October 19, 2017, 12:28pm UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/2 "2017-10-19T12:28:27Z")

</div>

Hi gydev,

I used Gulp to cache busting the main.js and main.css on the way you said.

The problem is to do the same with the page files. That ones with numbers. 1.js, for example. Right now, I am looking for a solution for these ones.

All the best!

---

<div class="post-metadata">

**Author:** ![gydev](https://avatars.discourse-cdn.com/v4/letter/g/ea5d25/32.png) [@gydev](https://forum.ionicframework.com/u/gydev)\
**Post date:** [October 19, 2017, 2:02pm UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/3 "2017-10-19T14:02:51Z")

</div>

ok, good to know, I am not used with gulp, I assume we can achieve the same with webpack which is used with ionic.  
Wondering why the ionic team did not address this out of the box in the buidling process, I assume they surely encountered this issue ?

---

<div class="post-metadata">

**Author:** ![gaurav\_ch](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/gaurav_ch/32/92509_2.png) [@gaurav\_ch](https://forum.ionicframework.com/u/gaurav_ch)\
**Post date:** [November 25, 2017, 8:36am UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/4 "2017-11-25T08:36:52Z")

</div>

I am also having cache busting problems with lazy load. the main.js and main.css files can be changed but not the lazy loaded generated ones.

---

<div class="post-metadata">

**Author:** ![JeffreyChen](https://avatars.discourse-cdn.com/v4/letter/j/5daacb/32.png) [@JeffreyChen](https://forum.ionicframework.com/u/JeffreyChen)\
**Post date:** [December 12, 2017, 2:51pm UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/5 "2017-12-12T14:51:49Z")

</div>

Don’t know how to solve this issue, too.

---

<div class="post-metadata">

**Author:** ![ahutatatong](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/ahutatatong/32/116411_2.png) [@ahutatatong](https://forum.ionicframework.com/u/ahutatatong)\
**Post date:** [January 11, 2018, 4:51pm UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/6 "2018-01-11T16:51:09Z")

</div>

I have written a [short tutorial](https://www.anagram.at/ionic-cache-busting-webpack/) explaining how this can be achieved.

It’s not ideal as its not completely dry but not too bad either (depends on how often you publish). Basically you need to adapt the webpack configuration and the index.html file.

---

<div class="post-metadata">

**Author:** ![gydev](https://avatars.discourse-cdn.com/v4/letter/g/ea5d25/32.png) [@gydev](https://forum.ionicframework.com/u/gydev)\
**Post date:** [January 12, 2018, 8:57am UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/7 "2018-01-12T08:57:39Z")

</div>

ohh sounds nice, I’ll have a look over the weekend ! Thanks for letting us know!  
Herzlichen Dank und schöne Wochenende!

---

<div class="post-metadata">

**Author:** ![rubencasas09](https://avatars.discourse-cdn.com/v4/letter/r/c77e96/32.png) [@rubencasas09](https://forum.ionicframework.com/u/rubencasas09)\
**Post date:** [January 12, 2018, 5:16pm UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/8 "2018-01-12T17:16:49Z")

</div>

There is a discussion on Github about this [https://github.com/ionic-team/ionic-app-scripts/issues/201](https://github.com/ionic-team/ionic-app-scripts/issues/201), I have implemented the solution by bergergit on 29 Nov 2017 and seems to work with lazy loading as well. The only file that doesn’t add the hash is polyfills.js

---

<div class="post-metadata">

**Author:** ![ramon](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/ramon/32/75852_2.png) [@ramon](https://forum.ionicframework.com/u/ramon)\
**Post date:** [June 8, 2018, 9:31am UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/9 "2018-06-08T09:31:15Z")

</div>

Hi.  
I solved it following this simple steps:

**1. Create “config” directory in the root path of my project with following “webpack.config.js” file:**

```auto
var webpack = require('webpack');
const defaultWebpackConfig = require('../node_modules/@ionic/app-scripts/config/webpack.config.js');

module.exports = function () {
    defaultWebpackConfig.prod.output['chunkFilename'] = "[name].[chunkhash].chunk.js";
    defaultWebpackConfig.dev.output['chunkFilename'] = "[name].[chunkhash].chunk.js";
    return defaultWebpackConfig;
};

```

**2. Add this lines to my package.json:**

```auto
"config": {
    "ionic_webpack": "./config/webpack.config.js"
},

```

Et voilà! Problem solved.

 ![Snip20180608_8](https://global.discourse-cdn.com/ionicframework/original/3X/f/7/f794935408d82a3f3e7f6fb54c98df58e03d18c5.png)

Hope it helps!

---

<div class="post-metadata">

**Author:** ![robinyo](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/robinyo/32/115964_2.png) [@robinyo](https://forum.ionicframework.com/u/robinyo)\
**Post date:** [June 8, 2018, 9:26pm UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/10 "2018-06-08T21:26:59Z")

</div>

> [@gydev](#):
>
> looking for an elegant solution for forcing cache buster.

See: [[PWA] Service worker app cache duration - #2 by robinyo](https://forum.ionicframework.com/t/pwa-service-worker-app-cache-duration/125400/2)

---

<div class="post-metadata">

**Author:** ![salonmonster](https://sea1.discourse-cdn.com/ionicframework/user_avatar/forum.ionicframework.com/salonmonster/32/120304_2.png) [@salonmonster](https://forum.ionicframework.com/u/salonmonster)\
**Post date:** [July 6, 2018, 4:54am UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/11 "2018-07-06T04:54:53Z")

</div>

Super helpful, thanks!

Combined with meirmsn’s code from: [https://gist.github.com/meirmsn/9b37d6c500654b9a487e0c0a72583ef2](https://gist.github.com/meirmsn/9b37d6c500654b9a487e0c0a72583ef2)

it makes a great complete solution

(swap this code in for the webpack.config.js code)

---

<div class="post-metadata">

**Author:** ![reedrichards](https://avatars.discourse-cdn.com/v4/letter/r/34f0e0/32.png) [@reedrichards](https://forum.ionicframework.com/u/reedrichards)\
**Post date:** [July 6, 2018, 6:06am UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/12 "2018-07-06T06:06:39Z")

</div>

For the record, I found and documented the solution in [[PWA] Service worker app cache duration](https://forum.ionicframework.com/t/pwa-service-worker-app-cache-duration/125400/13) yesterday. Using `workbox` instead of `sw-toolbox` seems to handle better the “cache busting” when redeploying a new app

---

<div class="post-metadata">

**Author:** ![Damiendev](https://avatars.discourse-cdn.com/v4/letter/d/ed655f/32.png) [@Damiendev](https://forum.ionicframework.com/u/Damiendev)\
**Post date:** [May 13, 2019, 5:55pm UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/13 "2019-05-13T17:55:12Z")

</div>

Thank you! This seems to have fixed my PWA caching issue!

---

<div class="post-metadata">

**Author:** ![softwaresciences](https://avatars.discourse-cdn.com/v4/letter/s/958977/32.png) [@softwaresciences](https://forum.ionicframework.com/u/softwaresciences)\
**Post date:** [August 17, 2019, 2:25pm UTC](https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/14 "2019-08-17T14:25:52Z")

</div>

**All files hashed, and solving a problem where the `ionic_webpack` parameter suddenly stopped being used by ionic v3**

I solved the hashing of the main.js, polyfills.js, etc by using `filename` AND `chunkFilename` in  
**/config/webpack.config.js**

```auto
var webpack = require('webpack');
const defaultWebpackConfig = require('../node_modules/@ionic/app-scripts/config/webpack.config.js');

module.exports = function () {
  defaultWebpackConfig.prod.output['chunkFilename'] = "[name].[chunkhash:10].js";
  defaultWebpackConfig.dev.output['chunkFilename'] = "[name].[chunkhash:10].js";
  defaultWebpackConfig.prod.output['filename'] = "[name].[chunkhash:10].js";
  defaultWebpackConfig.dev.output['filename'] = "[name].[chunkhash:10].js";
  return defaultWebpackConfig;
};

```

then, adding to package.json

```auto
    "scripts": {
        "ionic_webpack": "./config/webpack.config.js"
    },

```

**then to clean up any additional unhashed files** , you can add the `scripts/cache-busting.js`

```auto
#!/usr/bin/env node
// This file when run (i.e: npm run postbuild) will add a hash to these files: main.js, main.css, polyfills.js, vendor.js
// and will update index.html so that the script/link tags request those files with their corresponding hashes
// Based upon source: https://gist.github.com/haydenbr/7df417a8678efc404c820c61b6ffdd24
// Don't forget to: chmod 755 scripts/cache-busting.js

var fs = require('fs'),
    path = require('path'),
    cheerio = require('cheerio'),
    revHash = require('rev-hash');
const { exit } = require('process');
const { execSync } = require('child_process');

function exe(cmd){
  execSync(cmd, (error, stdout, stderr) => {
  if(error !== null){
    exit(error);
    return;
  }
  console.log(stdout);
  console.error(stderr);
})};
//exe('ls -l');

function findFile(dir,rgx){
  var files=fs.readdirSync(dir);
  for(var i=0;i<files.length;i++){
    if(rgx.test(path.join(dir,files[i]))){
      return path.join(dir,files[i]);
    }
  }
  return null;
}

var rootDir = path.resolve(__dirname, '../');
// var wwwRootDir = path.resolve(rootDir, 'platforms', 'browser', 'www');
var wwwRootDir = path.resolve(rootDir, 'www');
var buildDir = path.join(wwwRootDir, 'build');
var indexPath = path.join(wwwRootDir, 'index.html');
var serviceWorkerPath = path.join(wwwRootDir, 'service-worker.js');
var oldSWPaths = path.join(wwwRootDir, 'service-worker.*.js');
exe(`if [-e ${oldSWPaths}]; then rm ${oldSWPaths};fi`);

var cssPath = path.join(buildDir, 'main.css');
var cssFileHash = revHash(fs.readFileSync(cssPath));
var cssNewFileName = `main.${cssFileHash}.css`;
var cssNewPath = path.join(buildDir, cssNewFileName);
var cssNewRelativePath = path.join('build', cssNewFileName);

 var jsPath = path.join(buildDir, 'main.js');
 var jsHashedPath = findFile(buildDir,/main.*.js/);
 var jsFileHash;
 var jsNewFileName;
 if(jsPath == jsHashedPath && fs.existsSync(jsPath)){
   jsFileHash = revHash(fs.readFileSync(jsPath));
   jsNewFileName = `main.${jsFileHash}.js`;
 }
 else{
   jsPath = jsHashedPath;
   jsNewFileName = jsPath.replace(buildDir,'');
 }
// var jsNewFileName = `main.${jsFileHash}.js`;
var jsNewPath = path.join(buildDir, jsNewFileName);
var jsNewRelativePath = path.join('build', jsNewFileName);

var jsPolyfillsPath = path.join(buildDir, 'polyfills.js');
var jsPolyfillsFileHash = revHash(fs.readFileSync(jsPolyfillsPath));
var jsPolyfillsNewFileName = `polyfills.${jsPolyfillsFileHash}.js`;
var jsPolyfillsNewPath = path.join(buildDir, jsPolyfillsNewFileName);
var jsPolyfillsNewRelativePath = path.join('build', jsPolyfillsNewFileName);

var jsVendorPath = path.join(buildDir, 'vendor.js');
var jsVendorHashedPath = findFile(buildDir,/vendor.*.js/);
var jsVendorFileHash;
var jsVendorNewFileName;
if(jsVendorPath == jsVendorHashedPath && fs.existsSync(jsVendorPath)){
  jsVendorFileHash = revHash(fs.readFileSync(jsVendorPath));
  jsVendorNewFileName = `vendor.${jsVendorFileHash}.js`;
}
else{
  jsVendorPath = jsVendorHashedPath;
  jsVendorNewFileName = jsVendorPath.replace(buildDir,'');
}
// var jsVendorFileHash = revHash(fs.readFileSync(jsVendorPath));
// var jsVendorNewFileName = `vendor.${jsVendorFileHash}.js`;
var jsVendorNewPath = path.join(buildDir, jsVendorNewFileName);
var jsVendorNewRelativePath = path.join('build', jsVendorNewFileName);

var jsToolboxPath = path.join(buildDir, 'sw-toolbox.js');
var jsToolboxFileHash = revHash(fs.readFileSync(jsToolboxPath));
var jsToolboxNewFileName = `sw-toolbox.${jsToolboxFileHash}.js`;
var jsToolboxNewPath = path.join(buildDir, jsToolboxNewFileName);
var jsToolboxNewRelativePath = path.join('build', jsToolboxNewFileName);

// rename main.css to main.[hash].css
fs.renameSync(cssPath, cssNewPath);
if(fs.existsSync(cssPath+'.map'))
fs.renameSync(cssPath+'.map', cssNewPath+'.map');

// rename main.js to main.[hash].js
fs.renameSync(jsPath, jsNewPath);
if(fs.existsSync(jsPath+'.map'))
fs.renameSync(jsPath+'.map', jsNewPath+'.map');

// rename polyfills.js to polyfills.[hash].js
fs.renameSync(jsPolyfillsPath, jsPolyfillsNewPath);
if(fs.existsSync(jsPolyfillsPath+'.map'))
fs.renameSync(jsPolyfillsPath+'.map', jsPolyfillsNewPath+'.map');

// rename vendor.js to vendor.[hash].js
fs.renameSync(jsVendorPath, jsVendorNewPath);
if(fs.existsSync(jsVendorPath+'.map'))
fs.renameSync(jsVendorPath+'.map', jsVendorNewPath+'.map');

// rename sw-toolbox.js to sw-toolbox.[hash].js
fs.renameSync(jsToolboxPath, jsToolboxNewPath);
if(fs.existsSync(jsToolboxPath+'.map'))
fs.renameSync(jsToolboxPath+'.map', jsToolboxNewPath+'.map');

// update service-worker.js to load main.[hash].css
var swFile = fs.readFileSync(serviceWorkerPath, 'utf-8');
swFile = swFile.replace(/build\/main.css/mg,cssNewRelativePath)
.replace(/build\/main.js/mg,jsNewRelativePath)
.replace(/build\/polyfills.js/mg,jsPolyfillsNewRelativePath)
.replace(/build\/vendor.js/mg,jsVendorNewRelativePath)
.replace(/build\/sw-toolbox.js/mg,jsToolboxNewRelativePath);

fs.writeFileSync(serviceWorkerPath, swFile);

var swHash = revHash(fs.readFileSync(serviceWorkerPath));
fs.renameSync(serviceWorkerPath, serviceWorkerPath.replace(/\.js/,`.${swHash}.js`));

// update index.html to load main.[hash].css
$ = cheerio.load(fs.readFileSync(indexPath, 'utf-8'));

$('head link[href="build/main.css"]').attr('href', cssNewRelativePath);
$('body script[src="build/main.js"]').attr('src', jsNewRelativePath);
$('body script[src="build/polyfills.js"]').attr('src', jsPolyfillsNewRelativePath);
$('body script[src="build/vendor.js"]').attr('src', jsVendorNewRelativePath);
$('body script[src="build/sw-toolbox.js"]').attr('src', jsToolboxNewRelativePath);
const jsSWorker = $(`<script type="text/javascript">
   if (\'serviceWorker\' in navigator) {
      navigator.serviceWorker.register(\'service-worker.${swHash}.js\')
        .then(() => console.log(\'service worker installed\'))
        .catch(err => console.error(\'Error\', err));
    }
   </script>`);
$('head script').replaceWith(jsSWorker);

fs.writeFileSync(indexPath, $.html());

```

and adding to `package.json`

```auto
    "scripts": {
        "build:prod": "ionic-app-scripts build --prod --platform browser && npm run postbuild",
        "postbuild": "./scripts/cache-busting.js",
    },

```

**At some point, the hashing stopped working,** and I found that the `ionic_webpack` was no longer being read from `package.json`  
So to fix that, you can just add the parameter directly to the build command:

```auto
    "scripts": {
        "build:prod": "ionic-app-scripts build --prod --webpack ./config/webpack.config.js --platform browser && npm run postbuild",
    },

```

**Files loading, hashed:**

 ![image](https://global.discourse-cdn.com/ionicframework/original/3X/f/1/f1c67e31736f9f3a813c6abfab9f12bff290c49f.png)
