├── .gitignore
├── examples
├── app1
│ ├── styles
│ │ └── app.css
│ ├── js
│ │ └── app.js
│ ├── package.json
│ ├── index.html
│ └── gulpfile.js
└── app2
│ ├── styles
│ └── app.css
│ ├── js
│ └── app.js
│ ├── package.json
│ ├── index.html
│ ├── gulpfile.js
│ └── swExtra.js
├── templates
├── unminified
│ ├── cache.tpl.html
│ ├── sw.tpl.js
│ ├── README.md
│ ├── install.tpl.js
│ └── cache.tpl.js
└── index.js
├── package.json
├── README.md
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | node_modules
3 |
--------------------------------------------------------------------------------
/examples/app1/styles/app.css:
--------------------------------------------------------------------------------
1 | body {
2 | color: #FFF;
3 | background-color: #000;
4 | }
5 |
--------------------------------------------------------------------------------
/examples/app2/styles/app.css:
--------------------------------------------------------------------------------
1 | body {
2 | color: #FFF;
3 | background-color: #000;
4 | }
5 |
--------------------------------------------------------------------------------
/examples/app1/js/app.js:
--------------------------------------------------------------------------------
1 | window.addEventListener('DOMContentLoaded', function() {
2 | console.log('We are ready to rock!');
3 | });
4 |
--------------------------------------------------------------------------------
/examples/app2/js/app.js:
--------------------------------------------------------------------------------
1 | window.addEventListener('DOMContentLoaded', function() {
2 | console.log('We are ready to rock!');
3 | });
4 |
--------------------------------------------------------------------------------
/templates/unminified/cache.tpl.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
c
5 |
--------------------------------------------------------------------------------
/examples/app1/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gulp-sww-app1",
3 | "description": "An example that shows how to use the sww gulp plugin",
4 | "version": "0.0.0",
5 | "main": "gulpfile.js",
6 | "devDependencies": {
7 | "gulp": "^3.9.0"
8 | },
9 | "engines": {
10 | "node": ">=4.2.0"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/examples/app2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gulp-sww-app2",
3 | "description": "An example that shows how to use the sww gulp plugin",
4 | "version": "0.0.0",
5 | "main": "gulpfile.js",
6 | "devDependencies": {
7 | "gulp": "^3.9.0"
8 | },
9 | "engines": {
10 | "node": ">=4.2.0"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/examples/app1/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | App1
6 |
7 |
8 |
9 |
10 |
11 | I want to be offline
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/templates/unminified/sw.tpl.js:
--------------------------------------------------------------------------------
1 | importScripts('sww.js');
2 |
3 | var version = '$VERSION';
4 | var worker = new self.ServiceWorkerWare();
5 | worker.use(new self.StaticCacher($FILES_TO_LOAD));
6 | worker.use(new self.SimpleOfflineCache());
7 |
8 | var extraFiles = $HOOK;
9 | if (extraFiles.length) {
10 | importScripts(...extraFiles);
11 | }
12 |
13 | worker.init();
14 |
--------------------------------------------------------------------------------
/examples/app2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | App2
6 |
7 |
8 |
9 |
10 |
11 | I am offline and given extra output in the console
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/examples/app1/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var gulpsww = require('../../');
3 | var package = require('./package.json');
4 |
5 |
6 | gulp.task('offline', function() {
7 | return gulp.src([
8 | '**/*',
9 | '!gulpfile.js',
10 | '!package.json'
11 | ], { cwd: './' })
12 | .pipe(gulpsww({ 'version': package.version }))
13 | .pipe(gulp.dest('./'));
14 | });
15 |
16 | gulp.task('default', ['offline']);
17 |
--------------------------------------------------------------------------------
/examples/app2/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var gulpsww = require('../../');
3 | var package = require('./package.json');
4 |
5 |
6 | gulp.task('offline', function() {
7 | return gulp.src([
8 | '**/*',
9 | '!gulpfile.js',
10 | '!package.json'
11 | ], { cwd: './' })
12 | .pipe(gulpsww({ 'version': package.version, 'hookSW': 'swExtra.js' }))
13 | .pipe(gulp.dest('./'));
14 | });
15 |
16 | gulp.task('default', ['offline']);
17 |
--------------------------------------------------------------------------------
/examples/app2/swExtra.js:
--------------------------------------------------------------------------------
1 | // This file will be injected in the middle of the sw.
2 | // We can use the sww library or directly write code
3 | // for the worker here.
4 |
5 | worker.use({
6 | onActivate: function(evt) {
7 | console.log('I passed through the onActivate event!');
8 | }
9 | })
10 |
11 | worker.get('*', function(request, response) {
12 | console.log('---------> Logging a get request for ', request.url);
13 |
14 | return Promise.resolve(response);
15 | });
--------------------------------------------------------------------------------
/templates/unminified/README.md:
--------------------------------------------------------------------------------
1 | # JavaScript template files
2 |
3 | Here are located the original, unminified JavaScript and HTML files used by the
4 | plugin.
5 |
6 | If you need to modify `/templates/templates.js`, please do the changes on the
7 | corresponding file in this folder and minify it (You can use the [online Closure
8 | Compiler UI](https://closure-compiler.appspot.com/home) for JavaScript files,
9 | `Advanced` optimisation mode is preferred).
10 | Then copy and paste the minified content in `/templates/templates.js`.
11 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gulp-sww",
3 | "version": "0.1.4",
4 | "description": "A gulp plugin to make your web app work offline.",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "mocha"
8 | },
9 | "keywords": [
10 | "gulp",
11 | "gulpplugin",
12 | "sww",
13 | "offline",
14 | "serviceworker",
15 | "serviceworkers",
16 | "service worker",
17 | "service workers",
18 | "appcache"
19 | ],
20 | "author": "Francisco Jordano ",
21 | "homepage": "https://github.com/arcturus/gulp-sww/",
22 | "repository": "git@github.com:arcturus/gulp-sww.git",
23 | "license": "MPL-2.0",
24 | "dependencies": {
25 | "gulp-util": "^3.0.7",
26 | "node-appcache-generator": "0.0.2",
27 | "serviceworkers-ware": "^0.3.2",
28 | "through": "^2.3.8",
29 | "vinyl": "^1.1.0"
30 | },
31 | "engines": {
32 | "node": ">=4.2.0"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/templates/unminified/install.tpl.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
5 | // navigator.serviceWorker and window.applicationCache are both defined in
6 | // http pages but will not work, so we need to check the URL scheme.
7 | // As well we allow the hostname localhost for development pourpuses
8 | return;
9 | }
10 |
11 | if ('serviceWorker' in navigator && !navigator.serviceWorker.controller) {
12 | navigator.serviceWorker.register('sw.js');
13 | } else if ('applicationCache' in window) {
14 | if (localStorage !== null) {
15 | if (localStorage.getItem('cached-by-gulp-sww') !== '1') {
16 | redirect();
17 | }
18 | } else if (location.hash !== '#no-redirect') {
19 | redirect();
20 | }
21 | }
22 |
23 | // Redirect to the page where the assets are being cached.
24 | function redirect() {
25 | var redirectUrl = encodeURIComponent(location.href);
26 | location.href = 'cache.html?redirect_url=' + redirectUrl;
27 | }
28 | })();
29 |
--------------------------------------------------------------------------------
/templates/index.js:
--------------------------------------------------------------------------------
1 | // Look at /templates/unminified/README.md before changing content here.
2 | module.exports = {
3 | INSTALL_TPL_JS: `(function(){function a(){var a=encodeURIComponent(location.href);location.href="cache.html?redirect_url="+a}if("https:"===location.protocol||"localhost"===location.hostname)"serviceWorker"in navigator&&!navigator.serviceWorker.controller?navigator.serviceWorker.register("sw.js"):"applicationCache"in window&&(null!==localStorage?"1"!==localStorage.getItem("cached-by-gulp-sww")&&a():"#no-redirect"!==location.hash&&a())})();`,
4 | SW_TPL_JS: `importScripts("sww.js");var version="$VERSION",worker=new self.ServiceWorkerWare;worker.use(new self.StaticCacher($FILES_TO_LOAD)),worker.use(new self.SimpleOfflineCache);var extraFiles=$HOOK;extraFiles.length&&importScripts(...extraFiles),worker.init();`,
5 | CACHE_TPL_JS: `(function(){function e(){2!==applicationCache.status&&3!==applicationCache.status&&4!==applicationCache.status&&5!==applicationCache.status||c();g--?(d&&clearTimeout(d),d=setTimeout(e,1E3)):c()}function c(){var b=new URLSearchParams(location.search.substring(1));if(!b.has("debug")){var a=location.href.split("/");a.pop();a=a.join("/");b.has("redirect_url")&&(a=b.get("redirect_url")||a);null!==localStorage?localStorage.setItem("cached-by-gulp-sww","1"):a+="#no-redirect";location.href=a}}if(!("URLSearchParams"in
6 | window)){var f=function(b){this.a=b.split("&").map(function(a){var b=a.indexOf("=");return-1===b?[a,""]:[a.substring(0,b),a.substring(b+1)]})};f.prototype.has=function(b){return this.a.some(function(a){return a[0]===b})};f.prototype.get=function(b){var a=null;this.a.some(function(c){return c[0]===b?(a=c[1],!0):!1});return null===a?null:decodeURIComponent(a)};window.URLSearchParams=f}if("https:"!==location.protocol||"serviceWorker"in navigator)return c();var d=null,g=10;applicationCache.addEventListener("cached",
7 | c);applicationCache.addEventListener("checking",e);applicationCache.addEventListener("downloading",e);applicationCache.addEventListener("error",c);applicationCache.addEventListener("noupdate",c);applicationCache.addEventListener("obsolete",c);applicationCache.addEventListener("progress",e);applicationCache.addEventListener("updateready",c);d&&clearTimeout(d);d=setTimeout(e,250)})()`,
8 | CACHE_TPL_HTML: `c`
9 | };
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | gulp-sww
2 | ========
3 |
4 | A [gulp](http://gulpjs.com/) plugin to make your web app work offline.
5 |
6 | How it works
7 | ------------
8 | Once applied to your app, this plugin code caches all your frontend assets using
9 | service workers if supported.
10 |
11 | If not, AppCache is used. In this mode, the main page is redirected to an empty
12 | page that uses appcache to cache your assets. When all the caching operations
13 | are done, the user is redirected back to the main page.
14 | This redirection only happens once.
15 |
16 | Please note that it will only work on web app served over https.
17 |
18 | Details
19 | -------
20 | Make sure to serve the web app over `https`.
21 |
22 | This plugin uses the library [ServiceWorkerWare](https://github.com/fxos-components/serviceworkerware) to provide the integration with Service Worker.
23 | The AppCache manifest is generated by [node-appcache-generator](https://github.com/arcturus/node-appcache-generator).
24 |
25 | The steps this plugin provide are the following:
26 |
27 | + Receives a stream with your final set of assets.
28 | + Generates the files to create the worker and support the offline mode.
29 | + Modifies your `index.html` page to install the caching logic.
30 |
31 | Usage
32 | -----
33 | ```javascript
34 | var sww = require('gulp-sww');
35 |
36 | gulp.task('offline', function() {
37 | return gulp.src('**/*', { cwd : '' } )
38 | .pipe(sww())
39 | .pipe(gulp.dest('