So I modified the task in the example to fit an Aurelia project:
post-build.ts:
function injectHash() {
const path = require('path');
const fs = require('fs');
const util = require('util');
// get application version from package.json
const appVersion = require('../../package.json').version;
// promisify core API's
const readDir = util.promisify(fs.readdir);
const writeFile = util.promisify(fs.writeFile);
const readFile = util.promisify(fs.readFile);
// our version.json will be in the dist folder
const versionFilePath = path.join(__dirname + '/../../scripts/version.json');
let mainHash = '';
let mainBundleFile = '';
// RegExp to find main.bundle.js, even if it doesn't include a hash in it's name (dev build)
let mainBundleRegexp = /^app.bundle.([a-z0-9]*)?.js$/;
// read the dist folder files and find the one we're looking for
return readDir(path.join(__dirname, '../../scripts/'))
.then(files => {
mainBundleFile = files.find(f => mainBundleRegexp.test(f));
if (mainBundleFile) {
let matchHash = mainBundleFile.match(mainBundleRegexp);
// if it has a hash in it's name, mark it down
if (matchHash.length > 1 && !!matchHash[1]) {
mainHash = matchHash[1];
}
}
console.log(`Writing version and hash to ${versionFilePath}`);
// write current version and hash into the version.json file
const src = `{"version": "${appVersion}", "hash": "${mainHash}"}`;
return writeFile(versionFilePath, src);
}).then(() => {
// main bundle file not found, dev build?
if (!mainBundleFile) {
return Promise.resolve();
}
console.log(`Replacing hash-variable in the ${mainBundleFile} with value '${mainHash}'`);
// replace hash placeholder in our main.js file so the code knows it's current hash
const mainFilepath = path.join(__dirname, '../../scripts/', mainBundleFile);
return readFile(mainFilepath, 'utf8')
.then(mainFileData => {
const replacedFile = mainFileData.replace('{{POST_BUILD_ENTERS_HASH_HERE}}', mainHash);
return writeFile(mainFilepath, replacedFile);
});
}).catch(err => {
console.log('Error with post build:', err);
});
}
export default function postBuild() {
return injectHash();
}
Add this line in build.ts:
import postBuild from './post-build';
…and add the postBuild
task in the build
variable:
let build = gulp.series(
readProjectConfiguration,
gulp.parallel(
transpile,
processMarkup,
processCSS,
copyFiles,
prepareFontAwesome,
),
writeBundles,
postBuild
);
That was easier than expected, hopefully the client side code will be easy, too
Edit:
version-check-service.ts
:
import { HttpClient } from 'aurelia-fetch-client';
import { autoinject } from 'aurelia-framework';
//https://blog.nodeswat.com/automagic-reload-for-clients-after-deploy-with-angular-4-8440c9fdd96c
@autoinject
export class VersionCheckService {
// this will be replaced by actual hash post-build.js
private currentHash = '{{POST_BUILD_ENTERS_HASH_HERE}}';
constructor(private http: HttpClient) {
}
/**
* Checks in every set frequency the version of frontend application
* @param url
* @param {number} frequency - in milliseconds, defaults to 30 minutes
*/
public initVersionCheck(url, frequency = 1000 * 60 * 1) {
setInterval(() => {
this.checkVersion(url);
}, frequency);
}
/**
* Will do the call and check if the hash has changed or not
* @param url
*/
private checkVersion(url) {
// timestamp these requests to invalidate caches
this.http.fetch(url + '?t=' + new Date().getTime())
.then(r => r.json())
.then( (response: any) =>
{
const hash = response.hash;
console.log('Current hash: ' + this.currentHash);
console.log('New hash : ', hash);
const hashChanged = this.hasHashChanged(this.currentHash, hash);
// If new version, do something
if (hashChanged) {
console.log('Change!');
location.reload(true);
} else {
console.log('No change');
}
// store the new hash so we wouldn't trigger versionChange again
// only necessary in case you did not force refresh
//this.currentHash = hash;
},
(err) => {
console.error(err, 'Could not get version');
}
);
}
/**
* Checks if hash has changed.
* This file has the JS hash, if it is a different one than in the version.json
* we are dealing with version change
* @param currentHash
* @param newHash
* @returns {boolean}
*/
private hasHashChanged(currentHash, newHash) {
if (!currentHash || currentHash === '{{POST_BUILD_ENTERS_HASH_HERE}}') {
return false;
}
return currentHash !== newHash;
}
}