Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

broccoli-serviceworker

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

broccoli-serviceworker - npm Package Compare versions

Comparing version 0.0.4 to 0.0.5

lib/delete-old-caches.js

6

lib/ember-addon.js

@@ -23,4 +23,4 @@ var path = require('path');

enabled: this.app.env === 'production',
excludePaths: ['test.*'],
includePaths: ['/'],
excludePaths: ['test.*','robots.txt'],
precacheURLs: []
};

@@ -52,3 +52,3 @@

contentFor: function(type, config) {
if (config.environment !== 'test' && type === 'body-footer') {
if (config.environment !== 'test' && (!config.serviceWorker || config.serviceWorker.includeRegistration!== false) && type === 'body-footer') {
return stringifile('registration.js', 'script', __dirname);

@@ -55,0 +55,0 @@ }

if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./service-worker.js', {scope: './'})
.catch(function(error) {
alert('Error registering service worker:'+error);
console.error('Error registering service worker:'+error);
});
} else {
alert('service worker not supported');
}
console.log('service worker not supported');
}

@@ -6,3 +6,5 @@ var fs = require("fs");

var funnel = require('broccoli-funnel');
var swCachePolyFillFile = require.resolve('serviceworker-cache-polyfill');
var swToolboxFile = require.resolve('sw-toolbox/sw-toolbox.js');
var swToolboxMapFile = require.resolve('sw-toolbox/sw-toolbox.map.json');
var toolboxLocation = 'sw-toolbox.js';

@@ -15,11 +17,22 @@ var BroccoliServiceWorker = function BroccoliServiceWorker(inTree, options) {

options = options || {};
this.addPolyfill = options.addPolyfill || true;
this.skipWaiting = options.skipWaiting || false;
this.debug = options.debug || true;
if (options.skipWaiting === false) {
this.skipWaiting = false;
} else {
this.skipWaiting = true;
}
this.debug = options.debug || false;
this.dynamicCache = options.dynamicCache || [];
this.excludePaths = options.excludePaths || ['tests/*'];
this.fallback = options.fallback || [];
this.includePaths = options.includePaths || [];
this.polyFillLocation = options.polyFillLocation || 'serviceworker-cache-polyfill.js';
this.serviceWorkerFile = options.serviceWorkerFile || "service-worker.js";
this.precacheURLs = options.precacheURLs || [];
if (options.includeRegistration === false) {
this.includeRegistration = false;
} else {
this.includeRegistration = true;
}
if (this.includeRegistration === true || !options.serviceWorkerFile) {
this.serviceWorkerFile = "service-worker.js";
} else {
this.serviceWorkerFile = options.serviceWorkerFile;
}
};

@@ -31,3 +44,2 @@

