sw-builder
Advanced tools
Comparing version 1.0.2 to 1.0.3
@@ -1,1 +0,1 @@ | ||
import{writeTextFile}from"fs-utils-sync";import{buildOutputPath,buildPrecacheAssetPaths,generateCacheName,readConfigFile}from"../utils/index.js";import{buildTemplate}from"../template/index.js";const run=({config:e="sw-builder.config.json"})=>{var e=readConfigFile(e),t=buildTemplate(e.template,generateCacheName(),buildPrecacheAssetPaths(e.outDir,e.includeToPrecache,e.excludeFilesFromPrecache));writeTextFile(buildOutputPath(e.outDir),t)};export{run}; | ||
import{writeTextFile}from"fs-utils-sync";import{buildOutputPath,buildPrecacheAssetPaths,generateCacheName,readConfigFile}from"../utils/index.js";import{buildTemplate}from"../template/index.js";const run=({config:e="sw-builder.config.json"})=>{const t=readConfigFile(e),i=buildTemplate(t.template,generateCacheName(),buildPrecacheAssetPaths(t.outDir,t.includeToPrecache,t.excludeFilesFromPrecache));writeTextFile(buildOutputPath(t.outDir),i)};export{run}; |
#! /usr/bin/env node | ||
import process from"node:process";import{parseArgs}from"argv-utils";import{run}from"./build/index.js";try{run(parseArgs(process.argv)),process.exit(0)}catch(r){console.error(r),process.exit(1)} | ||
import process from"node:process";import{parseArgs}from"argv-utils";import{run}from"./build/index.js";(()=>{try{run(parseArgs(process.argv)),process.exit(0)}catch(r){console.error(r),process.exit(1)}})(); |
@@ -1,1 +0,1 @@ | ||
var ERRORS;!function(E){E.INVALID_TEMPLATE_NAME="INVALID_TEMPLATE_NAME",E.INVALID_CONFIG_VALUE="INVALID_CONFIG_VALUE",E.NOT_A_PATH_ELEMENT="NOT_A_PATH_ELEMENT"}(ERRORS=ERRORS||{});export{ERRORS}; | ||
var ERRORS;!function(E){E.INVALID_TEMPLATE_NAME="INVALID_TEMPLATE_NAME",E.INVALID_CONFIG_VALUE="INVALID_CONFIG_VALUE",E.NOT_A_PATH_ELEMENT="NOT_A_PATH_ELEMENT"}(ERRORS||(ERRORS={}));export{ERRORS}; |
@@ -1,1 +0,1 @@ | ||
import{encodeError}from"error-message-utils";import{ERRORS}from"../shared/index.js";import{BASE_TEMPLATE}from"./templates/index.js";const __insertCacheName=(e,r)=>e.replace("const CACHE_NAME = '';",`const CACHE_NAME = '${r}';`),__stringifyPrecacheAssets=t=>{var e="const PRECACHE_ASSETS = [\n";return e+t.reduce((e,r,s)=>e+` '${r}'`+(s<t.length-1?",\n":","),"")+"\n];"},__insertPrecacheAssets=(e,r)=>e.replace("const PRECACHE_ASSETS = [];",__stringifyPrecacheAssets(r)),__buildBaseTemplate=(e,r)=>__insertPrecacheAssets(__insertCacheName(BASE_TEMPLATE,e),r),buildTemplate=(e,r,s)=>{if("base"!==e)throw new Error(encodeError(`The template name '${e}' is not supported.`,ERRORS.INVALID_TEMPLATE_NAME));return __buildBaseTemplate(r,s)};export{buildTemplate}; | ||
import{encodeError}from"error-message-utils";import{ERRORS}from"../shared/index.js";import{BASE_TEMPLATE}from"./templates/index.js";const __insertCacheName=(e,r)=>e.replace("const CACHE_NAME = '';",`const CACHE_NAME = '${r}';`),__stringifyPrecacheAssets=e=>{let r="const PRECACHE_ASSETS = [\n";return r+=e.reduce(((r,s,t)=>`${r} '${s}'${t<e.length-1?",\n":","}`),""),r+="\n];",r},__insertPrecacheAssets=(e,r)=>e.replace("const PRECACHE_ASSETS = [];",__stringifyPrecacheAssets(r)),__buildBaseTemplate=(e,r)=>__insertPrecacheAssets(__insertCacheName(BASE_TEMPLATE,e),r),buildTemplate=(e,r,s)=>{if("base"===e)return __buildBaseTemplate(r,s);throw new Error(encodeError(`The template name '${e}' is not supported.`,ERRORS.INVALID_TEMPLATE_NAME))};export{buildTemplate}; |
@@ -1,121 +0,1 @@ | ||
const BASE_TEMPLATE=`/* ************************************************************************************************ | ||
* CONSTANTS * | ||
************************************************************************************************ */ | ||
// the current version of the cache | ||
const CACHE_NAME = ''; | ||
// assets that will be cached once the service worker is installed | ||
const PRECACHE_ASSETS = []; | ||
/* ************************************************************************************************ | ||
* MAIN CACHE ACTIONS * | ||
************************************************************************************************ */ | ||
/** | ||
* Adds the given list of resource URLs to the cache. | ||
* @param {*} resources | ||
* @returns Promise<void> | ||
*/ | ||
const addResourcesToCache = async (resources) => { | ||
const cache = await caches.open(CACHE_NAME); | ||
await cache.addAll(resources); | ||
}; | ||
/** | ||
* Adds the request and its response to the cache. | ||
* @param {*} request | ||
* @param {*} response | ||
* @returns Promise<void> | ||
*/ | ||
const putInCache = async (request, response) => { | ||
const cache = await caches.open(CACHE_NAME); | ||
await cache.put(request, response); | ||
}; | ||
/** | ||
* Intercepts the fetch requests and attempts to fill them with data from the cache. If not present, | ||
* it will perform the request and store the data in cache. | ||
* Note: the Response stored in cache is a clone as it can only be read once. | ||
* @param {*} request | ||
* @returns Promise<Response> | ||
*/ | ||
const cacheFirst = async (request) => { | ||
// first, try to get the resource from the cache | ||
const responseFromCache = await caches.match(request); | ||
if (responseFromCache) { | ||
return responseFromCache; | ||
} | ||
// next, try to get the resource from the network | ||
try { | ||
const responseFromNetwork = await fetch(request); | ||
putInCache(request, responseFromNetwork.clone()); | ||
return responseFromNetwork; | ||
} catch (error) { | ||
return new Response('Network error happened', { | ||
status: 408, | ||
headers: { 'Content-Type': 'text/plain' }, | ||
}); | ||
} | ||
}; | ||
/* ************************************************************************************************ | ||
* CACHE CLEAN UP ACTIONS * | ||
************************************************************************************************ */ | ||
/** | ||
* Deletes everything stored in cache that doesn't match the current version. | ||
* @returns Promise<void> | ||
*/ | ||
const deleteOldCaches = async () => { | ||
const keyList = await caches.keys(); | ||
const cachesToDelete = keyList.filter((key) => key !== CACHE_NAME); | ||
await Promise.all(cachesToDelete.map((key) => caches.delete(key))); | ||
}; | ||
/* ************************************************************************************************ | ||
* EVENTS * | ||
************************************************************************************************ */ | ||
/** | ||
* Triggers when the Service Worker has been fetched and registered. | ||
* It takes care of adding the base resources to the cache. | ||
*/ | ||
self.addEventListener('install', (event) => { | ||
event.waitUntil(addResourcesToCache(PRECACHE_ASSETS)); | ||
}); | ||
/** | ||
* Triggers after the Service Worker is installed and it has taken control of the app. | ||
* It takes care of enabling navigation preload (if supported) and it also takes control of any | ||
* pages that were controlled by the previous version of the worker (if any). | ||
*/ | ||
self.addEventListener('activate', (event) => { | ||
event.waitUntil(Promise.all([ | ||
self.clients.claim(), | ||
deleteOldCaches(), | ||
])); | ||
}); | ||
/** | ||
* Triggers when the app thread makes a network request. | ||
* It intercepts the request and checks if it can be filled with data from cache. Otherwise, it | ||
* resumes the network request and then stores it cache for future requests. | ||
*/ | ||
self.addEventListener('fetch', (event) => { | ||
event.respondWith(cacheFirst(event.request)); | ||
}); | ||
`;export{BASE_TEMPLATE}; | ||
const BASE_TEMPLATE="/* ************************************************************************************************\n* CONSTANTS *\n************************************************************************************************ */\n\n// the current version of the cache\nconst CACHE_NAME = '';\n\n// assets that will be cached once the service worker is installed\nconst PRECACHE_ASSETS = [];\n\n\n\n\n\n/* ************************************************************************************************\n* MAIN CACHE ACTIONS *\n************************************************************************************************ */\n\n/**\n* Adds the given list of resource URLs to the cache.\n* @param {*} resources\n* @returns Promise<void>\n*/\nconst addResourcesToCache = async (resources) => {\n const cache = await caches.open(CACHE_NAME);\n await cache.addAll(resources);\n};\n\n/**\n* Adds the request and its response to the cache.\n* @param {*} request\n* @param {*} response\n* @returns Promise<void>\n*/\nconst putInCache = async (request, response) => {\n const cache = await caches.open(CACHE_NAME);\n await cache.put(request, response);\n};\n\n/**\n* Intercepts the fetch requests and attempts to fill them with data from the cache. If not present,\n* it will perform the request and store the data in cache.\n* Note: the Response stored in cache is a clone as it can only be read once.\n* @param {*} request\n* @returns Promise<Response>\n*/\nconst cacheFirst = async (request) => {\n // first, try to get the resource from the cache\n const responseFromCache = await caches.match(request);\n if (responseFromCache) {\n return responseFromCache;\n }\n\n // next, try to get the resource from the network\n try {\n const responseFromNetwork = await fetch(request);\n putInCache(request, responseFromNetwork.clone());\n return responseFromNetwork;\n } catch (error) {\n return new Response('Network error happened', {\n status: 408,\n headers: { 'Content-Type': 'text/plain' },\n });\n }\n};\n\n\n\n\n\n/* ************************************************************************************************\n* CACHE CLEAN UP ACTIONS *\n************************************************************************************************ */\n\n/**\n* Deletes everything stored in cache that doesn't match the current version.\n* @returns Promise<void>\n*/\nconst deleteOldCaches = async () => {\n const keyList = await caches.keys();\n const cachesToDelete = keyList.filter((key) => key !== CACHE_NAME);\n await Promise.all(cachesToDelete.map((key) => caches.delete(key)));\n};\n\n\n\n\n\n/* ************************************************************************************************\n* EVENTS *\n************************************************************************************************ */\n\n/**\n* Triggers when the Service Worker has been fetched and registered. \n* It takes care of adding the base resources to the cache.\n*/\nself.addEventListener('install', (event) => {\n event.waitUntil(addResourcesToCache(PRECACHE_ASSETS));\n});\n\n/**\n* Triggers after the Service Worker is installed and it has taken control of the app. \n* It takes care of enabling navigation preload (if supported) and it also takes control of any \n* pages that were controlled by the previous version of the worker (if any).\n*/\nself.addEventListener('activate', (event) => {\n event.waitUntil(Promise.all([\n self.clients.claim(),\n deleteOldCaches(),\n ]));\n});\n\n/**\n* Triggers when the app thread makes a network request. \n* It intercepts the request and checks if it can be filled with data from cache. Otherwise, it \n* resumes the network request and then stores it cache for future requests.\n*/\nself.addEventListener('fetch', (event) => {\n event.respondWith(cacheFirst(event.request));\n});\n";export{BASE_TEMPLATE}; |
@@ -1,1 +0,1 @@ | ||
import{join}from"node:path";import{encodeError}from"error-message-utils";import{isDirectory,readJSONFile,getPathElement,readDirectory}from"fs-utils-sync";import{ERRORS}from"../shared/index.js";const CACHE_NAME_CHARACTERS="abcdefghijklmnopqrstuvwxyz0123456789",CACHE_NAME_LENGTH=10,OUTPUT_NAME="sw.js",__validateConfigFile=e=>{if(!e||"object"!=typeof e)throw console.log(e),new Error(encodeError("The extracted configuration is not a valid object.",ERRORS.INVALID_CONFIG_VALUE));if("string"!=typeof e.outDir||!e.outDir.length||!isDirectory(e.outDir))throw new Error(encodeError(`The outDir '${e.outDir}' is not a directory or doesn't exist.`,ERRORS.INVALID_CONFIG_VALUE));if("string"!=typeof e.template||!e.template.length)throw new Error(encodeError(`The template '${e.template}' is not a valid template name.`,ERRORS.INVALID_CONFIG_VALUE));if(!Array.isArray(e.includeToPrecache)||!e.includeToPrecache.length)throw console.log(e.includeToPrecache),new Error(encodeError(`The includeToPrecache '${e.includeToPrecache}' list is invalid or empty.`,ERRORS.INVALID_CONFIG_VALUE));if(!Array.isArray(e.excludeFilesFromPrecache))throw console.log(e.excludeFilesFromPrecache),new Error(encodeError(`The excludeFilesFromPrecache '${e.excludeFilesFromPrecache}' list is invalid.`,ERRORS.INVALID_CONFIG_VALUE))},__getPathElement=e=>{var r=getPathElement(e);if(null===r||!r.isDirectory&&!r.isFile)throw new Error(encodeError(`The asset '${e}' is not a path element.`,ERRORS.NOT_A_PATH_ELEMENT));return r},__extractCacheableFilesFromDirectory=(r,e,t)=>{let o=readDirectory(e,!0);return(o=o.filter(e=>{e=__getPathElement(e);return e.isFile&&!t.includes(e.baseName)})).map(e=>e.replace(r,""))},readConfigFile=e=>{e=readJSONFile(e);return __validateConfigFile(e),e},generateCacheName=()=>{let e="",r=0;for(;r<CACHE_NAME_LENGTH;)e+=CACHE_NAME_CHARACTERS.charAt(Math.floor(Math.random()*CACHE_NAME_CHARACTERS.length)),r+=1;return e},buildPrecacheAssetPaths=(t,e,o)=>{const i=["/"];return e.forEach(e=>{var r;"/"!==e&&((r=__getPathElement(join(t,e))).isFile&&!o.includes(r.baseName)?i.push(e):i.push(...__extractCacheableFilesFromDirectory(t,r.path,o)))}),i},buildOutputPath=e=>join(e,OUTPUT_NAME);export{CACHE_NAME_CHARACTERS,CACHE_NAME_LENGTH,OUTPUT_NAME,readConfigFile,generateCacheName,buildPrecacheAssetPaths,buildOutputPath}; | ||
import{join}from"node:path";import{encodeError}from"error-message-utils";import{isDirectory,readJSONFile,getPathElement,readDirectory}from"fs-utils-sync";import{ERRORS}from"../shared/index.js";const CACHE_NAME_CHARACTERS="abcdefghijklmnopqrstuvwxyz0123456789",CACHE_NAME_LENGTH=10,OUTPUT_NAME="sw.js",__validateConfigFile=e=>{if(!e||"object"!=typeof e)throw console.log(e),new Error(encodeError("The extracted configuration is not a valid object.",ERRORS.INVALID_CONFIG_VALUE));if("string"!=typeof e.outDir||!e.outDir.length||!isDirectory(e.outDir))throw new Error(encodeError(`The outDir '${e.outDir}' is not a directory or doesn't exist.`,ERRORS.INVALID_CONFIG_VALUE));if("string"!=typeof e.template||!e.template.length)throw new Error(encodeError(`The template '${e.template}' is not a valid template name.`,ERRORS.INVALID_CONFIG_VALUE));if(!Array.isArray(e.includeToPrecache)||!e.includeToPrecache.length)throw console.log(e.includeToPrecache),new Error(encodeError(`The includeToPrecache '${e.includeToPrecache}' list is invalid or empty.`,ERRORS.INVALID_CONFIG_VALUE));if(!Array.isArray(e.excludeFilesFromPrecache))throw console.log(e.excludeFilesFromPrecache),new Error(encodeError(`The excludeFilesFromPrecache '${e.excludeFilesFromPrecache}' list is invalid.`,ERRORS.INVALID_CONFIG_VALUE))},__getPathElement=e=>{const r=getPathElement(e);if(null===r||!r.isDirectory&&!r.isFile)throw new Error(encodeError(`The asset '${e}' is not a path element.`,ERRORS.NOT_A_PATH_ELEMENT));return r},__extractCacheableFilesFromDirectory=(e,r,t)=>{let o=readDirectory(r,!0);return o=o.filter((e=>{const r=__getPathElement(e);return r.isFile&&!t.includes(r.baseName)})),o.map((r=>r.replace(e,"")))},readConfigFile=e=>{const r=readJSONFile(e);return __validateConfigFile(r),r},generateCacheName=()=>{let e="",r=0;for(;r<10;)e+=CACHE_NAME_CHARACTERS.charAt(Math.floor(36*Math.random())),r+=1;return e},buildPrecacheAssetPaths=(e,r,t)=>{const o=["/"];return r.forEach((r=>{if("/"!==r){const i=__getPathElement(join(e,r));i.isFile&&!t.includes(i.baseName)?o.push(r):o.push(...__extractCacheableFilesFromDirectory(e,i.path,t))}})),o},buildOutputPath=e=>join(e,"sw.js");export{CACHE_NAME_CHARACTERS,CACHE_NAME_LENGTH,OUTPUT_NAME,readConfigFile,generateCacheName,buildPrecacheAssetPaths,buildOutputPath}; |
{ | ||
"name": "sw-builder", | ||
"version": "1.0.2", | ||
"version": "1.0.3", | ||
"description": "The sw-builder package automates the creation of your Application's Service Worker, which pre-caches your build. This leads to a better overall performance and enables users to access your PWA without an Internet connection.", | ||
@@ -9,3 +9,3 @@ "main": "dist/index.js", | ||
"scripts": { | ||
"start": "ts-lib-builder --tsconfigPath=tsconfig.build.json", | ||
"start": "ts-lib-builder --tsconfig=tsconfig.build.json", | ||
"test": "echo \"Error: tests are executed with npm run test:(integration|unit)\" && exit 1", | ||
@@ -50,3 +50,3 @@ "test:integration": "vitest run --config vitest.test-integration.config.ts", | ||
"eslint-config-airbnb-typescript": "^18.0.0", | ||
"ts-lib-builder": "^1.0.2", | ||
"ts-lib-builder": "^1.0.3", | ||
"typescript": "^5.4.5", | ||
@@ -57,5 +57,5 @@ "vitest": "^1.6.0" | ||
"argv-utils": "^1.0.2", | ||
"error-message-utils": "^1.0.1", | ||
"fs-utils-sync": "^1.0.0" | ||
"error-message-utils": "^1.0.2", | ||
"fs-utils-sync": "^1.0.1" | ||
} | ||
} |
16926
111
Updatederror-message-utils@^1.0.2
Updatedfs-utils-sync@^1.0.1