-
Notifications
You must be signed in to change notification settings - Fork 0
/
install-offline.js
136 lines (113 loc) · 3.44 KB
/
install-offline.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
126
127
128
129
130
131
132
133
134
135
136
let fs = require('fs');
let path = require('path');
let url = require('url');
let request = require('request');
let mkdirp = require('mkdirp');
// helper functions
let dir_remote_rel = 'static/remote';
let dir_remote = 'www/static/remote';
let file_queue = [];
let callback_done = null;
let regex_css_include = /(@import\s+?)?url\(["']?(.*?)["']?\)/g;
function push_file(parent_file, file_url, ext, rel) {
file_url = url.parse(file_url);
if (file_url.host === null) {
// relative path? resolve it
file_url = url.parse(url.resolve(parent_file.url.href, file_url.href));
}
let path_parts = (file_url.host + file_url.pathname).split('/');
path_parts = path_parts.map(decodeURIComponent);
let last_path_part = path_parts.pop();
let local_ext = path.extname(last_path_part);
// add query
if (file_url.search) {
last_path_part += file_url.search + local_ext;
}
// fix extension
if (ext && ext !== local_ext) {
last_path_part += ext;
local_ext = path.extname(last_path_part);
}
path_parts.push(last_path_part);
let local = path.join(...path_parts); // filesystem
let local_url = path_parts.map(encodeURIComponent).join('/'); // web
// include hash on local_url? do tests
let local_replace;
if (parent_file) {
local_replace = path.relative(path.dirname(parent_file.local_url), local_url);
} else {
local_replace = path.join(dir_remote_rel, local_url);
}
if (file_url.protocol === 'data:') {
return null;
} else if (file_url.protocol !== 'http:' && file_url.protocol !== 'https:') {
console.log(file_url);
throw new Error('unknown protocol ' + file_url.protocol);
}
let f = {
url: file_url,
local,
local_url,
local_ext,
local_full: path.join(dir_remote, local),
local_replace,
};
file_queue.push(f);
return f;
}
function search_and_replace_css_file(file, text) {
text = text.replace(regex_css_include, (match, p1, p2) => {
let child = push_file(file, p2, (p1 ? '.css' : null), true);
if (child) {
return (p1 || '') + 'url("' + child.local_replace + '")';
}
return match;
});
return text;
}
function download_next_file() {
let f = file_queue.pop();
if (!f) {
// nothing else to do
setTimeout(callback_done);
return;
}
let href = (f.url.hash ? f.url.href.slice(0, -f.url.hash.length) : f.url.href);
console.log('downloading: ' + href);
request({
url: href,
encoding: null,
}, (error, response, body) => {
if (!error && response.statusCode === 200) {
if (f.local_ext === '.css') {
body = search_and_replace_css_file(f, body.toString('utf8'));
}
// save to disk
mkdirp.sync(path.dirname(f.local_full));
fs.writeFileSync(f.local_full, body);
// continue downloading the next file
setTimeout(download_next_file);
} else if (!error) {
throw new Error('response.statusCode === ' + response.statusCode);
} else {
throw error.toString();
}
});
}
// find root files
let regex_jsdelivr = /="(https:\/\/cdn\.jsdelivr\.net\/.*)"/g;
let text = fs.readFileSync('www/index.html', 'utf8');
text = text.replace(regex_jsdelivr, (match, p1) => {
if (p1.endsWith('.js') || p1.endsWith('.css')) {
let file = push_file(null, p1);
return '="' + file.local_replace + '"';
}
return match;
});
fs.writeFileSync('www/index-offline.html', text, 'utf8');
// start downloading
setTimeout(download_next_file);
// done
callback_done = () => {
console.log('DONE');
};