Skip to content

Commit fb26e82

Browse files
committed
feat: support CSS imports - fixes #10
1 parent 4c66bb8 commit fb26e82

File tree

11 files changed

+5505
-4592
lines changed

11 files changed

+5505
-4592
lines changed

client/dist/index.js

Lines changed: 4882 additions & 4302 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/dist/index.min.js

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/dist/index.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/lib/code-sync.js

Lines changed: 16 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,15 @@
1-
"use strict";
2-
var events = require("./events");
3-
var utils = require("./browser.utils");
4-
var emitter = require("./emitter");
5-
var sync = exports;
6-
7-
var options = {
8-
tagNames: {
9-
css: "link",
10-
jpg: "img",
11-
jpeg: "img",
12-
png: "img",
13-
svg: "img",
14-
gif: "img",
15-
js: "script"
16-
},
17-
attrs: {
18-
link: "href",
19-
img: "src",
20-
script: "src"
21-
},
1+
import { Reloader } from "../vendor/Reloader";
2+
import { Timer } from "../vendor/Timer";
3+
4+
const events = require("./events");
5+
const utils = require("./browser.utils");
6+
const emitter = require("./emitter");
7+
const sync = exports;
8+
const nanlogger = require("nanologger");
9+
const log = nanlogger("Browsersync", { colors: { magenta: "#0F2634" } });
10+
const reloader = new Reloader(window, log, Timer);
11+
12+
const options = {
2213
blacklist: [
2314
// never allow .map files through
2415
function(incoming) {
@@ -27,21 +18,15 @@ var options = {
2718
]
2819
};
2920

30-
var hiddenElem;
31-
var OPT_PATH = "codeSync";
32-
33-
var current = function() {
21+
const OPT_PATH = "codeSync";
22+
const current = function() {
3423
return window.location.pathname;
3524
};
3625

3726
/**
3827
* @param {BrowserSync} bs
3928
*/
4029
sync.init = function(bs) {
41-
if (bs.options.tagNames) {
42-
options.tagNames = bs.options.tagNames;
43-
}
44-
4530
if (bs.options.scrollRestoreTechnique === "window.name") {
4631
sync.saveScrollInName(emitter);
4732
} else {
@@ -138,77 +123,6 @@ sync.saveScrollInCookie = function($window, $document) {
138123
emitter.on("browser:hardReload", utils.saveScrollPosition);
139124
};
140125

141-
/**
142-
* @param {string} search
143-
* @param {string} key
144-
* @param {string} suffix
145-
*/
146-
sync.updateSearch = function(search, key, suffix) {
147-
if (search === "") {
148-
return "?" + suffix;
149-
}
150-
151-
return (
152-
"?" +
153-
search
154-
.slice(1)
155-
.split("&")
156-
.map(function(item) {
157-
return item.split("=");
158-
})
159-
.filter(function(tuple) {
160-
return tuple[0] !== key;
161-
})
162-
.map(function(item) {
163-
return [item[0], item[1]].join("=");
164-
})
165-
.concat(suffix)
166-
.join("&")
167-
);
168-
};
169-
170-
/**
171-
* @param elem
172-
* @param attr
173-
* @param options
174-
* @returns {{elem: HTMLElement, timeStamp: number}}
175-
*/
176-
sync.swapFile = function(elem, attr, options) {
177-
var currentValue = elem[attr];
178-
var timeStamp = new Date().getTime();
179-
var key = "rel";
180-
var suffix = key + "=" + timeStamp;
181-
var anchor = utils.getLocation(currentValue);
182-
var search = sync.updateSearch(anchor.search, key, suffix);
183-
184-
if (options.timestamps === false) {
185-
elem[attr] = anchor.href;
186-
} else {
187-
elem[attr] = anchor.href.split("?")[0] + search;
188-
}
189-
190-
var body = document.body;
191-
192-
setTimeout(function() {
193-
if (!hiddenElem) {
194-
hiddenElem = document.createElement("DIV");
195-
body.appendChild(hiddenElem);
196-
} else {
197-
hiddenElem.style.display = "none";
198-
hiddenElem.style.display = "block";
199-
}
200-
}, 200);
201-
202-
return {
203-
elem: elem,
204-
timeStamp: timeStamp
205-
};
206-
};
207-
208-
sync.getFilenameOnly = function(url) {
209-
return /^[^\?]+(?=\?)/.exec(url);
210-
};
211-
212126
/**
213127
* @param {BrowserSync} bs
214128
* @returns {*}
@@ -221,9 +135,8 @@ sync.reload = function(bs) {
221135
if (!bs.canSync({ url: current() }, OPT_PATH)) {
222136
return;
223137
}
224-
var transformedElem;
138+
225139
var options = bs.options;
226-
var emitter = bs.emitter;
227140

228141
if (data.url || !options.injectChanges) {
229142
sync.reloadBrowser(true);
@@ -234,48 +147,11 @@ sync.reload = function(bs) {
234147
return;
235148
}
236149

237-
var domData = sync.getElems(data.ext);
238-
var elems = sync.getMatches(
239-
domData.elems,
240-
data.basename,
241-
domData.attr
242-
);
243-
244-
if (elems.length && options.notify) {
245-
emitter.emit("notify", {
246-
message: "Injected: " + data.basename
247-
});
248-
}
249-
250-
for (var i = 0, n = elems.length; i < n; i += 1) {
251-
transformedElem = sync.swapFile(
252-
elems[i],
253-
domData.attr,
254-
options
255-
);
256-
}
150+
reloader.reload(data.path, { liveCSS: true });
257151
}
258-
259-
return transformedElem;
260152
};
261153
};
262154

263-
/**
264-
* @param fileExtension
265-
* @returns {*}
266-
*/
267-
sync.getTagName = function(fileExtension) {
268-
return options.tagNames[fileExtension];
269-
};
270-
271-
/**
272-
* @param tagName
273-
* @returns {*}
274-
*/
275-
sync.getAttr = function(tagName) {
276-
return options.attrs[tagName];
277-
};
278-
279155
/**
280156
* @param incoming
281157
* @returns {boolean}
@@ -286,43 +162,6 @@ sync.isBlacklisted = function(incoming) {
286162
});
287163
};
288164

289-
/**
290-
* @param elems
291-
* @param url
292-
* @param attr
293-
* @returns {Array}
294-
*/
295-
sync.getMatches = function(elems, url, attr) {
296-
if (url[0] === "*") {
297-
return elems;
298-
}
299-
300-
var matches = [];
301-
var urlMatcher = new RegExp("(^|/)" + url);
302-
303-
for (var i = 0, len = elems.length; i < len; i += 1) {
304-
if (urlMatcher.test(elems[i][attr])) {
305-
matches.push(elems[i]);
306-
}
307-
}
308-
309-
return matches;
310-
};
311-
312-
/**
313-
* @param fileExtension
314-
* @returns {{elems: NodeList, attr: *}}
315-
*/
316-
sync.getElems = function(fileExtension) {
317-
var tagName = sync.getTagName(fileExtension);
318-
var attr = sync.getAttr(tagName);
319-
320-
return {
321-
elems: document.getElementsByTagName(tagName),
322-
attr: attr
323-
};
324-
};
325-
326165
/**
327166
* @param confirm
328167
*/

client/lib/utils.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
export function each(incoming) {
2+
return [].slice.call(incoming || []);
3+
}
4+
5+
export const splitUrl = function(url) {
6+
let hash, index, params;
7+
if ((index = url.indexOf("#")) >= 0) {
8+
hash = url.slice(index);
9+
url = url.slice(0, index);
10+
} else {
11+
hash = "";
12+
}
13+
14+
if ((index = url.indexOf("?")) >= 0) {
15+
params = url.slice(index);
16+
url = url.slice(0, index);
17+
} else {
18+
params = "";
19+
}
20+
21+
return { url, params, hash };
22+
};
23+
24+
export const pathFromUrl = function(url) {
25+
let path;
26+
({ url } = splitUrl(url));
27+
if (url.indexOf("file://") === 0) {
28+
path = url.replace(new RegExp(`^file://(localhost)?`), "");
29+
} else {
30+
// http : // hostname :8080 /
31+
path = url.replace(new RegExp(`^([^:]+:)?//([^:/]+)(:\\d*)?/`), "/");
32+
}
33+
34+
// decodeURI has special handling of stuff like semicolons, so use decodeURIComponent
35+
return decodeURIComponent(path);
36+
};
37+
38+
export const pickBestMatch = function(path, objects, pathFunc): any {
39+
let score;
40+
let bestMatch = { score: 0, object: null };
41+
42+
objects.forEach(object => {
43+
score = numberOfMatchingSegments(path, pathFunc(object));
44+
if (score > bestMatch.score) {
45+
bestMatch = { object, score };
46+
}
47+
});
48+
49+
if (bestMatch.score > 0) {
50+
return bestMatch;
51+
} else {
52+
return null;
53+
}
54+
};
55+
56+
export const numberOfMatchingSegments = function(path1, path2) {
57+
// get rid of leading slashes and normalize to lower case
58+
path1 = path1.replace(/^\/+/, "").toLowerCase();
59+
path2 = path2.replace(/^\/+/, "").toLowerCase();
60+
61+
if (path1 === path2) {
62+
return 10000;
63+
}
64+
65+
const comps1 = path1.split("/").reverse();
66+
const comps2 = path2.split("/").reverse();
67+
const len = Math.min(comps1.length, comps2.length);
68+
69+
let eqCount = 0;
70+
while (eqCount < len && comps1[eqCount] === comps2[eqCount]) {
71+
++eqCount;
72+
}
73+
74+
return eqCount;
75+
};
76+
77+
export const pathsMatch = (path1, path2) =>
78+
numberOfMatchingSegments(path1, path2) > 0;

0 commit comments

Comments
 (0)