UNPKG

9.67 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', {
4 value: true
5});
6
7var _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; }; })();
8
9function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
10
11function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
12
13var _webpackLibSingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
14
15var _webpackLibSingleEntryPlugin2 = _interopRequireDefault(_webpackLibSingleEntryPlugin);
16
17var _miscGetUglifyPlugin = require('./misc/get-uglify-plugin');
18
19var _miscGetUglifyPlugin2 = _interopRequireDefault(_miscGetUglifyPlugin);
20
21var _path = require('path');
22
23var _path2 = _interopRequireDefault(_path);
24
25var _deepExtend = require('deep-extend');
26
27var _deepExtend2 = _interopRequireDefault(_deepExtend);
28
29var _miscUtils = require('./misc/utils');
30
31var ServiceWorker = (function () {
32 function ServiceWorker(options) {
33 _classCallCheck(this, ServiceWorker);
34
35 if ((0, _miscUtils.isAbsolutePath)(options.output)) {
36 throw new Error('OfflinePlugin: ServiceWorker.output option must be a relative path, ' + 'but an absolute path was passed');
37 }
38
39 this.minify = options.minify;
40 this.output = options.output.replace(/^\.\/+/, '');
41 this.publicPath = options.publicPath;
42
43 this.basePath = null;
44 this.location = null;
45 this.pathRewrite = null;
46
47 // Tool specific properties
48 this.entry = options.entry;
49 this.scope = options.scope ? options.scope + '' : void 0;
50 this.events = !!options.events;
51 this.prefetchRequest = this.validatePrefetch(options.prefetchRequest);
52 this.updateViaCache = (options.updateViaCache || '') + '';
53 this.navigationPreload = options.navigationPreload;
54 this.forceInstall = !!options.forceInstall;
55
56 var cacheNameQualifier = '';
57
58 if (options.cacheName) {
59 cacheNameQualifier = ':' + options.cacheName;
60 }
61
62 this.ENTRY_NAME = 'serviceworker';
63 this.CACHE_NAME = 'webpack-offline' + cacheNameQualifier;
64 this.SW_DATA_VAR = '__wpo';
65 }
66
67 _createClass(ServiceWorker, [{
68 key: 'addEntry',
69 value: function addEntry(plugin, compilation, compiler) {
70 if (!this.entry) return Promise.resolve();
71
72 var name = plugin.entryPrefix + this.ENTRY_NAME;
73 var childCompiler = compilation.createChildCompiler(name, {
74 // filename: this.output
75 filename: name
76 });
77
78 var data = JSON.stringify({
79 data_var_name: this.SW_DATA_VAR,
80 cacheMaps: plugin.cacheMaps,
81 navigationPreload: this.stringifyNavigationPreload(this.navigationPreload, plugin)
82 });
83
84 var swLoaderPath = _path2['default'].join(__dirname, 'misc/sw-loader.js');
85 var loader = '!!' + swLoaderPath + '?json=' + escape(data);
86 var entry = loader + '!' + this.entry;
87
88 childCompiler.context = compiler.context;
89 new _webpackLibSingleEntryPlugin2['default'](compiler.context, entry, name).apply(childCompiler);
90
91 if (this.minify === true) {
92 if (!_miscGetUglifyPlugin2['default']) {
93 throw new Error('OfflinePlugin: uglifyjs-webpack-plugin is required to preform minification');
94 }
95
96 var options = {
97 test: new RegExp(name),
98 uglifyOptions: {
99 compress: {
100 warnings: false,
101 dead_code: true,
102 drop_console: true,
103 unused: true
104 },
105
106 output: {
107 comments: false
108 }
109 }
110 };
111
112 new _miscGetUglifyPlugin2['default'](options).apply(childCompiler);
113 } else if (this.minify !== false && _miscGetUglifyPlugin2['default']) {
114 // Do not perform auto-minification if UglifyJsPlugin isn't installed
115
116 (compiler.options.plugins || []).some(function (plugin) {
117 if (plugin instanceof _miscGetUglifyPlugin2['default']) {
118 var options = (0, _deepExtend2['default'])({}, plugin.options);
119
120 options.test = new RegExp(name);
121 new _miscGetUglifyPlugin2['default'](options).apply(childCompiler);
122
123 return true;
124 }
125 });
126 }
127
128 // Needed for HMR. offline-plugin doesn't support it,
129 // but added just in case to prevent other errors
130 var compilationFn = function compilationFn(compilation) {
131 if (compilation.cache) {
132 if (!compilation.cache[name]) {
133 compilation.cache[name] = {};
134 }
135
136 compilation.cache = compilation.cache[name];
137 }
138 };
139
140 if (childCompiler.hooks) {
141 var _plugin = { name: 'OfflinePlugin' };
142 childCompiler.hooks.compilation.tap(_plugin, compilationFn);
143 } else {
144 childCompiler.plugin('compilation', compilationFn);
145 }
146
147 return new Promise(function (resolve, reject) {
148 childCompiler.runAsChild(function (err, entries, childCompilation) {
149 if (err) {
150 reject(err);
151 return;
152 }
153
154 resolve();
155 });
156 });
157 }
158 }, {
159 key: 'apply',
160 value: function apply(plugin, compilation, compiler) {
161 var minify = undefined;
162
163 if (typeof this.minify === 'boolean') {
164 minify = this.minify;
165 } else {
166 minify = !!_miscGetUglifyPlugin2['default'] && !!(compiler.options.plugins || []).some(function (plugin) {
167 return plugin instanceof _miscGetUglifyPlugin2['default'];
168 });
169 }
170
171 var source = this.getDataTemplate(plugin.caches, plugin, minify);
172
173 if (this.entry) {
174 var _name = plugin.entryPrefix + this.ENTRY_NAME;
175 var asset = compilation.assets[_name];
176
177 if (!asset) {
178 compilation.errors.push(new Error('OfflinePlugin: ServiceWorker entry is not found in output assets'));
179
180 return;
181 }
182
183 delete compilation.assets[_name];
184
185 if (!plugin.__tests.swMetadataOnly) {
186 source += '\n\n' + asset.source();
187 }
188 }
189
190 compilation.assets[this.output] = (0, _miscUtils.getSource)(source);
191 }
192 }, {
193 key: 'getDataTemplate',
194 value: function getDataTemplate(data, plugin, minify) {
195 var rewriteFunction = this.pathRewrite;
196
197 var cache = function cache(key) {
198 return (data[key] || []).map(rewriteFunction);
199 };
200
201 var hashesMap = Object.keys(plugin.hashesMap).reduce(function (result, hash) {
202 var asset = plugin.hashesMap[hash];
203
204 result[hash] = rewriteFunction(asset);
205 return result;
206 }, {});
207
208 var externals = plugin.externals.map(rewriteFunction);
209
210 var pluginVersion = undefined;
211
212 if (plugin.pluginVersion && !plugin.__tests.noVersionDump) {
213 pluginVersion = plugin.pluginVersion;
214 }
215
216 return ('\n var ' + this.SW_DATA_VAR + ' = ' + JSON.stringify({
217 assets: {
218 main: cache('main'),
219 additional: cache('additional'),
220 optional: cache('optional')
221 },
222
223 externals: externals,
224
225 hashesMap: hashesMap,
226
227 strategy: plugin.strategy,
228 responseStrategy: plugin.responseStrategy,
229 version: plugin.version,
230 name: this.CACHE_NAME,
231 pluginVersion: pluginVersion,
232 relativePaths: plugin.relativePaths,
233
234 prefetchRequest: this.prefetchRequest,
235
236 // These aren't added
237 alwaysRevalidate: plugin.alwaysRevalidate,
238 preferOnline: plugin.preferOnline,
239 ignoreSearch: plugin.ignoreSearch
240 }, null, minify ? void 0 : ' ') + ';\n ').trim();
241 }
242 }, {
243 key: 'getConfig',
244 value: function getConfig(plugin) {
245 return {
246 location: this.location,
247 scope: this.scope,
248 updateViaCache: this.updateViaCache,
249 events: this.events,
250 force: this.forceInstall
251 };
252 }
253 }, {
254 key: 'validatePrefetch',
255 value: function validatePrefetch(request) {
256 if (!request) {
257 return void 0;
258 }
259
260 if (request.credentials === 'same-origin' && request.headers === void 0 && request.mode === 'cors' && request.cache === void 0) {
261 return void 0;
262 }
263
264 return {
265 credentials: request.credentials,
266 headers: request.headers,
267 mode: request.mode,
268 cache: request.cache
269 };
270 }
271 }, {
272 key: 'stringifyNavigationPreload',
273 value: function stringifyNavigationPreload(navigationPreload, plugin) {
274 var result = undefined;
275
276 if (typeof navigationPreload === 'object') {
277 result = navigationPreload = '{\n map: ' + (0, _miscUtils.functionToString)(navigationPreload.map) + ',\n test: ' + (0, _miscUtils.functionToString)(navigationPreload.test) + '\n }';
278 } else {
279 if (typeof navigationPreload !== 'boolean') {
280 if (plugin.responseStrategy === 'network-first') {
281 navigationPreload = true;
282 } else {
283 navigationPreload = false;
284 }
285 }
286
287 result = JSON.stringify(navigationPreload);
288 }
289
290 return result;
291 }
292 }]);
293
294 return ServiceWorker;
295})();
296
297exports['default'] = ServiceWorker;
298module.exports = exports['default'];
\No newline at end of file