-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathindex.js
More file actions
146 lines (129 loc) · 4.26 KB
/
index.js
File metadata and controls
146 lines (129 loc) · 4.26 KB
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
137
138
139
140
141
142
143
144
145
146
const loaderMap = window['inline-module-loaders'];
const currentScript = document.currentScript || document.querySelector('script');
// https://github.com/WICG/import-maps
const map = {imports: {}, scopes: {}};
const installed = new Set();
function toBase64(str) {
return btoa(unescape(encodeURIComponent(str)));
}
function loadContent(url) {
const request = new XMLHttpRequest();
request.open('GET', url, false); // `false` makes the request synchronous
request.send(null);
if(request.status === 200) {
return request.responseText;
}
throw new Error(request.statusText);
}
// replace code
function replaceImport(code, map) {
const importExp = /^(\s*import\s+[\s\S]*?from\s*['"`])([\s\S]*?)(['"`])/img;
return code.replace(importExp, (a, b, c, d) => {
const url = map[c];
if(url) {
return `${b}${url}${d}`;
}
return `${b}${c}${d}`;
});
}
function getBlobURL(module, replaceImportURL = false, map = {}) {
let jsCode = module.textContent;
if(module.hasAttribute('src')) {
const url = module.getAttribute('src');
jsCode = loadContent(url);
module.textContent = jsCode;
}
if(replaceImportURL) {
jsCode = replaceImport(jsCode, map);
}
let loaders = module.getAttribute('loader');
if(loaders) {
loaders = loaders.split(/\s*>\s*/);
jsCode = loaders.reduce((code, loader) => {
const {transform, imports} = loaderMap[loader];
const {code: resolved, map: sourceMap} = transform(code, {sourceMap: true, filename: module.getAttribute('name') || module.id || 'anonymous'});
if(sourceMap) code = `${resolved}\n\n//# sourceMappingURL=data:application/json;base64,${toBase64(JSON.stringify(sourceMap))}`;
else code = resolved;
Object.assign(map.imports, imports);
return code;
}, jsCode);
}
return createBlob(jsCode, 'text/javascript');
}
function createBlob(code, type = 'text/plain') {
const blob = new Blob([code], {type});
const blobURL = URL.createObjectURL(blob);
return blobURL;
}
function setup() {
const modules = document.querySelectorAll('script[type="inline-module"]');
const importMap = {};
const loadModules = [];
const importMapEl = document.querySelector('script[type="importmap"]');
if(importMapEl) {
console.warn('Cannot update importmap after <script type="importmap"> is set. Please use <script type="inline-module-importmap"> instead.');
}
[...modules].forEach((module) => {
const {id} = module;
const name = module.getAttribute('name');
const url = getBlobURL(module, !!importMapEl, importMap);
if(id) {
importMap[`#${id}`] = url;
importMap[`//#${id}`] = url; // for some platform only support protocals
}
if(name) {
importMap[name] = url;
importMap[`//${name}`] = url; // for some platform only support protocals
}
loadModules.push(url);
});
const externalMapEl = document.querySelector('script[type="inline-module-importmap"]');
if(externalMapEl) {
const externalMap = JSON.parse(externalMapEl.textContent);
Object.assign(map.imports, externalMap.imports);
Object.assign(map.scopes, externalMap.scopes);
}
Object.assign(map.imports, importMap);
if(!importMapEl) {
const mapEl = document.createElement('script');
mapEl.setAttribute('type', 'importmap');
mapEl.textContent = JSON.stringify(map);
currentScript.after(mapEl);
}
loadModules.forEach((url) => {
if(!installed.has(url)) { // mount
const el = document.createElement('script');
el.async = false;
el.setAttribute('type', 'module');
el.setAttribute('src', url);
currentScript.after(el);
installed.add(url);
}
});
}
if(currentScript.getAttribute('setup') !== 'false') {
setup();
}
window.inlineImport = async (moduleID) => {
const {imports} = map;
let blobURL = null;
if(moduleID in imports) blobURL = imports[moduleID];
else {
let module;
if(/^#/.test(moduleID)) {
module = document.querySelector(`script[type="inline-module"]${moduleID}`);
}
if(!module) {
module = document.querySelector(`script[type="inline-module"][name="${moduleID}"]`);
}
if(module) {
blobURL = getBlobURL(module);
imports[moduleID] = blobURL;
}
}
if(blobURL) {
const result = await import(blobURL);
return result;
}
return null;
};