anypack-plugin-serve 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +373 -0
- package/README.md +319 -0
- package/client.js +34 -0
- package/lib/client/ClientSocket.js +97 -0
- package/lib/client/client.js +114 -0
- package/lib/client/hmr.js +83 -0
- package/lib/client/log.js +25 -0
- package/lib/client/overlays/progress-minimal.js +118 -0
- package/lib/client/overlays/progress.js +170 -0
- package/lib/client/overlays/status.js +408 -0
- package/lib/client/overlays/util.js +46 -0
- package/lib/errors.js +38 -0
- package/lib/helpers.js +16 -0
- package/lib/index.js +286 -0
- package/lib/log.js +55 -0
- package/lib/middleware.js +154 -0
- package/lib/plugins/hmr.js +49 -0
- package/lib/plugins/ramdisk.js +110 -0
- package/lib/plugins/ramdisk_lib.js +146 -0
- package/lib/routes.js +118 -0
- package/lib/server.js +129 -0
- package/lib/validate.js +77 -0
- package/lib/ws.js +41 -0
- package/package.json +94 -0
package/client.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright © 2018 Andrew Powell
|
|
3
|
+
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
|
+
|
|
8
|
+
The above copyright notice and this permission notice shall be
|
|
9
|
+
included in all copies or substantial portions of this Source Code Form.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @note This file exists merely as an easy reference for folks adding it to their configuration entries
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
(() => {
|
|
17
|
+
const { run } = require('./lib/client/client');
|
|
18
|
+
let hash = '<unknown>';
|
|
19
|
+
let options;
|
|
20
|
+
try {
|
|
21
|
+
options = ʎɐɹɔosǝʌɹǝs;
|
|
22
|
+
} catch (e) {
|
|
23
|
+
const { log } = require('./lib/client/log');
|
|
24
|
+
log.error(
|
|
25
|
+
'The entry for webpack-plugin-serve was included in your build, but it does not appear that the plugin was. Please check your configuration.'
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
hash = __webpack_hash__;
|
|
31
|
+
} catch (e) {}
|
|
32
|
+
|
|
33
|
+
run(hash, options);
|
|
34
|
+
})();
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright © 2018 Andrew Powell
|
|
3
|
+
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
|
+
|
|
8
|
+
The above copyright notice and this permission notice shall be
|
|
9
|
+
included in all copies or substantial portions of this Source Code Form.
|
|
10
|
+
*/
|
|
11
|
+
const { error, refresh, warn } = require('./log')();
|
|
12
|
+
|
|
13
|
+
// ignore 1008 (HTTP 400 equivalent) and 1011 (HTTP 500 equivalent)
|
|
14
|
+
const ignoreCodes = [1008, 1011];
|
|
15
|
+
const maxAttempts = 10;
|
|
16
|
+
|
|
17
|
+
class ClientSocket {
|
|
18
|
+
constructor(options, ...args) {
|
|
19
|
+
this.args = args;
|
|
20
|
+
this.attempts = 0;
|
|
21
|
+
this.eventHandlers = [];
|
|
22
|
+
this.options = options;
|
|
23
|
+
this.retrying = false;
|
|
24
|
+
|
|
25
|
+
this.connect();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
addEventListener(...args) {
|
|
29
|
+
this.eventHandlers.push(args);
|
|
30
|
+
this.socket.addEventListener(...args);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
close() {
|
|
34
|
+
this.socket.close();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
connect() {
|
|
38
|
+
if (this.socket) {
|
|
39
|
+
delete this.socket;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.connecting = true;
|
|
43
|
+
|
|
44
|
+
this.socket = new WebSocket(...this.args);
|
|
45
|
+
|
|
46
|
+
if (this.options.retry) {
|
|
47
|
+
this.socket.addEventListener('close', (event) => {
|
|
48
|
+
if (ignoreCodes.includes(event.code)) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!this.retrying) {
|
|
53
|
+
warn(`The WebSocket was closed and will attempt to reconnect`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.reconnect();
|
|
57
|
+
});
|
|
58
|
+
} else {
|
|
59
|
+
this.socket.onclose = () =>
|
|
60
|
+
warn(`The client WebSocket was closed. ${refresh}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this.socket.addEventListener('open', () => {
|
|
64
|
+
this.attempts = 0;
|
|
65
|
+
this.retrying = false;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (this.eventHandlers.length) {
|
|
69
|
+
for (const [name, fn] of this.eventHandlers) {
|
|
70
|
+
this.socket.addEventListener(name, fn);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
reconnect() {
|
|
76
|
+
this.attempts += 1;
|
|
77
|
+
this.retrying = true;
|
|
78
|
+
|
|
79
|
+
if (this.attempts > maxAttempts) {
|
|
80
|
+
error(`The WebSocket could not be reconnected. ${refresh}`);
|
|
81
|
+
this.retrying = false;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const timeout = 1000 * this.attempts ** 2;
|
|
86
|
+
|
|
87
|
+
setTimeout(() => this.connect(this.args), timeout);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
removeEventListener(...args) {
|
|
91
|
+
const [, handler] = args;
|
|
92
|
+
this.eventHandlers = this.eventHandlers.filter(([, fn]) => fn === handler);
|
|
93
|
+
this.socket.removeEventListener(...args);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = { ClientSocket };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright © 2018 Andrew Powell
|
|
3
|
+
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
|
+
|
|
8
|
+
The above copyright notice and this permission notice shall be
|
|
9
|
+
included in all copies or substantial portions of this Source Code Form.
|
|
10
|
+
*/
|
|
11
|
+
const run = (buildHash, options) => {
|
|
12
|
+
const { address, client = {}, hmr, progress, secure, status } = options;
|
|
13
|
+
|
|
14
|
+
options.firstInstance = !window.webpackPluginServe;
|
|
15
|
+
|
|
16
|
+
window.webpackPluginServe = window.webpackPluginServe || {
|
|
17
|
+
compilers: {},
|
|
18
|
+
};
|
|
19
|
+
window.webpackPluginServe.silent = !!client.silent;
|
|
20
|
+
|
|
21
|
+
const { ClientSocket } = require('./ClientSocket');
|
|
22
|
+
const { replace } = require('./hmr');
|
|
23
|
+
const { error, info, warn } = require('./log')();
|
|
24
|
+
|
|
25
|
+
const protocol = secure ? 'wss' : 'ws';
|
|
26
|
+
const socket = new ClientSocket(
|
|
27
|
+
client,
|
|
28
|
+
`${client.protocol || protocol}://${client.address || address}/wps`,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const { compilerName } = options;
|
|
32
|
+
|
|
33
|
+
window.webpackPluginServe.compilers[compilerName] = {};
|
|
34
|
+
|
|
35
|
+
// prevents ECONNRESET errors on the server
|
|
36
|
+
window.addEventListener('beforeunload', () => socket.close());
|
|
37
|
+
|
|
38
|
+
socket.addEventListener('message', (message) => {
|
|
39
|
+
const { action, data = {} } = JSON.parse(message.data);
|
|
40
|
+
const { errors, hash = '<?>', warnings } = data || {};
|
|
41
|
+
const shortHash = hash.slice(0, 7);
|
|
42
|
+
const identifier = options.compilerName
|
|
43
|
+
? `(Compiler: ${options.compilerName}) `
|
|
44
|
+
: '';
|
|
45
|
+
const compiler = window.webpackPluginServe.compilers[compilerName];
|
|
46
|
+
const { wpsId } = data;
|
|
47
|
+
|
|
48
|
+
switch (action) {
|
|
49
|
+
case 'build':
|
|
50
|
+
compiler.done = false;
|
|
51
|
+
break;
|
|
52
|
+
case 'connected':
|
|
53
|
+
info(`WebSocket connected ${identifier}`);
|
|
54
|
+
break;
|
|
55
|
+
case 'done':
|
|
56
|
+
compiler.done = true;
|
|
57
|
+
break;
|
|
58
|
+
case 'problems':
|
|
59
|
+
if (data.errors.length) {
|
|
60
|
+
error(`${identifier}Build ${shortHash} produced errors:\n`, errors);
|
|
61
|
+
}
|
|
62
|
+
if (data.warnings.length) {
|
|
63
|
+
warn(
|
|
64
|
+
`${identifier}Build ${shortHash} produced warnings:\n`,
|
|
65
|
+
warnings,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
break;
|
|
69
|
+
case 'reload':
|
|
70
|
+
window.location.reload();
|
|
71
|
+
break;
|
|
72
|
+
case 'replace':
|
|
73
|
+
// actions with a wpsId in tow indicate actions that should only be executed when the wpsId sent
|
|
74
|
+
// matches the wpsId set in options. this is how we can identify multiple compilers in the
|
|
75
|
+
// client.
|
|
76
|
+
if (wpsId && wpsId === options.wpsId) {
|
|
77
|
+
replace(buildHash, hash, hmr === 'refresh-on-failure');
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
default:
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
if (options.firstInstance) {
|
|
85
|
+
if (progress === 'minimal') {
|
|
86
|
+
const { init } = require('./overlays/progress-minimal');
|
|
87
|
+
init(options, socket);
|
|
88
|
+
} else if (progress) {
|
|
89
|
+
const { init } = require('./overlays/progress');
|
|
90
|
+
init(options, socket);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (status) {
|
|
94
|
+
const { init } = require('./overlays/status');
|
|
95
|
+
init(options, socket);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (module.hot) {
|
|
99
|
+
info('Hot Module Replacement is active');
|
|
100
|
+
|
|
101
|
+
if (options.liveReload) {
|
|
102
|
+
info('Live Reload taking precedence over Hot Module Replacement');
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
warn('Hot Module Replacement is inactive');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!module.hot && options.liveReload) {
|
|
109
|
+
info('Live Reload is active');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
module.exports = { run };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright © 2018 Andrew Powell
|
|
3
|
+
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
|
+
|
|
8
|
+
The above copyright notice and this permission notice shall be
|
|
9
|
+
included in all copies or substantial portions of this Source Code Form.
|
|
10
|
+
*/
|
|
11
|
+
const { error, info, refresh, warn } = require('./log')();
|
|
12
|
+
|
|
13
|
+
let latest = true;
|
|
14
|
+
|
|
15
|
+
const hmr = (onFailure) => {
|
|
16
|
+
return {
|
|
17
|
+
onUnaccepted(data) {
|
|
18
|
+
onFailure();
|
|
19
|
+
warn('Change in unaccepted module(s):\n', data);
|
|
20
|
+
warn(data);
|
|
21
|
+
},
|
|
22
|
+
onDeclined(data) {
|
|
23
|
+
onFailure();
|
|
24
|
+
warn('Change in declined module(s):\n', data);
|
|
25
|
+
},
|
|
26
|
+
onErrored(data) {
|
|
27
|
+
onFailure();
|
|
28
|
+
error('Error in module(s):\n', data);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const replace = async (buildHash, hash, refreshOnFailure) => {
|
|
34
|
+
const { apply, check, status } = module.hot;
|
|
35
|
+
|
|
36
|
+
if (hash) {
|
|
37
|
+
latest = hash.includes(buildHash);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!latest) {
|
|
41
|
+
const hmrStatus = status();
|
|
42
|
+
|
|
43
|
+
if (hmrStatus === 'abort' || hmrStatus === 'fail') {
|
|
44
|
+
warn(`An HMR update was triggered, but ${hmrStatus}ed. ${refresh}`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let modules;
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
modules = await check(false);
|
|
52
|
+
} catch (_e) {
|
|
53
|
+
// noop. this typically happens when a MultiCompiler has more than one compiler that includes
|
|
54
|
+
// this script, and an update happens with a hash that isn't part of the compiler/module this
|
|
55
|
+
// instance was loaded for.
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!modules) {
|
|
60
|
+
warn(`No modules found for replacement. ${refresh}`);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
modules = await apply(
|
|
65
|
+
hmr(
|
|
66
|
+
refreshOnFailure
|
|
67
|
+
? () => {
|
|
68
|
+
if (refreshOnFailure) {
|
|
69
|
+
location.reload();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
: () => {},
|
|
73
|
+
),
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
if (modules) {
|
|
77
|
+
latest = true;
|
|
78
|
+
info(`Build ${hash.slice(0, 7)} replaced:\n`, modules);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
module.exports = { replace };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright © 2018 Andrew Powell
|
|
3
|
+
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
|
+
|
|
8
|
+
The above copyright notice and this permission notice shall be
|
|
9
|
+
included in all copies or substantial portions of this Source Code Form.
|
|
10
|
+
*/
|
|
11
|
+
const { error, info, warn } = console;
|
|
12
|
+
const log = {
|
|
13
|
+
error: error.bind(console, '⬡ wps:'),
|
|
14
|
+
info: info.bind(console, '⬡ wps:'),
|
|
15
|
+
refresh: 'Please refresh the page',
|
|
16
|
+
warn: warn.bind(console, '⬡ wps:'),
|
|
17
|
+
};
|
|
18
|
+
const noop = () => {};
|
|
19
|
+
const silent = {
|
|
20
|
+
error: noop,
|
|
21
|
+
info: noop,
|
|
22
|
+
warn: noop,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
module.exports = () => (window.webpackPluginServe.silent ? silent : log);
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright © 2018 Andrew Powell, Matheus Gonçalves da Silva
|
|
3
|
+
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
|
+
|
|
8
|
+
The above copyright notice and this permission notice shall be
|
|
9
|
+
included in all copies or substantial portions of this Source Code Form.
|
|
10
|
+
*/
|
|
11
|
+
const { addCss, addHtml } = require('./util');
|
|
12
|
+
|
|
13
|
+
const ns = 'wps-progress-minimal';
|
|
14
|
+
const html = `
|
|
15
|
+
<div id="${ns}" class="${ns}-hidden">
|
|
16
|
+
<div id="${ns}-bar"></div>
|
|
17
|
+
</div>
|
|
18
|
+
`;
|
|
19
|
+
const css = `
|
|
20
|
+
#${ns} {
|
|
21
|
+
position: fixed;
|
|
22
|
+
top: 0;
|
|
23
|
+
left: 0;
|
|
24
|
+
height: 4px;
|
|
25
|
+
width: 100vw;
|
|
26
|
+
z-index: 2147483645;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#${ns}-bar {
|
|
30
|
+
width: 0%;
|
|
31
|
+
height: 4px;
|
|
32
|
+
background-color: rgb(186, 223, 172);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@keyframes ${ns}-fade {
|
|
36
|
+
0% {
|
|
37
|
+
opacity: 1;
|
|
38
|
+
}
|
|
39
|
+
100% {
|
|
40
|
+
opacity: 0;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.${ns}-disappear {
|
|
45
|
+
animation: ${ns}-fade .3s;
|
|
46
|
+
animation-fill-mode: forwards;
|
|
47
|
+
animation-delay: .5s;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.${ns}-hidden {
|
|
51
|
+
display: none;
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
let hideOnPageVisible = false;
|
|
56
|
+
|
|
57
|
+
const update = (percent) => {
|
|
58
|
+
const bar = document.querySelector(`#${ns}-bar`);
|
|
59
|
+
bar.style.width = `${percent}%`;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const reset = (wrapper) => {
|
|
63
|
+
wrapper.classList.add(`${ns}-disappear`);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const init = (options, socket) => {
|
|
67
|
+
if (options.firstInstance) {
|
|
68
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
69
|
+
addCss(css);
|
|
70
|
+
addHtml(html);
|
|
71
|
+
|
|
72
|
+
const wrapper = document.querySelector(`#${ns}`);
|
|
73
|
+
wrapper.addEventListener('animationend', () => {
|
|
74
|
+
update(0);
|
|
75
|
+
wrapper.classList.add(`${ns}-hidden`);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
document.addEventListener('visibilitychange', () => {
|
|
80
|
+
if (!document.hidden && hideOnPageVisible) {
|
|
81
|
+
const wrapper = document.querySelector(`#${ns}`);
|
|
82
|
+
reset(wrapper);
|
|
83
|
+
hideOnPageVisible = false;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
socket.addEventListener('message', (message) => {
|
|
89
|
+
const { action, data } = JSON.parse(message.data);
|
|
90
|
+
|
|
91
|
+
if (action !== 'progress') {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const percent = Math.floor(data.percent * 100);
|
|
96
|
+
const wrapper = document.querySelector(`#${ns}`);
|
|
97
|
+
|
|
98
|
+
if (wrapper) {
|
|
99
|
+
wrapper.classList.remove(`${ns}-hidden`, `${ns}-disappear`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (data.percent === 1) {
|
|
103
|
+
if (document.hidden) {
|
|
104
|
+
hideOnPageVisible = true;
|
|
105
|
+
} else {
|
|
106
|
+
reset(wrapper);
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
hideOnPageVisible = false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
update(percent);
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
module.exports = {
|
|
117
|
+
init,
|
|
118
|
+
};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright © 2018 Andrew Powell, Matheus Gonçalves da Silva
|
|
3
|
+
|
|
4
|
+
This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
7
|
+
|
|
8
|
+
The above copyright notice and this permission notice shall be
|
|
9
|
+
included in all copies or substantial portions of this Source Code Form.
|
|
10
|
+
*/
|
|
11
|
+
const { addCss, addHtml } = require('./util');
|
|
12
|
+
|
|
13
|
+
const ns = 'wps-progress';
|
|
14
|
+
const css = `
|
|
15
|
+
#${ns}{
|
|
16
|
+
width: 200px;
|
|
17
|
+
height: 200px;
|
|
18
|
+
position: fixed;
|
|
19
|
+
right: 5%;
|
|
20
|
+
top: 5%;
|
|
21
|
+
transition: opacity .25s ease-in-out;
|
|
22
|
+
z-index: 2147483645;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#${ns}-bg {
|
|
26
|
+
fill: #282d35;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#${ns}-fill {
|
|
30
|
+
fill: rgba(0, 0, 0, 0);
|
|
31
|
+
stroke: rgb(186, 223, 172);
|
|
32
|
+
stroke-dasharray: 219.99078369140625;
|
|
33
|
+
stroke-dashoffset: -219.99078369140625;
|
|
34
|
+
stroke-width: 10;
|
|
35
|
+
transform: rotate(90deg)translate(0px, -80px);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#${ns}-percent {
|
|
39
|
+
font-family: 'Open Sans';
|
|
40
|
+
font-size: 18px;
|
|
41
|
+
fill: #ffffff;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#${ns}-percent-value {
|
|
45
|
+
dominant-baseline: middle;
|
|
46
|
+
text-anchor: middle;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#${ns}-percent-super {
|
|
50
|
+
fill: #bdc3c7;
|
|
51
|
+
font-size: .45em;
|
|
52
|
+
baseline-shift: 10%;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.${ns}-noselect {
|
|
56
|
+
-webkit-touch-callout: none;
|
|
57
|
+
-webkit-user-select: none;
|
|
58
|
+
-khtml-user-select: none;
|
|
59
|
+
-moz-user-select: none;
|
|
60
|
+
-ms-user-select: none;
|
|
61
|
+
user-select: none;
|
|
62
|
+
cursor: default;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@keyframes ${ns}-fade {
|
|
66
|
+
0% {
|
|
67
|
+
opacity: 1;
|
|
68
|
+
transform: scale(1);
|
|
69
|
+
-webkit-transform: scale(1);
|
|
70
|
+
}
|
|
71
|
+
100% {
|
|
72
|
+
opacity: 0;
|
|
73
|
+
transform: scale(0);
|
|
74
|
+
-webkit-transform: scale(0);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.${ns}-disappear {
|
|
79
|
+
animation: ${ns}-fade .3s;
|
|
80
|
+
animation-fill-mode:forwards;
|
|
81
|
+
animation-delay: .5s;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.${ns}-hidden {
|
|
85
|
+
display: none;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Put google web font at the end, or you'll see FOUC in Firefox */
|
|
89
|
+
@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,700');
|
|
90
|
+
`;
|
|
91
|
+
|
|
92
|
+
const html = `
|
|
93
|
+
<svg id="${ns}" class="${ns}-noselect ${ns}-hidden" x="0px" y="0px" viewBox="0 0 80 80">
|
|
94
|
+
<circle id="${ns}-bg" cx="50%" cy="50%" r="35"></circle>
|
|
95
|
+
<path id="${ns}-fill" d="M5,40a35,35 0 1,0 70,0a35,35 0 1,0 -70,0" />
|
|
96
|
+
<text id="${ns}-percent" x="50%" y="51%"><tspan id="${ns}-percent-value">0</tspan><tspan id="${ns}-percent-super">%</tspan></text>
|
|
97
|
+
</svg>
|
|
98
|
+
`;
|
|
99
|
+
|
|
100
|
+
let hideOnPageVisible = false;
|
|
101
|
+
|
|
102
|
+
const update = (percent) => {
|
|
103
|
+
const max = -219.99078369140625;
|
|
104
|
+
const value = document.querySelector(`#${ns}-percent-value`);
|
|
105
|
+
const track = document.querySelector(`#${ns}-fill`);
|
|
106
|
+
const offset = ((100 - percent) / 100) * max;
|
|
107
|
+
|
|
108
|
+
track.setAttribute('style', `stroke-dashoffset: ${offset}`);
|
|
109
|
+
value.innerHTML = percent.toString();
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const reset = (svg) => {
|
|
113
|
+
svg.classList.add(`${ns}-disappear`);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const init = (options, socket) => {
|
|
117
|
+
if (options.firstInstance) {
|
|
118
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
119
|
+
addCss(css);
|
|
120
|
+
addHtml(html);
|
|
121
|
+
|
|
122
|
+
// Reset progress to zero after disappear animation
|
|
123
|
+
const svg = document.querySelector(`#${ns}`);
|
|
124
|
+
svg.addEventListener('animationend', () => {
|
|
125
|
+
update(0);
|
|
126
|
+
svg.classList.add(`${ns}-hidden`);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
document.addEventListener('visibilitychange', () => {
|
|
131
|
+
if (!document.hidden && hideOnPageVisible) {
|
|
132
|
+
const svg = document.querySelector(`#${ns}`);
|
|
133
|
+
reset(svg);
|
|
134
|
+
hideOnPageVisible = false;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
socket.addEventListener('message', (message) => {
|
|
140
|
+
const { action, data } = JSON.parse(message.data);
|
|
141
|
+
|
|
142
|
+
if (action !== 'progress') {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const percent = Math.floor(data.percent * 100);
|
|
147
|
+
const svg = document.querySelector(`#${ns}`);
|
|
148
|
+
|
|
149
|
+
if (!svg) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// we can safely call this even if it doesn't have the class
|
|
154
|
+
svg.classList.remove(`${ns}-disappear`, `${ns}-hidden`);
|
|
155
|
+
|
|
156
|
+
if (data.percent === 1) {
|
|
157
|
+
if (document.hidden) {
|
|
158
|
+
hideOnPageVisible = true;
|
|
159
|
+
} else {
|
|
160
|
+
reset(svg);
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
hideOnPageVisible = false;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
update(percent);
|
|
167
|
+
});
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
module.exports = { init };
|