Skip to content

Commit 0fc3e13

Browse files
committed
AppCache runtime events
1 parent 9020558 commit 0fc3e13

File tree

9 files changed

+288
-64
lines changed

9 files changed

+288
-64
lines changed

lib/app-cache.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,22 @@ Object.defineProperty(exports, '__esModule', {
66

77
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
88

9+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
10+
911
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
1012

1113
var _es6Promise = require('es6-promise');
1214

1315
var _miscUtils = require('./misc/utils');
1416

17+
var _fs = require('fs');
18+
19+
var _fs2 = _interopRequireDefault(_fs);
20+
21+
var _path = require('path');
22+
23+
var _path2 = _interopRequireDefault(_path);
24+
1525
var AppCache = (function () {
1626
function AppCache(options) {
1727
_classCallCheck(this, AppCache);
@@ -20,6 +30,7 @@ var AppCache = (function () {
2030
this.FALLBACK = options.FALLBACK;
2131
this.name = 'manifest';
2232
this.caches = options.caches;
33+
this.events = !!options.events;
2334

2435
this.directory = options.directory.replace(/^\//, '').replace(/\/$/, '') + '/';
2536
this.basePath = (0, _miscUtils.pathToBase)(this.directory, true);
@@ -59,7 +70,8 @@ var AppCache = (function () {
5970

6071
var path = this.directory + this.name;
6172
var manifest = this.getManifestTemplate(cache, plugin);
62-
var page = this.getPageTemplate(this.name);
73+
var content = this.getPageContent();
74+
var page = this.getPageTemplate(this.name, content);
6375

6476
compilation.assets[path + '.appcache'] = (0, _miscUtils.getSource)(manifest);
6577
compilation.assets[path + '.html'] = (0, _miscUtils.getSource)(page);
@@ -91,12 +103,22 @@ var AppCache = (function () {
91103
value: function getPageTemplate(name, content) {
92104
return ('\n <!doctype html>\n <html manifest="' + name + '.appcache">' + (content || '') + '</html>\n ').trim().replace(/^ */gm, '');
93105
}
106+
}, {
107+
key: 'getPageContent',
108+
value: function getPageContent() {
109+
if (this.events) {
110+
return _fs2['default'].readFileSync(_path2['default'].join(__dirname, '../tpls/appcache-frame.tpl'), 'utf-8');
111+
} else {
112+
return '';
113+
}
114+
}
94115
}, {
95116
key: 'getConfig',
96117
value: function getConfig(plugin) {
97118
return {
98119
directory: plugin.publicPath + this.directory,
99-
name: this.name
120+
name: this.name,
121+
events: this.events
100122
};
101123
}
102124
}]);

lib/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,16 @@ var defaultOptions = {
6565

6666
ServiceWorker: {
6767
output: 'sw.js',
68-
entry: _path2['default'].join(__dirname, '../empty-entry.js')
68+
entry: _path2['default'].join(__dirname, '../empty-entry.js'),
69+
events: false
6970
},
7071

7172
AppCache: {
7273
NETWORK: '*',
7374
FALLBACK: null,
7475
directory: 'appcache/',
75-
caches: ['main', 'additional']
76+
caches: ['main', 'additional'],
77+
events: false
7678
}
7779
};
7880

lib/service-worker.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ var ServiceWorker = (function () {
3737
this.entry = options.entry;
3838
this.output = options.output.replace(/^\//, '');
3939
this.basePath = (0, _miscUtils.pathToBase)(this.output, true);
40+
this.events = !!options.events;
4041

4142
this.ENTRY_NAME = 'serviceworker';
4243
this.CACHE_NAME = 'webpack-offline';
@@ -175,7 +176,8 @@ var ServiceWorker = (function () {
175176
key: 'getConfig',
176177
value: function getConfig(plugin) {
177178
return {
178-
output: plugin.publicPath + this.output
179+
output: plugin.publicPath + this.output,
180+
events: this.events
179181
};
180182
}
181183
}]);

runtime.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
exports.install = function() {};
1+
exports.install = function() {};
2+
exports.applyUpdate = function() {};

src/app-cache.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import { Promise } from 'es6-promise';
22
import { getSource, pathToBase } from './misc/utils';
3+
import fs from 'fs';
4+
import path from 'path';
35

46
export default class AppCache {
57
constructor(options) {
68
this.NETWORK = options.NETWORK;
79
this.FALLBACK = options.FALLBACK;
810
this.name = 'manifest';
911
this.caches = options.caches;
12+
this.events = !!options.events;
1013

1114
this.directory = options.directory
1215
.replace(/^\//, '')
@@ -41,7 +44,8 @@ export default class AppCache {
4144

4245
const path = this.directory + this.name;
4346
const manifest = this.getManifestTemplate(cache, plugin);
44-
const page = this.getPageTemplate(this.name);
47+
const content = this.getPageContent();
48+
const page = this.getPageTemplate(this.name, content);
4549

4650
compilation.assets[path + '.appcache'] = getSource(manifest);
4751
compilation.assets[path + '.html'] = getSource(page);
@@ -84,10 +88,19 @@ export default class AppCache {
8488
`.trim().replace(/^ */gm, '');
8589
}
8690

91+
getPageContent() {
92+
if (this.events) {
93+
return fs.readFileSync(path.join(__dirname, '../tpls/appcache-frame.tpl'), 'utf-8');
94+
} else {
95+
return '';
96+
}
97+
}
98+
8799
getConfig(plugin) {
88100
return {
89101
directory: plugin.publicPath + this.directory,
90-
name: this.name
102+
name: this.name,
103+
events: this.events
91104
};
92105
}
93106
}

src/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,16 @@ const defaultOptions = {
3535

3636
ServiceWorker: {
3737
output: 'sw.js',
38-
entry: path.join(__dirname, '../empty-entry.js')
38+
entry: path.join(__dirname, '../empty-entry.js'),
39+
events: false
3940
},
4041

4142
AppCache: {
4243
NETWORK: '*',
4344
FALLBACK: null,
4445
directory: 'appcache/',
45-
caches: ['main', 'additional']
46+
caches: ['main', 'additional'],
47+
events: false
4648
}
4749
};
4850

src/service-worker.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export default class ServiceWorker {
1010
this.entry = options.entry;
1111
this.output = options.output.replace(/^\//, '');
1212
this.basePath = pathToBase(this.output, true);
13+
this.events = !!options.events;
1314

1415
this.ENTRY_NAME = 'serviceworker';
1516
this.CACHE_NAME = 'webpack-offline';
@@ -139,7 +140,8 @@ export default class ServiceWorker {
139140

140141
getConfig(plugin) {
141142
return {
142-
output: plugin.publicPath + this.output
143+
output: plugin.publicPath + this.output,
144+
events: this.events
143145
};
144146
}
145147
}

tpls/appcache-frame.tpl

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
<script>
2+
(function() {
3+
// ################################
4+
5+
var updateReadyInterval;
6+
var updatingFired;
7+
var downloadingInterval;
8+
var obsoleteInterval;
9+
var cleanUpTimer;
10+
11+
applicationCache.addEventListener('updateready', onUpdateReadyEvent);
12+
applicationCache.addEventListener('cached', onInstalledEvent);
13+
applicationCache.addEventListener('obsolete', onObsoleteEvent);
14+
15+
applicationCache.addEventListener('downloading', onDownloadingEvent);
16+
applicationCache.addEventListener('progress', onDownloadingEvent);
17+
18+
19+
switch (applicationCache.status) {
20+
case applicationCache.DOWNLOADING: {
21+
setTimeout(onDownloadingEvent, 1);
22+
} break;
23+
case applicationCache.OBSOLETE: {
24+
setTimeout(onObsoleteEvent, 1);
25+
} break;
26+
case applicationCache.UPDATEREADY: {
27+
setTimeout(onUpdateReadyEvent, 1);
28+
} break;
29+
30+
default: {
31+
downloadingInterval = setInterval(function() {
32+
if (applicationCache.status === applicationCache.DOWNLOADING) {
33+
onDownloadingEvent();
34+
}
35+
}, 50);
36+
37+
obsoleteInterval = setInterval(function() {
38+
if (applicationCache.status === applicationCache.OBSOLETE) {
39+
onObsoleteEvent();
40+
}
41+
}, 50);
42+
43+
updateReadyInterval = setInterval(function() {
44+
if (applicationCache.status === applicationCache.UPDATEREADY) {
45+
onUpdateReadyEvent();
46+
}
47+
}, 50);
48+
}
49+
}
50+
51+
cleanUpTimer = setTimeout(function() {
52+
cleanUp();
53+
}, 5000);
54+
55+
// ###############################
56+
57+
function onDownloadingEvent() {
58+
if (!updatingFired) {
59+
updatingFired = true;
60+
onUpdating();
61+
}
62+
63+
downloadingCleanUp();
64+
}
65+
66+
function onUpdateReadyEvent() {
67+
if (!updatingFired) {
68+
updatingFired = true;
69+
onUpdating();
70+
setTimeout(onUpdateReady, 1);
71+
} else {
72+
onUpdateReady();
73+
}
74+
75+
cleanUp();
76+
}
77+
78+
function onInstalledEvent() {
79+
onInstalled();
80+
cleanUp();
81+
}
82+
83+
function onObsoleteEvent() {
84+
onUpdateFailed();
85+
setTimeout(onUninstalled, 1);
86+
cleanUp();
87+
}
88+
89+
function downloadingCleanUp() {
90+
if (downloadingInterval) {
91+
clearInterval(downloadingInterval);
92+
downloadingInterval = null;
93+
}
94+
95+
applicationCache.removeEventListener('downloading', onDownloadingEvent);
96+
applicationCache.removeEventListener('progress', onDownloadingEvent);
97+
}
98+
99+
function cleanUp() {
100+
if (cleanUpTimer) {
101+
clearTimeout(cleanUpTimer);
102+
cleanUpTimer = null;
103+
}
104+
105+
downloadingCleanUp();
106+
107+
applicationCache.removeEventListener('updateready', onUpdateReadyEvent);
108+
applicationCache.removeEventListener('cached', onInstalledEvent);
109+
applicationCache.removeEventListener('obsolete', onObsoleteEvent);
110+
111+
if (updateReadyInterval) {
112+
clearInterval(updateReadyInterval);
113+
updateReadyInterval = null;
114+
}
115+
116+
if (obsoleteInterval) {
117+
clearInterval(obsoleteInterval);
118+
obsoleteInterval = null;
119+
}
120+
}
121+
122+
// ################################
123+
}());
124+
125+
function onUpdating() {
126+
sendEvent('onUpdating');
127+
}
128+
129+
function onUpdateReady() {
130+
sendEvent('onUpdateReady');
131+
}
132+
133+
function onUpdateFailed() {
134+
sendEvent('onUpdateFailed');
135+
}
136+
137+
function onUninstalled() {
138+
sendEvent('onUninstalled');
139+
}
140+
141+
function onInstalled() {
142+
sendEvent('onInstalled');
143+
}
144+
145+
function sendEvent(event) {
146+
window.parent.postMessage('__offline-plugin_AppCacheEvent:' + event, '*');
147+
}
148+
</script>

0 commit comments

Comments
 (0)