I have extended default web pack config in Ionic v3 for forcing cache busting.
I am able to fingerprint generated JavaScript artifacts, but I am unable to fingerprint images and JSON files under the assets folder. I took Help from Bundled files and cache-busting
.
An excerpt of webpack config.js
module.exports = {
// ...
output: {
filename: '[name].[chunkhash].js',
chunkFilename: '[name].[chunkhash].js',
},
plugins: [
new WebpackChunkHash({algorithm: 'md5'}) // 'md5' is default value
]
}
The above is the approach for fingerprinting JavaScript bundles, and it’s working fine. I want to add hashes/fingerprint images and JSON files inside the assets folder. I used the same approach for images also, but it did not work.
I have extended webpack config.js and added a new rule for images. By default webpack directly copies the images and assets to the output folder.
Copy Config.js
module.exports = {
copyAssets: {
src: ['{{SRC}}/assets/**/*'],
dest: '{{WWW}}/assets'
},
copyIndexContent: {
src: ['{{SRC}}/index.html', '{{SRC}}/manifest.json', '{{SRC}}/service-worker.js'],
dest: '{{WWW}}'
},
copyFonts: {
src: ['{{ROOT}}/node_modules/ionicons/dist/fonts/**/*', '{{ROOT}}/node_modules/ionic-angular/fonts/**/*'],
dest: '{{WWW}}/assets/fonts'
},
Here images and other assets are directly copied. I have added a new rule in extended webpack.config.js, but the build process is ignoring it. How do I fix this issue?
Excerpt of webpack config.js
{
test: /.(png|jpg|gif)$/,
loader: 'file-loader',
options: {
name:'[name].[hash].[ext]',//adding hash for cache busting
outputPath:'assets/imgs',
publicPath:'assets/imgs'
},
entire Webpack.config.js
/*
* The webpack config exports an object that has a valid webpack configuration
* For each environment name. By default, there are two Ionic environments:
* "dev" and "prod". As such, the webpack.config.js exports a dictionary object
* with "keys" for "dev" and "prod", where the value is a valid webpack configuration
* For details on configuring webpack, see their documentation here
* https://webpack.js.org/configuration/
*/
var path = require('path');
var webpack = require('webpack');
var ionicWebpackFactory = require(process.env.IONIC_WEBPACK_FACTORY);
var ModuleConcatPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
var PurifyPlugin = require('@angular-devkit/build-optimizer').PurifyPlugin;
var optimizedProdLoaders = [
{
test: /.json$/,
loader: 'json-loader'
},
{
test: /.js$/,
loader: [
{
loader: process.env.IONIC_CACHE_LOADER
},
{
loader: '@angular-devkit/build-optimizer/webpack-loader',
options: {
sourceMap: true
}
},
]
},
{
test: /.ts$/,
loader: [
{
loader: process.env.IONIC_CACHE_LOADER
},
{
loader: '@angular-devkit/build-optimizer/webpack-loader',
options: {
sourceMap: true
}
},
{
test: /.(png|jpg|gif)$/,
loader: 'file-loader',
options: {
name:'[name].[hash].[ext]',
outputPath:'assets/imgs',
publicPath:'assets/imgs'
},
},
{
loader: process.env.IONIC_WEBPACK_LOADER
}
]
}
];
function getProdLoaders() {
if (process.env.IONIC_OPTIMIZE_JS === 'true') {
return optimizedProdLoaders;
}
return devConfig.module.loaders;
}
var devConfig = {
entry: process.env.IONIC_APP_ENTRY_POINT,
output: {
path: '{{BUILD}}',
publicPath: 'build/',
filename: '[name].js',
devtoolModuleFilenameTemplate: ionicWebpackFactory.getSourceMapperFunction(),
},
devtool: process.env.IONIC_SOURCE_MAP_TYPE,
resolve: {
extensions: ['.ts', '.js', '.json'],
modules: [path.resolve('node_modules')]
},
module: {
loaders: [
{
test: /.json$/,
loader: 'json-loader'
},
{
test: /.ts$/,
loader: process.env.IONIC_WEBPACK_LOADER
},
{
test: /.(jpg|png)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[hash].[ext]",
outputPath:'assets/imgs',
publicPath:'assets/imgs'
},
}},
]
},
plugins: [
ionicWebpackFactory.getIonicEnvironmentPlugin(),
ionicWebpackFactory.getCommonChunksPlugin()
],
// Some libraries import Node.js modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
node: {
fs: 'empty',
net: 'empty',
tls: 'empty'
}
};
var prodConfig = {
entry: process.env.IONIC_APP_ENTRY_POINT,
output: {
path: '{{BUILD}}',
publicPath: 'build/',
filename: '[name].js',
devtoolModuleFilenameTemplate: ionicWebpackFactory.getSourceMapperFunction(),
},
devtool: process.env.IONIC_SOURCE_MAP_TYPE,
resolve: {
extensions: ['.ts', '.js', '.json'],
modules: [path.resolve('node_modules')]
},
module: {
loaders: getProdLoaders()
},
plugins: [
ionicWebpackFactory.getIonicEnvironmentPlugin(),
ionicWebpackFactory.getCommonChunksPlugin(),
new ModuleConcatPlugin(),
new PurifyPlugin()
],
// Some libraries import Node.js modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
node: {
fs: 'empty',
net: 'empty',
tls: 'empty'
}
};
module.exports = {
dev: devConfig,
prod: prodConfig
}
Advertisement
Answer
Eventually, I used gulp for fingerprinting static assets.
- Drop Angular Output hashing and build the application.
ng build --prod --aot --output-hashing none
. - post-build execute a gulp script which would fingerprint all the assets and update the references.
npm i gulp gulp-rev gulp-rev-delete-original gulp-rev-collector
gulpfile.js
const gulp = require('gulp');
const rev = require('gulp-rev');
const revdel = require('gulp-rev-delete-original');
const collect = require('gulp-rev-collector');
// finger priniting static assets
gulp.task('revision:fingerprint', () => {
return gulp
.src([
'dist/welcome/**/*.css',
'dist/welcome/**/*.js',
'dist/welcome/**/*.{jpg,png,jpeg,gif,svg,json,xml,ico,eot,ttf,woff,woff2}'
])
.pipe(rev())
.pipe(revdel())
.pipe(gulp.dest('dist/welcome'))
.pipe(rev.manifest({ path: 'manifest-hash.json' }))
.pipe(gulp.dest('dist'));
});
gulp.task('revision:update-fingerprinted-references', () => {
return gulp
.src(['dist/manifest-hash.json', 'dist/**/*.{html,json,css,js}'])
.pipe(collect())
.pipe(gulp.dest('dist'));
});
gulp.task(
'revision',
gulp.series(
'revision:fingerprint',
'revision:update-fingerprinted-references'));
Add a new script in package.json
"gulp-revision": "gulp revision"
Execute npm run gulp-revision
Post-build.