@lvce-editor/iframe-worker 1.1.0 → 1.2.0
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/dist/iframeWorkerMain.js +257 -22
- package/package.json +1 -1
package/dist/iframeWorkerMain.js
CHANGED
|
@@ -1,29 +1,12 @@
|
|
|
1
|
-
const SemiColon = ';';
|
|
2
|
-
const Space = ' ';
|
|
3
|
-
|
|
4
|
-
const addSemicolon = line => {
|
|
5
|
-
return line + SemiColon;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
const getContentSecurityPolicy = items => {
|
|
9
|
-
return items.map(addSemicolon).join(Space);
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const getWebViewCsp = webView => {
|
|
13
|
-
if (webView && webView.contentSecurityPolicy) {
|
|
14
|
-
return getContentSecurityPolicy(webView.contentSecurityPolicy);
|
|
15
|
-
}
|
|
16
|
-
const csp = getContentSecurityPolicy([`default-src 'none'`, `script-src 'self'`, `style-src 'self'`, `img-src 'self'`, `media-src 'self'`]);
|
|
17
|
-
return csp;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
1
|
const createUrl = (protocol, host) => {
|
|
21
2
|
return protocol + '//' + host;
|
|
22
3
|
};
|
|
23
4
|
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
5
|
+
const createLocalHostUrl = (locationProtocol, locationHost, isGitpod, webViewPort) => {
|
|
6
|
+
if (isGitpod) {
|
|
7
|
+
return createUrl(locationProtocol, locationHost.replace('3000', `${webViewPort}`));
|
|
8
|
+
}
|
|
9
|
+
return `http://localhost:${webViewPort}`;
|
|
27
10
|
};
|
|
28
11
|
|
|
29
12
|
const Web = 1;
|
|
@@ -46,6 +29,7 @@ const getPlatform = () => {
|
|
|
46
29
|
// @ts-ignore
|
|
47
30
|
return PLATFORM;
|
|
48
31
|
}
|
|
32
|
+
// @ts-ignore
|
|
49
33
|
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') {
|
|
50
34
|
return Test;
|
|
51
35
|
}
|
|
@@ -60,8 +44,257 @@ const getPlatform = () => {
|
|
|
60
44
|
};
|
|
61
45
|
const platform = getPlatform();
|
|
62
46
|
|
|
47
|
+
const getAssetDir = () => {
|
|
48
|
+
// @ts-ignore
|
|
49
|
+
if (typeof ASSET_DIR !== 'undefined') {
|
|
50
|
+
// @ts-ignore
|
|
51
|
+
return ASSET_DIR;
|
|
52
|
+
}
|
|
53
|
+
if (platform === Electron) {
|
|
54
|
+
return '';
|
|
55
|
+
}
|
|
56
|
+
return '';
|
|
57
|
+
};
|
|
58
|
+
const assetDir = getAssetDir();
|
|
59
|
+
|
|
60
|
+
const getWebViewHtml = (baseUrl, locationOrigin, elements) => {
|
|
61
|
+
if (!elements) {
|
|
62
|
+
return '';
|
|
63
|
+
}
|
|
64
|
+
const middle = [];
|
|
65
|
+
middle.push('<meta charset="utf-8">');
|
|
66
|
+
for (const element of elements) {
|
|
67
|
+
if (element.type === 'title') {
|
|
68
|
+
middle.push(`<title>${element.value}</title>`);
|
|
69
|
+
} else if (element.type === 'script') {
|
|
70
|
+
middle.push(`<script type="module" src="${locationOrigin}${assetDir}/js/preview-injected.js"></script>`);
|
|
71
|
+
middle.push(`<script type="module" src="${locationOrigin}${baseUrl}/${element.path}"></script>`);
|
|
72
|
+
} else if (element.type === 'css') {
|
|
73
|
+
middle.push(`<link rel="stylesheet" href="${locationOrigin}${baseUrl}/${element.path}" />`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const middleHtml = middle.join('\n ');
|
|
77
|
+
let html = `<!DOCTYPE html>
|
|
78
|
+
<html>
|
|
79
|
+
<head>
|
|
80
|
+
${middleHtml}
|
|
81
|
+
</head>
|
|
82
|
+
</html>
|
|
83
|
+
`;
|
|
84
|
+
return html;
|
|
85
|
+
};
|
|
86
|
+
|
|
63
87
|
const WebView = 'lvce-oss-webview';
|
|
64
88
|
|
|
89
|
+
const getWebView$1 = (webViews, webViewId) => {
|
|
90
|
+
for (const webView of webViews) {
|
|
91
|
+
if (webView.id === webViewId) {
|
|
92
|
+
return webView;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
96
|
+
};
|
|
97
|
+
const getWebViewPath = (webViews, webViewId) => {
|
|
98
|
+
const webView = getWebView$1(webViews, webViewId);
|
|
99
|
+
if (!webView) {
|
|
100
|
+
return '';
|
|
101
|
+
}
|
|
102
|
+
return webView.path;
|
|
103
|
+
};
|
|
104
|
+
const getWebViewUri = (webViews, webViewId) => {
|
|
105
|
+
const webViewPath = getWebViewPath(webViews, webViewId);
|
|
106
|
+
if (!webViewPath) {
|
|
107
|
+
return '';
|
|
108
|
+
}
|
|
109
|
+
if (webViewPath.startsWith('/')) {
|
|
110
|
+
// TODO make it work on windows also
|
|
111
|
+
return `file://${webViewPath}`;
|
|
112
|
+
}
|
|
113
|
+
return webViewPath;
|
|
114
|
+
};
|
|
115
|
+
const getIframeSrcRemote = (webViews, webViewPort, webViewId, locationProtocol, locationHost, isGitpod, root) => {
|
|
116
|
+
const webView = getWebView$1(webViews, webViewId);
|
|
117
|
+
const webViewUri = getWebViewUri(webViews, webViewId);
|
|
118
|
+
if (!webViewUri) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
let iframeSrc = webViewUri;
|
|
122
|
+
let webViewRoot = webViewUri;
|
|
123
|
+
if (platform === Electron) {
|
|
124
|
+
const relativePath = new URL(webViewUri).pathname.replace('/index.html', '');
|
|
125
|
+
iframeSrc = `${WebView}://-${relativePath}/`;
|
|
126
|
+
// TODO
|
|
127
|
+
} else if (platform === Remote) {
|
|
128
|
+
const relativePath = new URL(webViewUri).pathname.replace('/index.html', '');
|
|
129
|
+
if (webViewUri.startsWith('file://')) {
|
|
130
|
+
// ignore
|
|
131
|
+
webViewRoot = webViewUri.slice('file://'.length).replace('/index.html', '');
|
|
132
|
+
} else {
|
|
133
|
+
webViewRoot = root + relativePath;
|
|
134
|
+
}
|
|
135
|
+
iframeSrc = createLocalHostUrl(locationProtocol, locationHost, isGitpod, webViewPort);
|
|
136
|
+
}
|
|
137
|
+
let iframeContent = getWebViewHtml('', '', webView.elements);
|
|
138
|
+
// TODO either
|
|
139
|
+
// - load webviews the same as in web using blob urls
|
|
140
|
+
// - load webviews from a pattern like /webviews/:id/:fileName
|
|
141
|
+
iframeContent = iframeContent.replaceAll('/media/', '/').replaceAll('//', '/');
|
|
142
|
+
return {
|
|
143
|
+
srcDoc: '',
|
|
144
|
+
iframeSrc,
|
|
145
|
+
webViewRoot,
|
|
146
|
+
iframeContent
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const getBlobUrl = (content, contentType) => {
|
|
151
|
+
const blob = new Blob([content], {
|
|
152
|
+
type: contentType
|
|
153
|
+
});
|
|
154
|
+
const url = URL.createObjectURL(blob); // TODO dispose
|
|
155
|
+
return url;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const getDefaultBaseUrl = webView => {
|
|
159
|
+
const {
|
|
160
|
+
remotePath,
|
|
161
|
+
path
|
|
162
|
+
} = webView;
|
|
163
|
+
if (remotePath) {
|
|
164
|
+
if (remotePath.endsWith('/index.html')) {
|
|
165
|
+
return remotePath.slice(0, -'/index.html'.length);
|
|
166
|
+
}
|
|
167
|
+
return remotePath;
|
|
168
|
+
}
|
|
169
|
+
if (path) {
|
|
170
|
+
if (path.endsWith('/index.html')) {
|
|
171
|
+
return path.slice(0, -'/index.html'.length);
|
|
172
|
+
}
|
|
173
|
+
return path;
|
|
174
|
+
}
|
|
175
|
+
return '';
|
|
176
|
+
};
|
|
177
|
+
const getWebViewBaseUrl = webView => {
|
|
178
|
+
const defaultBaseUrl = getDefaultBaseUrl(webView);
|
|
179
|
+
return defaultBaseUrl;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const getIframeSrc$1 = (webView, locationOrigin) => {
|
|
183
|
+
const baseUrl = getWebViewBaseUrl(webView);
|
|
184
|
+
const srcHtml = getWebViewHtml(baseUrl, locationOrigin, webView.elements);
|
|
185
|
+
if (srcHtml) {
|
|
186
|
+
const blobUrl = getBlobUrl(srcHtml, 'text/html');
|
|
187
|
+
return {
|
|
188
|
+
srcDoc: '',
|
|
189
|
+
iframeSrc: blobUrl,
|
|
190
|
+
webViewRoot: '',
|
|
191
|
+
iframeContent: ''
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
return undefined;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const getWebView = (webViews, webViewId) => {
|
|
198
|
+
for (const webView of webViews) {
|
|
199
|
+
if (webView.id === webViewId) {
|
|
200
|
+
return webView;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return undefined;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const normalizeLine$1 = line => {
|
|
207
|
+
if (line.startsWith('Error: ')) {
|
|
208
|
+
return line.slice(`Error: `.length);
|
|
209
|
+
}
|
|
210
|
+
if (line.startsWith('VError: ')) {
|
|
211
|
+
return line.slice(`VError: `.length);
|
|
212
|
+
}
|
|
213
|
+
return line;
|
|
214
|
+
};
|
|
215
|
+
const getCombinedMessage$1 = (error, message) => {
|
|
216
|
+
const stringifiedError = normalizeLine$1(`${error}`);
|
|
217
|
+
if (message) {
|
|
218
|
+
return `${message}: ${stringifiedError}`;
|
|
219
|
+
}
|
|
220
|
+
return stringifiedError;
|
|
221
|
+
};
|
|
222
|
+
const NewLine$2 = '\n';
|
|
223
|
+
const getNewLineIndex$1 = (string, startIndex = undefined) => {
|
|
224
|
+
return string.indexOf(NewLine$2, startIndex);
|
|
225
|
+
};
|
|
226
|
+
const mergeStacks$1 = (parent, child) => {
|
|
227
|
+
if (!child) {
|
|
228
|
+
return parent;
|
|
229
|
+
}
|
|
230
|
+
const parentNewLineIndex = getNewLineIndex$1(parent);
|
|
231
|
+
const childNewLineIndex = getNewLineIndex$1(child);
|
|
232
|
+
if (childNewLineIndex === -1) {
|
|
233
|
+
return parent;
|
|
234
|
+
}
|
|
235
|
+
const parentFirstLine = parent.slice(0, parentNewLineIndex);
|
|
236
|
+
const childRest = child.slice(childNewLineIndex);
|
|
237
|
+
const childFirstLine = normalizeLine$1(child.slice(0, childNewLineIndex));
|
|
238
|
+
if (parentFirstLine.includes(childFirstLine)) {
|
|
239
|
+
return parentFirstLine + childRest;
|
|
240
|
+
}
|
|
241
|
+
return child;
|
|
242
|
+
};
|
|
243
|
+
let VError$1 = class VError extends Error {
|
|
244
|
+
constructor(error, message) {
|
|
245
|
+
const combinedMessage = getCombinedMessage$1(error, message);
|
|
246
|
+
super(combinedMessage);
|
|
247
|
+
this.name = 'VError';
|
|
248
|
+
if (error instanceof Error) {
|
|
249
|
+
this.stack = mergeStacks$1(this.stack, error.stack);
|
|
250
|
+
}
|
|
251
|
+
if (error.codeFrame) {
|
|
252
|
+
// @ts-ignore
|
|
253
|
+
this.codeFrame = error.codeFrame;
|
|
254
|
+
}
|
|
255
|
+
if (error.code) {
|
|
256
|
+
// @ts-ignore
|
|
257
|
+
this.code = error.code;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const getIframeSrc = (webViews, webViewId, webViewPort, root, isGitpod, locationProtocol, locationHost, locationOrigin) => {
|
|
263
|
+
try {
|
|
264
|
+
const webView = getWebView(webViews, webViewId);
|
|
265
|
+
if (platform === Web) {
|
|
266
|
+
return getIframeSrc$1(webView, locationOrigin);
|
|
267
|
+
}
|
|
268
|
+
return getIframeSrcRemote(webViews, webViewPort, webViewId, locationProtocol, locationHost, isGitpod, root);
|
|
269
|
+
} catch (error) {
|
|
270
|
+
throw new VError$1(error, `Failed to construct webview iframe src`);
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const SemiColon = ';';
|
|
275
|
+
const Space = ' ';
|
|
276
|
+
|
|
277
|
+
const addSemicolon = line => {
|
|
278
|
+
return line + SemiColon;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const getContentSecurityPolicy = items => {
|
|
282
|
+
return items.map(addSemicolon).join(Space);
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const getWebViewCsp = webView => {
|
|
286
|
+
if (webView && webView.contentSecurityPolicy) {
|
|
287
|
+
return getContentSecurityPolicy(webView.contentSecurityPolicy);
|
|
288
|
+
}
|
|
289
|
+
const csp = getContentSecurityPolicy([`default-src 'none'`, `script-src 'self'`, `style-src 'self'`, `img-src 'self'`, `media-src 'self'`]);
|
|
290
|
+
return csp;
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const getWebViewFrameAncestors = (locationProtocol, locationHost) => {
|
|
294
|
+
const frameAncestors = createUrl(locationProtocol, locationHost);
|
|
295
|
+
return frameAncestors;
|
|
296
|
+
};
|
|
297
|
+
|
|
65
298
|
const getWebViewOrigin = webViewPort => {
|
|
66
299
|
// TODO don't hardcode protocol
|
|
67
300
|
let origin = '';
|
|
@@ -104,7 +337,9 @@ const commandMap = {
|
|
|
104
337
|
'Location.getHost': getHost,
|
|
105
338
|
'Location.getOrigin': getOrigin,
|
|
106
339
|
'Location.getProtocol': getProtocol,
|
|
340
|
+
'WebView.getBaseUrl': getWebViewBaseUrl,
|
|
107
341
|
'WebView.getFrameAncestors': getWebViewFrameAncestors,
|
|
342
|
+
'WebView.getIframeSrc': getIframeSrc,
|
|
108
343
|
'WebView.getOrigin': getWebViewOrigin,
|
|
109
344
|
'WebView.getSandbox': getIframeSandbox,
|
|
110
345
|
'WebView.getWebViewCsp': getWebViewCsp
|