Skip to content

Instantly share code, notes, and snippets.

@meirmsn
Last active April 25, 2020 16:05
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save meirmsn/9b37d6c500654b9a487e0c0a72583ef2 to your computer and use it in GitHub Desktop.
Save meirmsn/9b37d6c500654b9a487e0c0a72583ef2 to your computer and use it in GitHub Desktop.
# 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.
@jcyh0120
Copy link

jcyh0120 commented May 1, 2018

want to know for ionic, too.

@salonmonster
Copy link

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

@meirmsn
Copy link
Author

meirmsn commented Aug 29, 2018

@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?

@andhadj
Copy link

andhadj commented Sep 3, 2018

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

@lincolnthree
Copy link

This works PERFECTLY. Thank you for this awesome, simple integration. Really made my life a LOT easier.

@itayher
Copy link

itayher commented Jan 20, 2019

Thanks a lot, your code works great!!!

@jesusmorenomartin
Copy link

Great job!!! Thank you so much!!!

@meirmsn
Copy link
Author

meirmsn commented Nov 14, 2019

Thanks everyone! I'm glad it has been helpful

@startupskateboard
Copy link

Does anyone know how I can make this work with the latest version of Ionic?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment