1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | import etpl from 'etpl';
|
7 | import fs from 'fs';
|
8 | import path from 'path';
|
9 | import babel from 'babel-core';
|
10 |
|
11 |
|
12 | const cwd = process.cwd();
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | function 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 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 | function 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 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | function 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 |
|
83 | SwRegisterPlugin.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 |
|
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 |
|
152 | export default SwRegisterPlugin;
|
153 |
|