forked from shepherdwind/css-hot-loader
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hotModuleReplacement.js
125 lines (104 loc) · 2.88 KB
/
hotModuleReplacement.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
var normalizeUrl = require('normalize-url');
var srcByModuleId = Object.create(null);
var debounce = require('lodash/debounce');
var noDocument = typeof document === 'undefined';
var forEach = Array.prototype.forEach;
var noop = function () {};
var getCurrentScriptUrl = function(moduleId) {
var src = srcByModuleId[moduleId];
if (!src) {
if (document.currentScript) {
src = document.currentScript.src;
} else {
var scripts = document.getElementsByTagName('script');
var lastScriptTag = scripts[scripts.length - 1];
if (lastScriptTag) {
src = lastScriptTag.src;
}
}
srcByModuleId[moduleId] = src;
}
return function(fileMap) {
var splitResult = /([^\\/]+)\.js$/.exec(src);
var filename = splitResult && splitResult[1];
if (!filename) {
return [src.replace('.js', '.css')];
}
return fileMap.split(',').map(function(mapRule) {
var reg = new RegExp(filename + '\\.js$', 'g')
return normalizeUrl(src.replace(reg, mapRule.replace(/{fileName}/g, filename) + '.css'), { stripWWW: false });
});
};
};
function updateCss(el, url) {
if (!url) {
url = el.href.split('?')[0];
}
if (el.isLoaded === false) {
// We seem to be about to replace a css link that hasn't loaded yet.
// We're probably changing the same file more than once.
return;
}
if (!url || !(url.indexOf('.css') > -1)) return;
el.visited = true;
var newEl = el.cloneNode();
newEl.isLoaded = false;
newEl.addEventListener('load', function () {
newEl.isLoaded = true;
el.remove();
});
newEl.addEventListener('error', function () {
newEl.isLoaded = true;
el.remove();
});
newEl.href = url + '?' + Date.now();
el.parentNode.appendChild(newEl);
}
function reloadStyle(src) {
var elements = document.querySelectorAll('link');
var loaded = false;
forEach.call(elements, function(el) {
if (el.visited === true) return;
var url = getReloadUrl(el.href, src);
if (url) {
updateCss(el, url);
loaded = true;
}
});
return loaded;
}
function getReloadUrl(href, src) {
href = normalizeUrl(href, { stripWWW: false });
var ret;
src.some(function(url) {
if (href.indexOf(src) > -1) {
ret = url;
}
});
return ret;
}
function reloadAll() {
var elements = document.querySelectorAll('link');
forEach.call(elements, function(el) {
if (el.visited === true) return;
updateCss(el);
});
}
module.exports = function(moduleId, options) {
var getScriptSrc;
if (noDocument) {
return noop;
}
getScriptSrc = getCurrentScriptUrl(moduleId);
function update() {
var src = getScriptSrc(options.fileMap);
var reloaded = reloadStyle(src);
if (reloaded && !options.reloadAll) {
console.log('[HMR] css reload %s', src.join(' '));
} else {
console.log('[HMR] Reload all css');
reloadAll();
}
}
return debounce(update, 10);
};