BroccoliServiceWorker.prototype.write = function(readTree, destDir) {
var addPolyfill = this.addPolyfill;
var skipWaiting = this.skipWaiting;

@@ -37,4 +49,3 @@ var debug = this.debug;

var fallback = this.fallback;
var includePaths = this.includePaths;
var polyFillLocation = this.polyFillLocation;
var precacheURLs = this.precacheURLs;
var serviceWorkerFile = this.serviceWorkerFile;

@@ -46,36 +57,12 @@ var serviceWorkerTree = funnel(this.inTree, {

return readTree(serviceWorkerTree).then(function (srcDir) {
var cacheVersion = (new Date()).getTime();
var lines = [];
if (addPolyfill) {
lines.push("importScripts('"+polyFillLocation+"');");
lines.push("importScripts('"+toolboxLocation+"');");
lines.push("var CACHE_PREFIX = 'brocsw-v';");
lines.push("var CACHE_VERSION = CACHE_PREFIX+'"+(new Date()).getTime()+"';");
lines.push("toolbox.options.cache.name = CACHE_VERSION;");
if (debug) {
lines.push("toolbox.options.debug = true;");
}
lines.push("var CACHE_VERSION = '" + cacheVersion + "';");
lines.push("var CURRENT_CACHES = {");
lines.push(" prefetch: 'prefetch-cache-v' + CACHE_VERSION");
lines.push("};");
if (dynamicCache.length) {
lines.push("CURRENT_CACHES['dynamic'] = 'dynamic-cache-v' + CACHE_VERSION;");
}
if (dynamicCache.length) {
lines.push("var DYNAMIC_URLS = [");
dynamicCache.forEach(function(cacheURL, idx, array) {
lines.push(createArrayLine("new RegExp('"+escapeRegExp(cacheURL)+"')", idx, array.length));
});
lines.push("];");
}
if (fallback.length) {
lines.push("var FALLBACK_URLS = [");
fallback.forEach(function(fallback, idx, array) {
var fallbackParts = fallback.split(' ');
if (fallbackParts.length > 1) {
var matchLine = "{match: new RegExp('"+escapeRegExp(fallbackParts[0])+"'), fallback:'"+fallbackParts[1]+"'}";
lines.push(createArrayLine(matchLine, idx, array.length));
}
});
lines.push("];");
}
lines.push("self.addEventListener('install', function(event) {");
lines.push(" var urlsToPrefetch = [");
lines.push("var urlsToPrefetch = [");
lines.push(" '/',");
getFilesRecursively(srcDir, [ "**/*" ]).forEach(function (file, idx, array) {

@@ -90,146 +77,41 @@ var srcFile = path.join(srcDir, file);

lines.push("];");
includePaths.forEach(function (file, idx, array) {
precacheURLs.forEach(function (file, idx, array) {
lines.push("urlsToPrefetch.push('"+file+"');");
});
//ServiceWorker code derived from examples at https://github.com/GoogleChrome/samples/tree/gh-pages/service-worker
addDebugLine("'Handling install event. Resources to pre-fetch:', urlsToPrefetch", debug, lines);
if (skipWaiting) {
lines.push(" if (self.skipWaiting) { self.skipWaiting(); }");
}
lines.push(" event.waitUntil(");
lines.push(" caches.open(CURRENT_CACHES['prefetch']).then(function(cache) {");
lines.push(" return cache.addAll(urlsToPrefetch.map(function(urlToPrefetch) {");
lines.push(" return new Request(urlToPrefetch, {mode: 'no-cors'});");
lines.push(" })).then(function() {");
addDebugLine("'All resources have been fetched and cached.'", debug, lines);
lines.push(" });");
lines.push(" }).catch(function(error) {");
lines.push(" console.error('Pre-fetching failed:', error);");
lines.push(" })");
lines.push(" );");
lines.push("urlsToPrefetch.forEach(function(url) {");
lines.push(" toolbox.router.any(url, toolbox.cacheFirst);");
lines.push("});");
lines.push("self.addEventListener('activate', function(event) {");
lines.push(" // Delete all caches that aren't named in CURRENT_CACHES.");
lines.push(" // While there is only one cache in this example, the same logic will handle the case where");
lines.push(" // there are multiple versioned caches.");
lines.push(" var expectedCacheNames = Object.keys(CURRENT_CACHES).map(function(key) {");
lines.push(" return CURRENT_CACHES[key];");
lines.push(" });");
lines.push(" event.waitUntil(");
lines.push(" caches.keys().then(function(cacheNames) {");
lines.push(" return Promise.all(");
lines.push(" cacheNames.map(function(cacheName) {");
lines.push(" if (expectedCacheNames.indexOf(cacheName) === -1) {");
lines.push(" // If this cache name isn't present in the array of \"expected\" cache names, then delete it.");
addDebugLine("'Deleting out of date cache:', cacheName", debug, lines);
lines.push(" return caches.delete(cacheName);");
lines.push(" }");
lines.push(" })");
lines.push(" );");
lines.push(" })");
lines.push(" );");
lines.push("});");
lines.push("self.addEventListener('fetch', function(event) {");
addDebugLine("'Handling fetch event for', event.request.url", debug, lines);
lines.push("toolbox.precache(urlsToPrefetch);");
if (dynamicCache.length) {
lines.push(" if(dynamicCacheResponse(event)) {");
addDebugLine("'Found dynamic cache response:', event.request.url", debug, lines);
lines.push(" return;");
lines.push(" }");
dynamicCache.forEach(function(cacheURL, idx, array) {
lines.push("toolbox.router.any('"+cacheURL+"',toolbox.networkFirst);");
});
}
addDebugLine("'Looking in caches for:', event.request.url", debug, lines);
lines.push(" event.respondWith(");
lines.push(" // caches.match() will look for a cache entry in all of the caches available to the service worker.");
lines.push(" // It's an alternative to first opening a specific named cache and then matching on that.");
lines.push(" caches.match(event.request).then(function(response) {");
lines.push(" if (response) {");
addDebugLine("'Found response in cache:', response", debug, lines);
if (fallback.length) {
lines.push(" if (response.status >= 400) {");
addDebugLine("'Got error status, checking for fallback. Response status was:', response.status", debug, lines);
lines.push(" return fallbackResponse(event.request, response);");
lines.push(" }");
fallback.forEach(function(fallback, idx, array) {
var fallbackParts = fallback.split(' ');
if (fallbackParts.length > 1) {
var fallbackOptions = "{fallbackURL:'"+fallbackParts[1]+"'}";
lines.push("toolbox.router.any('"+fallbackParts[0]+"',fallbackResponse, "+fallbackOptions+");");
}
});
}
lines.push(" return response;");
lines.push(" }");
addDebugLine("'No response found in cache. About to fetch from network:'+event.request", debug, lines);
lines.push(" // event.request will always have the proper mode set ('cors, 'no-cors', etc.) so we don't");
lines.push(" // have to hardcode 'no-cors' like we do when fetch()ing in the install handler.");
lines.push(" return fetch(event.request).then(function(response) {");
addDebugLine("'Response from network is:', response", debug, lines);
lines.push(" return response;");
lines.push(" }).catch(function(error) {");
lines.push(" // This catch() will handle exceptions thrown from the fetch() operation.");
lines.push(" // Note that a HTTP error response (e.g. 404) will NOT trigger an exception.");
lines.push(" // It will return a normal response object that has the appropriate error code set.");
if (fallback.length) {
addDebugLine("'Got error, checking for fallback. Error was:', error", debug, lines);
lines.push(" return fallbackResponse(event.request, response);");
} else {
lines.push(" console.error('Fetching failed:', error);");
lines.push(" throw error;");
if (skipWaiting || debug) {
lines.push("self.addEventListener('install', function(event) {");
addDebugLine("'Handling install event. Resources to pre-fetch:', urlsToPrefetch", debug, lines);
if (skipWaiting) {
lines.push(" if (self.skipWaiting) { self.skipWaiting(); }");
}
lines.push("});");
}
lines.push(" });");
lines.push(" })");
lines.push(" );");
lines.push("});");
if (dynamicCache.length) {
lines.push("function dynamicCacheResponse(event) {");
lines.push(" var matchingUrls = DYNAMIC_URLS.filter(function(dynamicURL) {");
lines.push(" return (event.request.url.match(dynamicURL) !== null);");
lines.push(" });");
lines.push(" if (matchingUrls.length) {");
addDebugLine("'Pulling dynamic url: '+event.request.url+' from network and adding to cache.'", debug, lines);
lines.push(" event.respondWith(");
lines.push(" caches.open('dynamic-cache-v"+cacheVersion+"').then(function(cache) {");
lines.push(" return fetch(event.request).then(function(response) {");
addDebugLine("'Got response for dynamic url: '+event.request.url+' now adding to cache.', response", debug, lines);
lines.push(" if (response.status >= 400) {");
addDebugLine("'Got response error for dynamic url, try to pull from cache: ',response.status", debug, lines);
lines.push(" caches.match(event.request).then(function(response) {");
lines.push(" return response;");
lines.push(" });");
lines.push(" } else {");
lines.push(" cache.put(event.request, response.clone());");
lines.push(" return response;");
lines.push(" }");
lines.push(" }).catch(function(error) {");
addDebugLine("'Got error for dynamic url, try to pull from cache: ',error", debug, lines);
lines.push(" caches.match(event.request).then(function(response) {");
lines.push(" return response;");
lines.push(" });");
lines.push(" });");
lines.push(" })");
lines.push(" );");
lines.push(" return true;");
lines.push(" } else {");
lines.push(" return false;");
lines.push(" }");
lines.push("}");
}
lines.push(getFileContents('delete-old-caches.js'));
if (fallback.length) {
lines.push("function fallbackResponse(request, response) {");
addDebugLine("'Looking for fallback for:', request.url", debug, lines);
lines.push(" var matchingUrls =FALLBACK_URLS.filter(function(fallbackURL) {");
addDebugLine("'Checking for fallback match with:', fallbackURL", debug, lines);
lines.push(" return (request.url.match(fallbackURL.match) !== null);");
lines.push(" });");
lines.push(" if (matchingUrls.length) {");
addDebugLine("'Fetching from fallback url: '+ matchingUrls[0].fallback +'for url: '+event.request.url", debug, lines);
lines.push(" return caches.match(matchingUrls[0].fallback);");
lines.push(" } else {");
lines.push(" return response; ");
lines.push(" } ");
lines.push("}");
lines.push(getFileContents('fallback-response.js'));
}
lines.push(getFileContents('log-debug.js'));
fs.writeFileSync(path.join(destDir, serviceWorkerFile), lines.join("\n"));
if (addPolyfill) {
fs.writeFileSync(path.join(destDir, polyFillLocation), fs.readFileSync(swCachePolyFillFile));
fs.writeFileSync(path.join(destDir, toolboxLocation), fs.readFileSync(swToolboxFile));
if (debug) {
fs.writeFileSync(path.join(destDir, 'sw-toolbox.map.json'), fs.readFileSync(swToolboxMapFile));
}

@@ -266,2 +148,7 @@ });

function getFileContents(fileName) {
var filePath = [ __dirname, fileName].join('/');
return fs.readFileSync(filePath);
}
module.exports = BroccoliServiceWorker;
{
"name": "broccoli-serviceworker",
"version": "0.0.4",
"version": "0.0.5",
"description": "A broccoli plugin automating ServiceWorker file creation for Broccoli and Ember.js",

@@ -33,5 +33,5 @@ "main": "lib/service-worker.js",

"broccoli-writer": "~0.1.1",
"serviceworker-cache-polyfill": "^3.0.0",
"stringifile": "^0.1.1"
"stringifile": "^0.1.1",
"sw-toolbox": "^3.0.1"
}
}

@@ -14,4 +14,6 @@ broccoli-serviceworker

`npm install --save-dev broccoli-serviceworker`
`ember install broccoli-serviceworker`
###Configuration
By default the service worker will be generated for production builds and the service worker registration logic will be added to your index.html automatically. Additionally, you can further customize broccoli-serviceworker by setting configurations in your environment.js file:
```JavaScript

@@ -22,16 +24,32 @@ //app/config/environment.js

enabled: true,
serviceWorkerFile: "service-worker.js",
excludePaths: ['tests/', 'online.html',],
includePaths: ['/'],
debug: true,
precacheURLs: ['/mystaticresouce'],
excludePaths: ['test.*', 'robots.txt',],
fallback: [
'/online.html offline.html'
'/online.html /offline.html'
],
dynamicCache: [
'/api/todos'
]
],
includeRegistration: true,
serviceWorkerFile: "service-worker.js",
skipWaiting: true
};
```
The following options are available:
* **enabled** - Generate service worker. Defaults to true in production.
* **debug** - Display debug messages in console.
* **precacheURLs** - Array of URLs to precache and always serve from the cache. broccoli-serviceworker will automatically add all Ember app resources (e.g. files in dist) as precached URLs unless explictly excluded in excludePaths.
* **excludePaths** - Array of paths to exclude from precache. Files can be filtered using regular expressions.
```JavaScript
{
excludePaths: ['index.html', new RegExp(/.\.map$/)],
}
```
* **includeRegistration** -- Automatically add the service worker registration script using contentFor to place the script in body-footer. Defaults to true.
* **serviceWorkerFile** - Name of the service worker file to generate. If **includeRegistration** is set to true, this setting is unused. Defaults to *service-worker.js*.
* **fallback** - Array of URLs with fallbacks when the resource isn't available via network or cache.
* **dynamicCache** - List of URLs that should use a network first strategy that falls back to a cached version of the response if the network is unavailable. For more details, see the details on [sw-toolbox's networkFirst strategy](https://github.com/GoogleChrome/sw-toolbox#user-content-toolboxnetworkfirst).
* **skipWaiting** - Allows a simple page refresh to update the app. Defaults to true.
Upgrade your `index.html` (see below) and you are done.
The service worker bootstrap logic will be added to your index.html automatically, using contentFor hooks.

@@ -54,2 +72,3 @@ Usage for Broccoli.js

```
Upgrade your `index.html` (see below) and you are done.

@@ -59,3 +78,3 @@ Options

You can pass some options as the second argument to `writeServiceWorker`:
You can the [options specified above](#configuration) as the second argument to `writeServiceWorker`:

@@ -66,6 +85,6 @@ ```JavaScript

serviceWorkerFile: "service-worker.js",
excludePaths: ['tests/', 'online.html',],
includePaths: ['/'],
excludePaths: ['test.*', 'online.html',],
precacheURLs: ['/api/offlineStates'],
fallback: [
'/online.html offline.html'
'/api/states /api/offlineStates'
],

@@ -79,12 +98,2 @@ dynamicCache: [

Files can be filtered using regular expressions.
```JavaScript
{
excludePaths: ['index.html', new RegExp(/.\.map$/)],
includePaths: ['']
}
```
Upgrade your index.html

@@ -107,5 +116,5 @@ -----------------------

alert('service worker not supported');
}
}
</script>
</html>
```

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc