Posted under Angular & Knowledge Base & PWAs & Web
Permalink
Tags Tip, Tutorial
My PWAs dynamically create and load a url cache in the service worker, when the installation event fires.
As this cache contains all the files in the dist/project-name directory tree (i.e. the entire deployment) for an angular app, I was keen to create the script containing the list of files to be cached dynamically as a post build step, so that the post build script could be generic and adaptive to the build contents.
This turned out to be pretty straightforward. The following points are noteworthy:
- I wanted to dynamically create a JS file which defined an array containing the urls of all the files to be cached. This script would then be included by the service worker to be used when it created and loaded the cache, during its install event.
- The above JS file was imported by the service worker script. I had some issues getting this to work via modules/module support, and noted from this post here that using the importScripts function instead (e.g. importScripts(‘pwa-cache-urls.js’);) gave better cross browser support/backwards compatibility. I therefore switched to using importScripts and it all worked fine.
- glob.sync was used to generate an array containing all the deployed files to be cached, excluding directories using {nodir: true}. This was then mapped/formatted as required into a string containing all the script for the file.
- fs.writeFileSync was used to create the script file from the above string.
- The project name and the generated script file name were passed as arguments to the post build file, in package.json. Whilst I did look for a dynamic way to derive/lookup the project name, an easy way to do this was not obvious and there was no loss of flexibility in just passing it in the postbuild script definition in package.json, along with the name of the dynamically created script file.
This all worked fine, and I was able to create a generic post build script that would be able to discover the files to be cached dynamically and create the script for them, for any angular project I was working with.
The prototype example code for the post build is below:
const glob= require(‘glob’);
const fs = require(‘fs’);const args = process.argv;
validateArgs(args);
const projectName = args[2];
const cacheJSFileName = args[3];const pathPrefix = ‘dist/’ + projectName + “/”;
const cacheJSFilePath = pathPrefix + cacheJSFileName;fs.writeFileSync(cacheJSFilePath, buildCacheJSFile());
function validateArgs(args) {
const argErrors = [
“Project Name and Cache Filename were not passed to post-build.js”,
“Cache Filename was not passed to post-build.js”
]
if (args.length < 4) {
throw new Error(argErrors[args.length – 2]);
}
}function buildCacheJSFile() {
const mapPathDelimiters = (path) => path.replaceAll(“\\”, “/”);
const mapPathPrefix = (path) => path.replace(pathPrefix, “”);const cacheJSFilePrefix = “const CACHED_URLS = [\r\n ‘./'”;
const cacheJSFileSuffix = “\r\n]\r\n”;
const formatCacheJSFileEntry = (file) => “,\r\n ‘” + file + “‘”;const cacheFiles = glob.sync(pathPrefix + “**”, {nodir: true});
let mappedCacheFiles = cacheFiles.map((file) => mapPathPrefix(mapPathDelimiters(file)));
let cacheJSFile = cacheJSFilePrefix;
mappedCacheFiles.forEach( file => cacheJSFile += formatCacheJSFileEntry(file));
cacheJSFile += cacheJSFileSuffix;
return cacheJSFile;
}
Comments Off on Progressive Web Apps – Dynamic Cache Script Creation