# To build a prod version of the app, then just need to run: | |
ionic build --prod && npm run postbuild |
#!/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'); | |
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 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 jsFileHash = revHash(fs.readFileSync(jsPath)); | |
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 jsVendorFileHash = revHash(fs.readFileSync(jsVendorPath)); | |
var jsVendorNewFileName = `vendor.${jsVendorFileHash}.js`; | |
var jsVendorNewPath = path.join(buildDir, jsVendorNewFileName); | |
var jsVendorNewRelativePath = path.join('build', jsVendorNewFileName); | |
// rename main.css to main.[hash].css | |
fs.renameSync(cssPath, cssNewPath); | |
// rename main.js to main.[hash].js | |
fs.renameSync(jsPath, jsNewPath); | |
// rename polyfills.js to polyfills.[hash].js | |
fs.renameSync(jsPolyfillsPath, jsPolyfillsNewPath); | |
// rename vendor.js to vendor.[hash].js | |
fs.renameSync(jsVendorPath, jsVendorNewPath); | |
// 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); | |
fs.writeFileSync(indexPath, $.html()); |
# run this command in your terminal to give npm permission to run the cache busting script | |
chmod 755 ./cache-busting.js |
// Add the following two lines to src/index.html | |
<meta http-equiv="Cache-control" content="no-cache, no-store, must-revalidate"> | |
<meta http-equiv="Pragma" content="no-cache"> | |
// The above change I'm not sure yet if it is helping or not, but leaving it here in case it's useful | |
// or others understand it better |
# Add these modules to your dev dependencies for cache-busting.js to work | |
npm i cheerio --save-dev | |
npm i rev-hash --save-dev |
"scripts": { | |
"postbuild": "./cache-busting.js" | |
} |
// Edit this file: node_modules/@ionic/app-scripts/config/webpack.config.js | |
// The following change enables the hashing of the modules / chunk files, | |
// so it works with lazy loading. | |
// | |
// Add the following line to add "chunkFilename" key to prodConfig' output dict: | |
chunkFilename: '[name].[chunkhash].chunk.js', | |
// So it should look like: | |
var prodConfig = { | |
entry: process.env.IONIC_APP_ENTRY_POINT, | |
output: { | |
path: '{{BUILD}}', | |
publicPath: 'build/', | |
filename: '[name].js', | |
chunkFilename: '[name].[chunkhash].chunk.js', | |
devtoolModuleFilenameTemplate: ionicWebpackFactory.getSourceMapperFunction(), | |
}, | |
// (line 14 is the only change: a one line addition) | |
// Granted this is not the best solution, some problems: you have to remember to add | |
// this line back everytime you are re-installing packages, or installing them for | |
// the first time, or updating ionic to the latest version, and probably many more issues | |
// that are beyond me. But it's somewhat simple and it has worked for my case. |
want to know for ionic, too.
You can avoid having to update webpack.config.js after updating your packages by instead:
1. Creating a “config” directory in the root path of your project with following “webpack.config.js” file:
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 these lines to your package.json:
"config": {
"ionic_webpack": "./config/webpack.config.js"
}
Thanks to Ramon for the tip: https://forum.ionicframework.com/t/bundled-files-and-cache-busting-lazy-loading/109114/9
@MiniRobot that's pretty rad, thank you!
@bilal4 Happy it was helpful! I just tried doing a couple builds and the vendor hash doesn't change for me. Not sure why in your case ionic would change the vendor.js on each build?
@jcyh0120 This gist is for an Ionic Project, not sure what you mean?
Regarding the two lines in index.html they seem to be needed in order to instruct the browser not to cache the index.html file.
Source: https://stackoverflow.com/questions/49547/how-to-control-web-page-caching-across-all-browsers
This works PERFECTLY. Thank you for this awesome, simple integration. Really made my life a LOT easier.
Thanks a lot, your code works great!!!
Great job!!! Thank you so much!!!
Thanks everyone! I'm glad it has been helpful
Does anyone know how I can make this work with the latest version of Ionic?
thanks this solution works for me
but ionic is updating vendor.js also on each build, because of this new file hash is created.
Any solution for this?