{"id":2853,"date":"2024-02-06T13:52:49","date_gmt":"2024-02-06T13:52:49","guid":{"rendered":"https:\/\/salientsoft.co.uk\/?p=2853"},"modified":"2024-02-07T10:49:41","modified_gmt":"2024-02-07T10:49:41","slug":"progressive-web-apps-dynamic-cache-script-creation","status":"publish","type":"post","link":"https:\/\/salientsoft.co.uk\/?p=2853","title":{"rendered":"Progressive Web Apps &#8211; Dynamic Cache Script Creation"},"content":{"rendered":"\n<p>My PWAs dynamically create and load a url cache in the service worker, when the installation event fires.<br \/>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.<\/p>\n<p>This turned out to be pretty straightforward. The following points are noteworthy:<\/p>\n<ol>\n<li>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.<\/li>\n<li>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 <strong><a href=\"https:\/\/stackoverflow.com\/questions\/44901550\">this post here<\/a><\/strong> that using the <em><strong>importScripts<\/strong><\/em> function instead (e.g. <strong><em>importScripts(&#8216;pwa-cache-urls.js&#8217;);<\/em><\/strong>) gave better cross browser support\/backwards compatibility. I therefore switched to using <em><strong>importScripts<\/strong><\/em> and it all worked fine.<\/li>\n<li><em><strong>glob.sync<\/strong><\/em> was used to generate an array containing all the deployed files to be cached, excluding directories using <em><strong>{nodir: true}<\/strong><\/em>. This was then mapped\/formatted as required into a string containing all the script for the file.<\/li>\n<li><em><strong>fs.writeFileSync<\/strong><\/em> was used to create the script file from the above string.<\/li>\n<li>The project name and the generated script file name were passed as arguments to the post build file, in <em><strong>package.json<\/strong><\/em>. 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.<\/li>\n<\/ol>\n<p>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.<\/p>\n<p>The prototype example code for the post build is below:<\/p>\n<blockquote>\n<p>const glob= require(&#8216;glob&#8217;);<br \/>const fs = require(&#8216;fs&#8217;);<\/p>\n<p>const args = process.argv;<br \/>validateArgs(args);<br \/>const projectName = args[2];<br \/>const cacheJSFileName = args[3];<\/p>\n<p>const pathPrefix = &#8216;dist\/&#8217; + projectName + &#8220;\/&#8221;;<br \/>const cacheJSFilePath = pathPrefix + cacheJSFileName;<\/p>\n<p>fs.writeFileSync(cacheJSFilePath, buildCacheJSFile());<\/p>\n<p>function validateArgs(args) {<br \/>\u00a0 const argErrors = [<br \/>\u00a0 \u00a0 &#8220;Project Name and Cache Filename were not passed to post-build.js&#8221;,<br \/>\u00a0 \u00a0 &#8220;Cache Filename was not passed to post-build.js&#8221;<br \/>\u00a0 ]<br \/>\u00a0 if (args.length &lt; 4) {<br \/>\u00a0 throw new Error(argErrors[args.length &#8211; 2]);<br \/>\u00a0 }<br \/>}<\/p>\n<p>function buildCacheJSFile() {<br \/>\u00a0 const mapPathDelimiters = (path) =&gt; path.replaceAll(&#8220;\\\\&#8221;, &#8220;\/&#8221;);<br \/>\u00a0 const mapPathPrefix = (path) =&gt; path.replace(pathPrefix, &#8220;&#8221;);<\/p>\n<p>\u00a0 const cacheJSFilePrefix = &#8220;const CACHED_URLS = [\\r\\n &#8216;.\/'&#8221;;<br \/>\u00a0 const cacheJSFileSuffix = &#8220;\\r\\n]\\r\\n&#8221;;<br \/>\u00a0 const formatCacheJSFileEntry = (file) =&gt; &#8220;,\\r\\n &#8216;&#8221; + file + &#8220;&#8216;&#8221;;<\/p>\n<p>\u00a0 const cacheFiles = glob.sync(pathPrefix + &#8220;**&#8221;, {nodir: true});<br \/>\u00a0 let mappedCacheFiles = cacheFiles.map((file) =&gt; mapPathPrefix(mapPathDelimiters(file)));<br \/>\u00a0 let cacheJSFile = cacheJSFilePrefix;<br \/>\u00a0 mappedCacheFiles.forEach( file =&gt; cacheJSFile += formatCacheJSFileEntry(file));<br \/>\u00a0 cacheJSFile += cacheJSFileSuffix;<br \/>\u00a0 return cacheJSFile;<br \/>}<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>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 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[198,11,239,77],"tags":[16,15],"_links":{"self":[{"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/2853"}],"collection":[{"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2853"}],"version-history":[{"count":6,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/2853\/revisions"}],"predecessor-version":[{"id":2861,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/2853\/revisions\/2861"}],"wp:attachment":[{"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2853"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2853"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2853"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}