UNPKG

4.16 kBJavaScriptView Raw
1/**
2 * @file serviceWorker register no-cache solution
3 * @author mj(zoumiaojiang@gmail.com)
4 */
5
6import etpl from 'etpl';
7import fs from 'fs';
8import path from 'path';
9import babel from 'babel-core';
10
11
12const cwd = process.cwd();
13
14
15/**
16 * 获取时间戳版本号
17 *
18 * @return {string} 版本号
19 */
20function getVersion() {
21 let d = new Date();
22 let p = function (value) {
23 return value < 10 ? ('0' + value) : value;
24 };
25
26 return ''
27 + d.getFullYear()
28 + p(d.getMonth() + 1)
29 + p(d.getDate())
30 + p(d.getHours())
31 + p(d.getMinutes())
32 + p(d.getSeconds());
33}
34
35/**
36 * babel 编译
37 *
38 * @param {string} source 源代码
39 * @return {string} 编译后的代码
40 */
41function babelCompiler(source) {
42 return babel.transform(source, {
43 comments: false,
44 minified: true,
45 plugins: [
46 'transform-runtime',
47 'external-helpers'
48 ],
49 presets: [
50 [
51 'env',
52 {
53 targets: {
54 node: 3
55 },
56 modules: false
57 }
58 ]
59 ]
60 }).code;
61}
62
63/**
64 * sw Register 插件
65 *
66 * @constructor
67 * @param {Object} options 参数
68 */
69function SwRegisterPlugin(options = {}) {
70
71 let filePath = path.resolve(cwd, (options.filePath || './src/sw-register.js'));
72
73 if (!fs.existsSync(filePath)) {
74 filePath = path.resolve(__dirname, '..', 'templates', 'sw-register.js');
75 }
76 this.filePath = filePath;
77 this.fileName = path.basename(filePath);
78 this.version = options.version || getVersion();
79}
80
81
82
83SwRegisterPlugin.prototype.apply = function (compiler) {
84
85 const me = this;
86 const swRegisterEntryFilePath = path.resolve(__dirname, '..', 'templates', 'sw-register-entry.js.tpl');
87 const swRegisterFilePath = me.filePath;
88
89 compiler.plugin('emit', (compilation, callback) => {
90
91 let publicPath = me.publicPath = ((compilation.outputOptions.publicPath || '') + '/').replace(/\/{1,}/g, '/');
92
93 Object.keys(compilation.assets).forEach(asset => {
94
95 if (asset.indexOf('.html') > -1) {
96 let htmlContent = compilation.assets[asset].source();
97 let swRegisterEntryFileTpl = fs.readFileSync(swRegisterEntryFilePath, 'utf-8');
98 let swRegisterEntryFileContent = etpl.compile(swRegisterEntryFileTpl)(me);
99 let con = fs.readFileSync(swRegisterFilePath, 'utf-8');
100 let version = me.version;
101
102 /* eslint-disable max-nested-callbacks */
103 con = babelCompiler(con).replace(/(['"])([^\s\;\,\(\)]+?\.js)\1/g, item => {
104
105 let swJs = RegExp.$2;
106
107 if (swJs[0] !== '/') {
108 throw new Error('Js path in `sw-register.js` must be a absolute path');
109 }
110
111 if (swJs.indexOf(publicPath) < 0) {
112 const ret = item.replace(
113 swJs,
114 (publicPath + '/' + swJs)
115 .replace(/\/{1,}/g, '/')
116 .replace(/\.js/g, ext => `${ext}?v=${version}`)
117 );
118 return ret;
119 }
120
121 return item.replace(/\.js/g, ext => `${ext}?v=${version}`);
122 });
123
124
125 htmlContent = htmlContent.replace(/<\/body>/, swRegisterEntryFileContent + '</body>');
126
127 compilation.assets[asset] = {
128 source() {
129 return htmlContent;
130 },
131 size() {
132 return htmlContent.length;
133 }
134 };
135
136 compilation.assets[me.fileName] = {
137 source() {
138 return con;
139 },
140 size() {
141 return con.length;
142 }
143 };
144 }
145 });
146 callback();
147 });
148
149};
150
151/* eslint-disable */
152export default SwRegisterPlugin;
153