@rindo/core 3.0.1 → 3.1.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/cli/config-flags.d.ts +122 -122
- package/cli/index.cjs +2301 -2432
- package/cli/index.d.ts +19 -19
- package/cli/index.js +2302 -2433
- package/cli/package.json +1 -1
- package/compiler/package.json +1 -1
- package/compiler/rindo.d.ts +73 -73
- package/compiler/rindo.js +66137 -62907
- package/compiler/rindo.min.js +2 -2
- package/compiler/sys/in-memory-fs.d.ts +218 -218
- package/compiler/transpile.d.ts +32 -32
- package/dev-server/client/app-error.d.ts +18 -18
- package/dev-server/client/events.d.ts +6 -6
- package/dev-server/client/hmr-components.d.ts +1 -1
- package/dev-server/client/hmr-external-styles.d.ts +1 -1
- package/dev-server/client/hmr-images.d.ts +1 -1
- package/dev-server/client/hmr-inline-styles.d.ts +1 -1
- package/dev-server/client/hmr-util.d.ts +9 -9
- package/dev-server/client/hmr-window.d.ts +10 -10
- package/dev-server/client/index.d.ts +6 -6
- package/dev-server/client/index.js +781 -781
- package/dev-server/client/logger.d.ts +5 -5
- package/dev-server/client/package.json +1 -1
- package/dev-server/client/progress.d.ts +3 -3
- package/dev-server/client/status.d.ts +4 -4
- package/dev-server/connector.html +2 -2
- package/dev-server/index.d.ts +3 -3
- package/dev-server/index.js +228 -228
- package/dev-server/open-in-editor-api.js +1 -1
- package/dev-server/package.json +1 -1
- package/dev-server/server-process.js +1300 -1281
- package/dev-server/ws.js +1 -1
- package/dev-server/xdg-open +0 -0
- package/internal/app-data/index.cjs +88 -88
- package/internal/app-data/index.d.ts +4 -4
- package/internal/app-data/index.js +88 -88
- package/internal/app-data/package.json +1 -1
- package/internal/client/css-shim.js +1 -1
- package/internal/client/dom.js +1 -1
- package/internal/client/index.js +3380 -3380
- package/internal/client/package.json +1 -1
- package/internal/client/patch-browser.js +155 -155
- package/internal/client/patch-esm.js +25 -25
- package/internal/client/shadow-css.js +382 -382
- package/internal/hydrate/package.json +1 -1
- package/internal/index.d.ts +2 -2
- package/internal/index.js +1 -1
- package/internal/package.json +1 -1
- package/internal/rindo-private.d.ts +2272 -2268
- package/internal/rindo-public-compiler.d.ts +2377 -2356
- package/internal/rindo-public-docs.d.ts +139 -139
- package/internal/rindo-public-runtime.d.ts +1636 -1636
- package/internal/testing/package.json +1 -1
- package/mock-doc/index.cjs +4766 -4766
- package/mock-doc/index.d.ts +1006 -1006
- package/mock-doc/index.js +4766 -4766
- package/mock-doc/package.json +1 -1
- package/package.json +9 -9
- package/screenshot/connector-base.d.ts +42 -42
- package/screenshot/connector-local.d.ts +7 -7
- package/screenshot/index.d.ts +3 -3
- package/screenshot/index.js +615 -615
- package/screenshot/package.json +1 -1
- package/screenshot/pixel-match.d.ts +1 -1
- package/screenshot/pixel-match.js +14 -14
- package/screenshot/screenshot-compare.d.ts +3 -3
- package/screenshot/screenshot-fs.d.ts +15 -15
- package/sys/node/autoprefixer.js +2 -2
- package/sys/node/glob.js +1 -1
- package/sys/node/graceful-fs.js +1 -1
- package/sys/node/index.d.ts +22 -22
- package/sys/node/index.js +6 -3
- package/sys/node/node-fetch.js +1 -1
- package/sys/node/package.json +1 -1
- package/sys/node/prompts.js +1 -1
- package/sys/node/worker.js +1 -1
- package/testing/index.d.ts +12 -12
- package/testing/index.js +7 -3
- package/testing/jest/jest-config.d.ts +16 -16
- package/testing/jest/jest-environment.d.ts +15 -15
- package/testing/jest/jest-preprocessor.d.ts +59 -59
- package/testing/jest/jest-runner.d.ts +10 -10
- package/testing/jest/jest-screenshot.d.ts +2 -2
- package/testing/jest/jest-serializer.d.ts +4 -4
- package/testing/jest/jest-setup-test-framework.d.ts +1 -1
- package/testing/matchers/attributes.d.ts +14 -14
- package/testing/matchers/class-list.d.ts +12 -12
- package/testing/matchers/events.d.ts +21 -21
- package/testing/matchers/html.d.ts +12 -12
- package/testing/matchers/index.d.ts +23 -23
- package/testing/matchers/screenshot.d.ts +5 -5
- package/testing/matchers/text.d.ts +4 -4
- package/testing/mock-fetch.d.ts +11 -11
- package/testing/mocks.d.ts +56 -56
- package/testing/package.json +1 -1
- package/testing/puppeteer/index.d.ts +2 -2
- package/testing/puppeteer/puppeteer-browser.d.ts +6 -6
- package/testing/puppeteer/puppeteer-declarations.d.ts +403 -403
- package/testing/puppeteer/puppeteer-element.d.ts +67 -67
- package/testing/puppeteer/puppeteer-emulate.d.ts +2 -2
- package/testing/puppeteer/puppeteer-events.d.ts +21 -21
- package/testing/puppeteer/puppeteer-page.d.ts +2 -2
- package/testing/puppeteer/puppeteer-screenshot.d.ts +4 -4
- package/testing/reset-build-conditionals.d.ts +2 -2
- package/testing/spec-page.d.ts +2 -2
- package/testing/test-transpile.d.ts +2 -2
- package/testing/testing-logger.d.ts +25 -25
- package/testing/testing-sys.d.ts +6 -6
- package/testing/testing-utils.d.ts +79 -79
- package/testing/testing.d.ts +2 -2
- package/dependencies.json +0 -120
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
Rindo Dev Server Process v3.0
|
|
2
|
+
Rindo Dev Server Process v3.1.0 | MIT Licensed | https://rindojs.web.app
|
|
3
3
|
*/
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
@@ -53,324 +53,324 @@ const openInEditorApi__default = /*#__PURE__*/_interopDefaultLegacy(openInEditor
|
|
|
53
53
|
const zlib__namespace = /*#__PURE__*/_interopNamespace(zlib);
|
|
54
54
|
const ws__namespace = /*#__PURE__*/_interopNamespace(ws);
|
|
55
55
|
|
|
56
|
-
/**
|
|
57
|
-
* This is just a no-op, don't expect it to do anything.
|
|
58
|
-
*/
|
|
59
|
-
const noop = () => {
|
|
60
|
-
/* noop*/
|
|
61
|
-
};
|
|
62
|
-
const isFunction = (v) => typeof v === 'function';
|
|
56
|
+
/**
|
|
57
|
+
* This is just a no-op, don't expect it to do anything.
|
|
58
|
+
*/
|
|
59
|
+
const noop = () => {
|
|
60
|
+
/* noop*/
|
|
61
|
+
};
|
|
62
|
+
const isFunction = (v) => typeof v === 'function';
|
|
63
63
|
const isString = (v) => typeof v === 'string';
|
|
64
64
|
|
|
65
|
-
/**
|
|
66
|
-
* Builds a diagnostic from an `Error`, appends it to the `diagnostics` parameter, and returns the created diagnostic
|
|
67
|
-
* @param diagnostics the series of diagnostics the newly created diagnostics should be added to
|
|
68
|
-
* @param err the error to derive information from in generating the diagnostic
|
|
69
|
-
* @param msg an optional message to use in place of `err` to generate the diagnostic
|
|
70
|
-
* @returns the generated diagnostic
|
|
71
|
-
*/
|
|
72
|
-
const catchError = (diagnostics, err, msg) => {
|
|
73
|
-
const diagnostic = {
|
|
74
|
-
level: 'error',
|
|
75
|
-
type: 'build',
|
|
76
|
-
header: 'Build Error',
|
|
77
|
-
messageText: 'build error',
|
|
78
|
-
relFilePath: null,
|
|
79
|
-
absFilePath: null,
|
|
80
|
-
lines: [],
|
|
81
|
-
};
|
|
82
|
-
if (isString(msg)) {
|
|
83
|
-
diagnostic.messageText = msg.length ? msg : 'UNKNOWN ERROR';
|
|
84
|
-
}
|
|
85
|
-
else if (err != null) {
|
|
86
|
-
if (err.stack != null) {
|
|
87
|
-
diagnostic.messageText = err.stack.toString();
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
if (err.message != null) {
|
|
91
|
-
diagnostic.messageText = err.message.length ? err.message : 'UNKNOWN ERROR';
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
diagnostic.messageText = err.toString();
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (diagnostics != null && !shouldIgnoreError(diagnostic.messageText)) {
|
|
99
|
-
diagnostics.push(diagnostic);
|
|
100
|
-
}
|
|
101
|
-
return diagnostic;
|
|
102
|
-
};
|
|
103
|
-
const shouldIgnoreError = (msg) => {
|
|
104
|
-
return msg === TASK_CANCELED_MSG;
|
|
105
|
-
};
|
|
65
|
+
/**
|
|
66
|
+
* Builds a diagnostic from an `Error`, appends it to the `diagnostics` parameter, and returns the created diagnostic
|
|
67
|
+
* @param diagnostics the series of diagnostics the newly created diagnostics should be added to
|
|
68
|
+
* @param err the error to derive information from in generating the diagnostic
|
|
69
|
+
* @param msg an optional message to use in place of `err` to generate the diagnostic
|
|
70
|
+
* @returns the generated diagnostic
|
|
71
|
+
*/
|
|
72
|
+
const catchError = (diagnostics, err, msg) => {
|
|
73
|
+
const diagnostic = {
|
|
74
|
+
level: 'error',
|
|
75
|
+
type: 'build',
|
|
76
|
+
header: 'Build Error',
|
|
77
|
+
messageText: 'build error',
|
|
78
|
+
relFilePath: null,
|
|
79
|
+
absFilePath: null,
|
|
80
|
+
lines: [],
|
|
81
|
+
};
|
|
82
|
+
if (isString(msg)) {
|
|
83
|
+
diagnostic.messageText = msg.length ? msg : 'UNKNOWN ERROR';
|
|
84
|
+
}
|
|
85
|
+
else if (err != null) {
|
|
86
|
+
if (err.stack != null) {
|
|
87
|
+
diagnostic.messageText = err.stack.toString();
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
if (err.message != null) {
|
|
91
|
+
diagnostic.messageText = err.message.length ? err.message : 'UNKNOWN ERROR';
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
diagnostic.messageText = err.toString();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (diagnostics != null && !shouldIgnoreError(diagnostic.messageText)) {
|
|
99
|
+
diagnostics.push(diagnostic);
|
|
100
|
+
}
|
|
101
|
+
return diagnostic;
|
|
102
|
+
};
|
|
103
|
+
const shouldIgnoreError = (msg) => {
|
|
104
|
+
return msg === TASK_CANCELED_MSG;
|
|
105
|
+
};
|
|
106
106
|
const TASK_CANCELED_MSG = `task canceled`;
|
|
107
107
|
|
|
108
|
-
/**
|
|
109
|
-
* Convert Windows backslash paths to slash paths: foo\\bar ➔ foo/bar
|
|
110
|
-
* Forward-slash paths can be used in Windows as long as they're not
|
|
111
|
-
* extended-length paths and don't contain any non-ascii characters.
|
|
112
|
-
* This was created since the path methods in Node.js outputs \\ paths on Windows.
|
|
113
|
-
* @param path the Windows-based path to convert
|
|
114
|
-
* @returns the converted path
|
|
115
|
-
*/
|
|
116
|
-
const normalizePath = (path) => {
|
|
117
|
-
if (typeof path !== 'string') {
|
|
118
|
-
throw new Error(`invalid path to normalize`);
|
|
119
|
-
}
|
|
120
|
-
path = normalizeSlashes(path.trim());
|
|
121
|
-
const components = pathComponents(path, getRootLength(path));
|
|
122
|
-
const reducedComponents = reducePathComponents(components);
|
|
123
|
-
const rootPart = reducedComponents[0];
|
|
124
|
-
const secondPart = reducedComponents[1];
|
|
125
|
-
const normalized = rootPart + reducedComponents.slice(1).join('/');
|
|
126
|
-
if (normalized === '') {
|
|
127
|
-
return '.';
|
|
128
|
-
}
|
|
129
|
-
if (rootPart === '' &&
|
|
130
|
-
secondPart &&
|
|
131
|
-
path.includes('/') &&
|
|
132
|
-
!secondPart.startsWith('.') &&
|
|
133
|
-
!secondPart.startsWith('@')) {
|
|
134
|
-
return './' + normalized;
|
|
135
|
-
}
|
|
136
|
-
return normalized;
|
|
137
|
-
};
|
|
138
|
-
const normalizeSlashes = (path) => path.replace(backslashRegExp, '/');
|
|
139
|
-
const altDirectorySeparator = '\\';
|
|
140
|
-
const urlSchemeSeparator = '://';
|
|
141
|
-
const backslashRegExp = /\\/g;
|
|
142
|
-
const reducePathComponents = (components) => {
|
|
143
|
-
if (!Array.isArray(components) || components.length === 0) {
|
|
144
|
-
return [];
|
|
145
|
-
}
|
|
146
|
-
const reduced = [components[0]];
|
|
147
|
-
for (let i = 1; i < components.length; i++) {
|
|
148
|
-
const component = components[i];
|
|
149
|
-
if (!component)
|
|
150
|
-
continue;
|
|
151
|
-
if (component === '.')
|
|
152
|
-
continue;
|
|
153
|
-
if (component === '..') {
|
|
154
|
-
if (reduced.length > 1) {
|
|
155
|
-
if (reduced[reduced.length - 1] !== '..') {
|
|
156
|
-
reduced.pop();
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
else if (reduced[0])
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
reduced.push(component);
|
|
164
|
-
}
|
|
165
|
-
return reduced;
|
|
166
|
-
};
|
|
167
|
-
const getRootLength = (path) => {
|
|
168
|
-
const rootLength = getEncodedRootLength(path);
|
|
169
|
-
return rootLength < 0 ? ~rootLength : rootLength;
|
|
170
|
-
};
|
|
171
|
-
const getEncodedRootLength = (path) => {
|
|
172
|
-
if (!path)
|
|
173
|
-
return 0;
|
|
174
|
-
const ch0 = path.charCodeAt(0);
|
|
175
|
-
// POSIX or UNC
|
|
176
|
-
if (ch0 === 47 /* CharacterCodes.slash */ || ch0 === 92 /* CharacterCodes.backslash */) {
|
|
177
|
-
if (path.charCodeAt(1) !== ch0)
|
|
178
|
-
return 1; // POSIX: "/" (or non-normalized "\")
|
|
179
|
-
const p1 = path.indexOf(ch0 === 47 /* CharacterCodes.slash */ ? '/' : altDirectorySeparator, 2);
|
|
180
|
-
if (p1 < 0)
|
|
181
|
-
return path.length; // UNC: "//server" or "\\server"
|
|
182
|
-
return p1 + 1; // UNC: "//server/" or "\\server\"
|
|
183
|
-
}
|
|
184
|
-
// DOS
|
|
185
|
-
if (isVolumeCharacter(ch0) && path.charCodeAt(1) === 58 /* CharacterCodes.colon */) {
|
|
186
|
-
const ch2 = path.charCodeAt(2);
|
|
187
|
-
if (ch2 === 47 /* CharacterCodes.slash */ || ch2 === 92 /* CharacterCodes.backslash */)
|
|
188
|
-
return 3; // DOS: "c:/" or "c:\"
|
|
189
|
-
if (path.length === 2)
|
|
190
|
-
return 2; // DOS: "c:" (but not "c:d")
|
|
191
|
-
}
|
|
192
|
-
// URL
|
|
193
|
-
const schemeEnd = path.indexOf(urlSchemeSeparator);
|
|
194
|
-
if (schemeEnd !== -1) {
|
|
195
|
-
const authorityStart = schemeEnd + urlSchemeSeparator.length;
|
|
196
|
-
const authorityEnd = path.indexOf('/', authorityStart);
|
|
197
|
-
if (authorityEnd !== -1) {
|
|
198
|
-
// URL: "file:///", "file://server/", "file://server/path"
|
|
199
|
-
// For local "file" URLs, include the leading DOS volume (if present).
|
|
200
|
-
// Per https://www.ietf.org/rfc/rfc1738.txt, a host of "" or "localhost" is a
|
|
201
|
-
// special case interpreted as "the machine from which the URL is being interpreted".
|
|
202
|
-
const scheme = path.slice(0, schemeEnd);
|
|
203
|
-
const authority = path.slice(authorityStart, authorityEnd);
|
|
204
|
-
if (scheme === 'file' &&
|
|
205
|
-
(authority === '' || authority === 'localhost') &&
|
|
206
|
-
isVolumeCharacter(path.charCodeAt(authorityEnd + 1))) {
|
|
207
|
-
const volumeSeparatorEnd = getFileUrlVolumeSeparatorEnd(path, authorityEnd + 2);
|
|
208
|
-
if (volumeSeparatorEnd !== -1) {
|
|
209
|
-
if (path.charCodeAt(volumeSeparatorEnd) === 47 /* CharacterCodes.slash */) {
|
|
210
|
-
// URL: "file:///c:/", "file://localhost/c:/", "file:///c%3a/", "file://localhost/c%3a/"
|
|
211
|
-
return ~(volumeSeparatorEnd + 1);
|
|
212
|
-
}
|
|
213
|
-
if (volumeSeparatorEnd === path.length) {
|
|
214
|
-
// URL: "file:///c:", "file://localhost/c:", "file:///c$3a", "file://localhost/c%3a"
|
|
215
|
-
// but not "file:///c:d" or "file:///c%3ad"
|
|
216
|
-
return ~volumeSeparatorEnd;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
return ~(authorityEnd + 1); // URL: "file://server/", "http://server/"
|
|
221
|
-
}
|
|
222
|
-
return ~path.length; // URL: "file://server", "http://server"
|
|
223
|
-
}
|
|
224
|
-
// relative
|
|
225
|
-
return 0;
|
|
226
|
-
};
|
|
227
|
-
const isVolumeCharacter = (charCode) => (charCode >= 97 /* CharacterCodes.a */ && charCode <= 122 /* CharacterCodes.z */) ||
|
|
228
|
-
(charCode >= 65 /* CharacterCodes.A */ && charCode <= 90 /* CharacterCodes.Z */);
|
|
229
|
-
const getFileUrlVolumeSeparatorEnd = (url, start) => {
|
|
230
|
-
const ch0 = url.charCodeAt(start);
|
|
231
|
-
if (ch0 === 58 /* CharacterCodes.colon */)
|
|
232
|
-
return start + 1;
|
|
233
|
-
if (ch0 === 37 /* CharacterCodes.percent */ && url.charCodeAt(start + 1) === 51 /* CharacterCodes._3 */) {
|
|
234
|
-
const ch2 = url.charCodeAt(start + 2);
|
|
235
|
-
if (ch2 === 97 /* CharacterCodes.a */ || ch2 === 65 /* CharacterCodes.A */)
|
|
236
|
-
return start + 3;
|
|
237
|
-
}
|
|
238
|
-
return -1;
|
|
239
|
-
};
|
|
240
|
-
const pathComponents = (path, rootLength) => {
|
|
241
|
-
const root = path.substring(0, rootLength);
|
|
242
|
-
const rest = path.substring(rootLength).split('/');
|
|
243
|
-
const restLen = rest.length;
|
|
244
|
-
if (restLen > 0 && !rest[restLen - 1]) {
|
|
245
|
-
rest.pop();
|
|
246
|
-
}
|
|
247
|
-
return [root, ...rest];
|
|
108
|
+
/**
|
|
109
|
+
* Convert Windows backslash paths to slash paths: foo\\bar ➔ foo/bar
|
|
110
|
+
* Forward-slash paths can be used in Windows as long as they're not
|
|
111
|
+
* extended-length paths and don't contain any non-ascii characters.
|
|
112
|
+
* This was created since the path methods in Node.js outputs \\ paths on Windows.
|
|
113
|
+
* @param path the Windows-based path to convert
|
|
114
|
+
* @returns the converted path
|
|
115
|
+
*/
|
|
116
|
+
const normalizePath = (path) => {
|
|
117
|
+
if (typeof path !== 'string') {
|
|
118
|
+
throw new Error(`invalid path to normalize`);
|
|
119
|
+
}
|
|
120
|
+
path = normalizeSlashes(path.trim());
|
|
121
|
+
const components = pathComponents(path, getRootLength(path));
|
|
122
|
+
const reducedComponents = reducePathComponents(components);
|
|
123
|
+
const rootPart = reducedComponents[0];
|
|
124
|
+
const secondPart = reducedComponents[1];
|
|
125
|
+
const normalized = rootPart + reducedComponents.slice(1).join('/');
|
|
126
|
+
if (normalized === '') {
|
|
127
|
+
return '.';
|
|
128
|
+
}
|
|
129
|
+
if (rootPart === '' &&
|
|
130
|
+
secondPart &&
|
|
131
|
+
path.includes('/') &&
|
|
132
|
+
!secondPart.startsWith('.') &&
|
|
133
|
+
!secondPart.startsWith('@')) {
|
|
134
|
+
return './' + normalized;
|
|
135
|
+
}
|
|
136
|
+
return normalized;
|
|
137
|
+
};
|
|
138
|
+
const normalizeSlashes = (path) => path.replace(backslashRegExp, '/');
|
|
139
|
+
const altDirectorySeparator = '\\';
|
|
140
|
+
const urlSchemeSeparator = '://';
|
|
141
|
+
const backslashRegExp = /\\/g;
|
|
142
|
+
const reducePathComponents = (components) => {
|
|
143
|
+
if (!Array.isArray(components) || components.length === 0) {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
const reduced = [components[0]];
|
|
147
|
+
for (let i = 1; i < components.length; i++) {
|
|
148
|
+
const component = components[i];
|
|
149
|
+
if (!component)
|
|
150
|
+
continue;
|
|
151
|
+
if (component === '.')
|
|
152
|
+
continue;
|
|
153
|
+
if (component === '..') {
|
|
154
|
+
if (reduced.length > 1) {
|
|
155
|
+
if (reduced[reduced.length - 1] !== '..') {
|
|
156
|
+
reduced.pop();
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else if (reduced[0])
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
reduced.push(component);
|
|
164
|
+
}
|
|
165
|
+
return reduced;
|
|
166
|
+
};
|
|
167
|
+
const getRootLength = (path) => {
|
|
168
|
+
const rootLength = getEncodedRootLength(path);
|
|
169
|
+
return rootLength < 0 ? ~rootLength : rootLength;
|
|
170
|
+
};
|
|
171
|
+
const getEncodedRootLength = (path) => {
|
|
172
|
+
if (!path)
|
|
173
|
+
return 0;
|
|
174
|
+
const ch0 = path.charCodeAt(0);
|
|
175
|
+
// POSIX or UNC
|
|
176
|
+
if (ch0 === 47 /* CharacterCodes.slash */ || ch0 === 92 /* CharacterCodes.backslash */) {
|
|
177
|
+
if (path.charCodeAt(1) !== ch0)
|
|
178
|
+
return 1; // POSIX: "/" (or non-normalized "\")
|
|
179
|
+
const p1 = path.indexOf(ch0 === 47 /* CharacterCodes.slash */ ? '/' : altDirectorySeparator, 2);
|
|
180
|
+
if (p1 < 0)
|
|
181
|
+
return path.length; // UNC: "//server" or "\\server"
|
|
182
|
+
return p1 + 1; // UNC: "//server/" or "\\server\"
|
|
183
|
+
}
|
|
184
|
+
// DOS
|
|
185
|
+
if (isVolumeCharacter(ch0) && path.charCodeAt(1) === 58 /* CharacterCodes.colon */) {
|
|
186
|
+
const ch2 = path.charCodeAt(2);
|
|
187
|
+
if (ch2 === 47 /* CharacterCodes.slash */ || ch2 === 92 /* CharacterCodes.backslash */)
|
|
188
|
+
return 3; // DOS: "c:/" or "c:\"
|
|
189
|
+
if (path.length === 2)
|
|
190
|
+
return 2; // DOS: "c:" (but not "c:d")
|
|
191
|
+
}
|
|
192
|
+
// URL
|
|
193
|
+
const schemeEnd = path.indexOf(urlSchemeSeparator);
|
|
194
|
+
if (schemeEnd !== -1) {
|
|
195
|
+
const authorityStart = schemeEnd + urlSchemeSeparator.length;
|
|
196
|
+
const authorityEnd = path.indexOf('/', authorityStart);
|
|
197
|
+
if (authorityEnd !== -1) {
|
|
198
|
+
// URL: "file:///", "file://server/", "file://server/path"
|
|
199
|
+
// For local "file" URLs, include the leading DOS volume (if present).
|
|
200
|
+
// Per https://www.ietf.org/rfc/rfc1738.txt, a host of "" or "localhost" is a
|
|
201
|
+
// special case interpreted as "the machine from which the URL is being interpreted".
|
|
202
|
+
const scheme = path.slice(0, schemeEnd);
|
|
203
|
+
const authority = path.slice(authorityStart, authorityEnd);
|
|
204
|
+
if (scheme === 'file' &&
|
|
205
|
+
(authority === '' || authority === 'localhost') &&
|
|
206
|
+
isVolumeCharacter(path.charCodeAt(authorityEnd + 1))) {
|
|
207
|
+
const volumeSeparatorEnd = getFileUrlVolumeSeparatorEnd(path, authorityEnd + 2);
|
|
208
|
+
if (volumeSeparatorEnd !== -1) {
|
|
209
|
+
if (path.charCodeAt(volumeSeparatorEnd) === 47 /* CharacterCodes.slash */) {
|
|
210
|
+
// URL: "file:///c:/", "file://localhost/c:/", "file:///c%3a/", "file://localhost/c%3a/"
|
|
211
|
+
return ~(volumeSeparatorEnd + 1);
|
|
212
|
+
}
|
|
213
|
+
if (volumeSeparatorEnd === path.length) {
|
|
214
|
+
// URL: "file:///c:", "file://localhost/c:", "file:///c$3a", "file://localhost/c%3a"
|
|
215
|
+
// but not "file:///c:d" or "file:///c%3ad"
|
|
216
|
+
return ~volumeSeparatorEnd;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return ~(authorityEnd + 1); // URL: "file://server/", "http://server/"
|
|
221
|
+
}
|
|
222
|
+
return ~path.length; // URL: "file://server", "http://server"
|
|
223
|
+
}
|
|
224
|
+
// relative
|
|
225
|
+
return 0;
|
|
226
|
+
};
|
|
227
|
+
const isVolumeCharacter = (charCode) => (charCode >= 97 /* CharacterCodes.a */ && charCode <= 122 /* CharacterCodes.z */) ||
|
|
228
|
+
(charCode >= 65 /* CharacterCodes.A */ && charCode <= 90 /* CharacterCodes.Z */);
|
|
229
|
+
const getFileUrlVolumeSeparatorEnd = (url, start) => {
|
|
230
|
+
const ch0 = url.charCodeAt(start);
|
|
231
|
+
if (ch0 === 58 /* CharacterCodes.colon */)
|
|
232
|
+
return start + 1;
|
|
233
|
+
if (ch0 === 37 /* CharacterCodes.percent */ && url.charCodeAt(start + 1) === 51 /* CharacterCodes._3 */) {
|
|
234
|
+
const ch2 = url.charCodeAt(start + 2);
|
|
235
|
+
if (ch2 === 97 /* CharacterCodes.a */ || ch2 === 65 /* CharacterCodes.A */)
|
|
236
|
+
return start + 3;
|
|
237
|
+
}
|
|
238
|
+
return -1;
|
|
239
|
+
};
|
|
240
|
+
const pathComponents = (path, rootLength) => {
|
|
241
|
+
const root = path.substring(0, rootLength);
|
|
242
|
+
const rest = path.substring(rootLength).split('/');
|
|
243
|
+
const restLen = rest.length;
|
|
244
|
+
if (restLen > 0 && !rest[restLen - 1]) {
|
|
245
|
+
rest.pop();
|
|
246
|
+
}
|
|
247
|
+
return [root, ...rest];
|
|
248
248
|
};
|
|
249
249
|
|
|
250
|
-
const DEV_SERVER_URL = '/~dev-server';
|
|
251
|
-
const DEV_MODULE_URL = '/~dev-module';
|
|
252
|
-
const DEV_SERVER_INIT_URL = `${DEV_SERVER_URL}-init`;
|
|
250
|
+
const DEV_SERVER_URL = '/~dev-server';
|
|
251
|
+
const DEV_MODULE_URL = '/~dev-module';
|
|
252
|
+
const DEV_SERVER_INIT_URL = `${DEV_SERVER_URL}-init`;
|
|
253
253
|
const OPEN_IN_EDITOR_URL = `${DEV_SERVER_URL}-open-in-editor`;
|
|
254
254
|
|
|
255
|
-
const version = '3.0
|
|
255
|
+
const version = '3.1.0';
|
|
256
256
|
|
|
257
257
|
const contentTypes = {"123":"application/vnd.lotus-1-2-3","1km":"application/vnd.1000minds.decision-model+xml","3dml":"text/vnd.in3d.3dml","3ds":"image/x-3ds","3g2":"video/3gpp2","3gp":"video/3gpp","3gpp":"video/3gpp","3mf":"model/3mf","7z":"application/x-7z-compressed","aab":"application/x-authorware-bin","aac":"audio/x-aac","aam":"application/x-authorware-map","aas":"application/x-authorware-seg","abw":"application/x-abiword","ac":"application/vnd.nokia.n-gage.ac+xml","acc":"application/vnd.americandynamics.acc","ace":"application/x-ace-compressed","acu":"application/vnd.acucobol","acutc":"application/vnd.acucorp","adp":"audio/adpcm","aep":"application/vnd.audiograph","afm":"application/x-font-type1","afp":"application/vnd.ibm.modcap","age":"application/vnd.age","ahead":"application/vnd.ahead.space","ai":"application/postscript","aif":"audio/x-aiff","aifc":"audio/x-aiff","aiff":"audio/x-aiff","air":"application/vnd.adobe.air-application-installer-package+zip","ait":"application/vnd.dvb.ait","ami":"application/vnd.amiga.ami","amr":"audio/amr","apk":"application/vnd.android.package-archive","apng":"image/apng","appcache":"text/cache-manifest","application":"application/x-ms-application","apr":"application/vnd.lotus-approach","arc":"application/x-freearc","arj":"application/x-arj","asc":"application/pgp-signature","asf":"video/x-ms-asf","asm":"text/x-asm","aso":"application/vnd.accpac.simply.aso","asx":"video/x-ms-asf","atc":"application/vnd.acucorp","atom":"application/atom+xml","atomcat":"application/atomcat+xml","atomdeleted":"application/atomdeleted+xml","atomsvc":"application/atomsvc+xml","atx":"application/vnd.antix.game-component","au":"audio/basic","avci":"image/avci","avcs":"image/avcs","avi":"video/x-msvideo","avif":"image/avif","aw":"application/applixware","azf":"application/vnd.airzip.filesecure.azf","azs":"application/vnd.airzip.filesecure.azs","azv":"image/vnd.airzip.accelerator.azv","azw":"application/vnd.amazon.ebook","b16":"image/vnd.pco.b16","bat":"application/x-msdownload","bcpio":"application/x-bcpio","bdf":"application/x-font-bdf","bdm":"application/vnd.syncml.dm+wbxml","bdoc":"application/x-bdoc","bed":"application/vnd.realvnc.bed","bh2":"application/vnd.fujitsu.oasysprs","bin":"application/octet-stream","blb":"application/x-blorb","blorb":"application/x-blorb","bmi":"application/vnd.bmi","bmml":"application/vnd.balsamiq.bmml+xml","bmp":"image/x-ms-bmp","book":"application/vnd.framemaker","box":"application/vnd.previewsystems.box","boz":"application/x-bzip2","bpk":"application/octet-stream","bsp":"model/vnd.valve.source.compiled-map","btif":"image/prs.btif","buffer":"application/octet-stream","bz":"application/x-bzip","bz2":"application/x-bzip2","c":"text/x-c","c11amc":"application/vnd.cluetrust.cartomobile-config","c11amz":"application/vnd.cluetrust.cartomobile-config-pkg","c4d":"application/vnd.clonk.c4group","c4f":"application/vnd.clonk.c4group","c4g":"application/vnd.clonk.c4group","c4p":"application/vnd.clonk.c4group","c4u":"application/vnd.clonk.c4group","cab":"application/vnd.ms-cab-compressed","caf":"audio/x-caf","cap":"application/vnd.tcpdump.pcap","car":"application/vnd.curl.car","cat":"application/vnd.ms-pki.seccat","cb7":"application/x-cbr","cba":"application/x-cbr","cbr":"application/x-cbr","cbt":"application/x-cbr","cbz":"application/x-cbr","cc":"text/x-c","cco":"application/x-cocoa","cct":"application/x-director","ccxml":"application/ccxml+xml","cdbcmsg":"application/vnd.contact.cmsg","cdf":"application/x-netcdf","cdfx":"application/cdfx+xml","cdkey":"application/vnd.mediastation.cdkey","cdmia":"application/cdmi-capability","cdmic":"application/cdmi-container","cdmid":"application/cdmi-domain","cdmio":"application/cdmi-object","cdmiq":"application/cdmi-queue","cdx":"chemical/x-cdx","cdxml":"application/vnd.chemdraw+xml","cdy":"application/vnd.cinderella","cer":"application/pkix-cert","cfs":"application/x-cfs-compressed","cgm":"image/cgm","chat":"application/x-chat","chm":"application/vnd.ms-htmlhelp","chrt":"application/vnd.kde.kchart","cif":"chemical/x-cif","cii":"application/vnd.anser-web-certificate-issue-initiation","cil":"application/vnd.ms-artgalry","cjs":"application/node","cla":"application/vnd.claymore","class":"application/java-vm","clkk":"application/vnd.crick.clicker.keyboard","clkp":"application/vnd.crick.clicker.palette","clkt":"application/vnd.crick.clicker.template","clkw":"application/vnd.crick.clicker.wordbank","clkx":"application/vnd.crick.clicker","clp":"application/x-msclip","cmc":"application/vnd.cosmocaller","cmdf":"chemical/x-cmdf","cml":"chemical/x-cml","cmp":"application/vnd.yellowriver-custom-menu","cmx":"image/x-cmx","cod":"application/vnd.rim.cod","coffee":"text/coffeescript","com":"application/x-msdownload","conf":"text/plain","cpio":"application/x-cpio","cpl":"application/cpl+xml","cpp":"text/x-c","cpt":"application/mac-compactpro","crd":"application/x-mscardfile","crl":"application/pkix-crl","crt":"application/x-x509-ca-cert","crx":"application/x-chrome-extension","cryptonote":"application/vnd.rig.cryptonote","csh":"application/x-csh","csl":"application/vnd.citationstyles.style+xml","csml":"chemical/x-csml","csp":"application/vnd.commonspace","css":"text/css","cst":"application/x-director","csv":"text/csv","cu":"application/cu-seeme","curl":"text/vnd.curl","cww":"application/prs.cww","cxt":"application/x-director","cxx":"text/x-c","dae":"model/vnd.collada+xml","daf":"application/vnd.mobius.daf","dart":"application/vnd.dart","dataless":"application/vnd.fdsn.seed","davmount":"application/davmount+xml","dbf":"application/vnd.dbf","dbk":"application/docbook+xml","dcr":"application/x-director","dcurl":"text/vnd.curl.dcurl","dd2":"application/vnd.oma.dd2+xml","ddd":"application/vnd.fujixerox.ddd","ddf":"application/vnd.syncml.dmddf+xml","dds":"image/vnd.ms-dds","deb":"application/x-debian-package","def":"text/plain","deploy":"application/octet-stream","der":"application/x-x509-ca-cert","dfac":"application/vnd.dreamfactory","dgc":"application/x-dgc-compressed","dic":"text/x-c","dir":"application/x-director","dis":"application/vnd.mobius.dis","disposition-notification":"message/disposition-notification","dist":"application/octet-stream","distz":"application/octet-stream","djv":"image/vnd.djvu","djvu":"image/vnd.djvu","dll":"application/x-msdownload","dmg":"application/x-apple-diskimage","dmp":"application/vnd.tcpdump.pcap","dms":"application/octet-stream","dna":"application/vnd.dna","doc":"application/msword","docm":"application/vnd.ms-word.document.macroenabled.12","docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document","dot":"application/msword","dotm":"application/vnd.ms-word.template.macroenabled.12","dotx":"application/vnd.openxmlformats-officedocument.wordprocessingml.template","dp":"application/vnd.osgi.dp","dpg":"application/vnd.dpgraph","dra":"audio/vnd.dra","drle":"image/dicom-rle","dsc":"text/prs.lines.tag","dssc":"application/dssc+der","dtb":"application/x-dtbook+xml","dtd":"application/xml-dtd","dts":"audio/vnd.dts","dtshd":"audio/vnd.dts.hd","dump":"application/octet-stream","dvb":"video/vnd.dvb.file","dvi":"application/x-dvi","dwd":"application/atsc-dwd+xml","dwf":"model/vnd.dwf","dwg":"image/vnd.dwg","dxf":"image/vnd.dxf","dxp":"application/vnd.spotfire.dxp","dxr":"application/x-director","ear":"application/java-archive","ecelp4800":"audio/vnd.nuera.ecelp4800","ecelp7470":"audio/vnd.nuera.ecelp7470","ecelp9600":"audio/vnd.nuera.ecelp9600","ecma":"application/ecmascript","edm":"application/vnd.novadigm.edm","edx":"application/vnd.novadigm.edx","efif":"application/vnd.picsel","ei6":"application/vnd.pg.osasli","elc":"application/octet-stream","emf":"image/emf","eml":"message/rfc822","emma":"application/emma+xml","emotionml":"application/emotionml+xml","emz":"application/x-msmetafile","eol":"audio/vnd.digital-winds","eot":"application/vnd.ms-fontobject","eps":"application/postscript","epub":"application/epub+zip","es":"application/ecmascript","es3":"application/vnd.eszigno3+xml","esa":"application/vnd.osgi.subsystem","esf":"application/vnd.epson.esf","et3":"application/vnd.eszigno3+xml","etx":"text/x-setext","eva":"application/x-eva","evy":"application/x-envoy","exe":"application/x-msdownload","exi":"application/exi","exp":"application/express","exr":"image/aces","ext":"application/vnd.novadigm.ext","ez":"application/andrew-inset","ez2":"application/vnd.ezpix-album","ez3":"application/vnd.ezpix-package","f":"text/x-fortran","f4v":"video/x-f4v","f77":"text/x-fortran","f90":"text/x-fortran","fbs":"image/vnd.fastbidsheet","fcdt":"application/vnd.adobe.formscentral.fcdt","fcs":"application/vnd.isac.fcs","fdf":"application/vnd.fdf","fdt":"application/fdt+xml","fe_launch":"application/vnd.denovo.fcselayout-link","fg5":"application/vnd.fujitsu.oasysgp","fgd":"application/x-director","fh":"image/x-freehand","fh4":"image/x-freehand","fh5":"image/x-freehand","fh7":"image/x-freehand","fhc":"image/x-freehand","fig":"application/x-xfig","fits":"image/fits","flac":"audio/x-flac","fli":"video/x-fli","flo":"application/vnd.micrografx.flo","flv":"video/x-flv","flw":"application/vnd.kde.kivio","flx":"text/vnd.fmi.flexstor","fly":"text/vnd.fly","fm":"application/vnd.framemaker","fnc":"application/vnd.frogans.fnc","fo":"application/vnd.software602.filler.form+xml","for":"text/x-fortran","fpx":"image/vnd.fpx","frame":"application/vnd.framemaker","fsc":"application/vnd.fsc.weblaunch","fst":"image/vnd.fst","ftc":"application/vnd.fluxtime.clip","fti":"application/vnd.anser-web-funds-transfer-initiation","fvt":"video/vnd.fvt","fxp":"application/vnd.adobe.fxp","fxpl":"application/vnd.adobe.fxp","fzs":"application/vnd.fuzzysheet","g2w":"application/vnd.geoplan","g3":"image/g3fax","g3w":"application/vnd.geospace","gac":"application/vnd.groove-account","gam":"application/x-tads","gbr":"application/rpki-ghostbusters","gca":"application/x-gca-compressed","gdl":"model/vnd.gdl","gdoc":"application/vnd.google-apps.document","ged":"text/vnd.familysearch.gedcom","geo":"application/vnd.dynageo","geojson":"application/geo+json","gex":"application/vnd.geometry-explorer","ggb":"application/vnd.geogebra.file","ggt":"application/vnd.geogebra.tool","ghf":"application/vnd.groove-help","gif":"image/gif","gim":"application/vnd.groove-identity-message","glb":"model/gltf-binary","gltf":"model/gltf+json","gml":"application/gml+xml","gmx":"application/vnd.gmx","gnumeric":"application/x-gnumeric","gph":"application/vnd.flographit","gpx":"application/gpx+xml","gqf":"application/vnd.grafeq","gqs":"application/vnd.grafeq","gram":"application/srgs","gramps":"application/x-gramps-xml","gre":"application/vnd.geometry-explorer","grv":"application/vnd.groove-injector","grxml":"application/srgs+xml","gsf":"application/x-font-ghostscript","gsheet":"application/vnd.google-apps.spreadsheet","gslides":"application/vnd.google-apps.presentation","gtar":"application/x-gtar","gtm":"application/vnd.groove-tool-message","gtw":"model/vnd.gtw","gv":"text/vnd.graphviz","gxf":"application/gxf","gxt":"application/vnd.geonext","gz":"application/gzip","h":"text/x-c","h261":"video/h261","h263":"video/h263","h264":"video/h264","hal":"application/vnd.hal+xml","hbci":"application/vnd.hbci","hbs":"text/x-handlebars-template","hdd":"application/x-virtualbox-hdd","hdf":"application/x-hdf","heic":"image/heic","heics":"image/heic-sequence","heif":"image/heif","heifs":"image/heif-sequence","hej2":"image/hej2k","held":"application/atsc-held+xml","hh":"text/x-c","hjson":"application/hjson","hlp":"application/winhlp","hpgl":"application/vnd.hp-hpgl","hpid":"application/vnd.hp-hpid","hps":"application/vnd.hp-hps","hqx":"application/mac-binhex40","hsj2":"image/hsj2","htc":"text/x-component","htke":"application/vnd.kenameaapp","htm":"text/html","html":"text/html","hvd":"application/vnd.yamaha.hv-dic","hvp":"application/vnd.yamaha.hv-voice","hvs":"application/vnd.yamaha.hv-script","i2g":"application/vnd.intergeo","icc":"application/vnd.iccprofile","ice":"x-conference/x-cooltalk","icm":"application/vnd.iccprofile","ico":"image/x-icon","ics":"text/calendar","ief":"image/ief","ifb":"text/calendar","ifm":"application/vnd.shana.informed.formdata","iges":"model/iges","igl":"application/vnd.igloader","igm":"application/vnd.insors.igm","igs":"model/iges","igx":"application/vnd.micrografx.igx","iif":"application/vnd.shana.informed.interchange","img":"application/octet-stream","imp":"application/vnd.accpac.simply.imp","ims":"application/vnd.ms-ims","in":"text/plain","ini":"text/plain","ink":"application/inkml+xml","inkml":"application/inkml+xml","install":"application/x-install-instructions","iota":"application/vnd.astraea-software.iota","ipfix":"application/ipfix","ipk":"application/vnd.shana.informed.package","irm":"application/vnd.ibm.rights-management","irp":"application/vnd.irepository.package+xml","iso":"application/x-iso9660-image","itp":"application/vnd.shana.informed.formtemplate","its":"application/its+xml","ivp":"application/vnd.immervision-ivp","ivu":"application/vnd.immervision-ivu","jad":"text/vnd.sun.j2me.app-descriptor","jade":"text/jade","jam":"application/vnd.jam","jar":"application/java-archive","jardiff":"application/x-java-archive-diff","java":"text/x-java-source","jhc":"image/jphc","jisp":"application/vnd.jisp","jls":"image/jls","jlt":"application/vnd.hp-jlyt","jng":"image/x-jng","jnlp":"application/x-java-jnlp-file","joda":"application/vnd.joost.joda-archive","jp2":"image/jp2","jpe":"image/jpeg","jpeg":"image/jpeg","jpf":"image/jpx","jpg":"image/jpeg","jpg2":"image/jp2","jpgm":"video/jpm","jpgv":"video/jpeg","jph":"image/jph","jpm":"video/jpm","jpx":"image/jpx","js":"application/javascript","json":"application/json","json5":"application/json5","jsonld":"application/ld+json","jsonml":"application/jsonml+json","jsx":"text/jsx","jxr":"image/jxr","jxra":"image/jxra","jxrs":"image/jxrs","jxs":"image/jxs","jxsc":"image/jxsc","jxsi":"image/jxsi","jxss":"image/jxss","kar":"audio/midi","karbon":"application/vnd.kde.karbon","kdbx":"application/x-keepass2","key":"application/x-iwork-keynote-sffkey","kfo":"application/vnd.kde.kformula","kia":"application/vnd.kidspiration","kml":"application/vnd.google-earth.kml+xml","kmz":"application/vnd.google-earth.kmz","kne":"application/vnd.kinar","knp":"application/vnd.kinar","kon":"application/vnd.kde.kontour","kpr":"application/vnd.kde.kpresenter","kpt":"application/vnd.kde.kpresenter","kpxx":"application/vnd.ds-keypoint","ksp":"application/vnd.kde.kspread","ktr":"application/vnd.kahootz","ktx":"image/ktx","ktx2":"image/ktx2","ktz":"application/vnd.kahootz","kwd":"application/vnd.kde.kword","kwt":"application/vnd.kde.kword","lasxml":"application/vnd.las.las+xml","latex":"application/x-latex","lbd":"application/vnd.llamagraphics.life-balance.desktop","lbe":"application/vnd.llamagraphics.life-balance.exchange+xml","les":"application/vnd.hhe.lesson-player","less":"text/less","lgr":"application/lgr+xml","lha":"application/x-lzh-compressed","link66":"application/vnd.route66.link66+xml","list":"text/plain","list3820":"application/vnd.ibm.modcap","listafp":"application/vnd.ibm.modcap","litcoffee":"text/coffeescript","lnk":"application/x-ms-shortcut","log":"text/plain","lostxml":"application/lost+xml","lrf":"application/octet-stream","lrm":"application/vnd.ms-lrm","ltf":"application/vnd.frogans.ltf","lua":"text/x-lua","luac":"application/x-lua-bytecode","lvp":"audio/vnd.lucent.voice","lwp":"application/vnd.lotus-wordpro","lzh":"application/x-lzh-compressed","m13":"application/x-msmediaview","m14":"application/x-msmediaview","m1v":"video/mpeg","m21":"application/mp21","m2a":"audio/mpeg","m2v":"video/mpeg","m3a":"audio/mpeg","m3u":"audio/x-mpegurl","m3u8":"application/vnd.apple.mpegurl","m4a":"audio/x-m4a","m4p":"application/mp4","m4s":"video/iso.segment","m4u":"video/vnd.mpegurl","m4v":"video/x-m4v","ma":"application/mathematica","mads":"application/mads+xml","maei":"application/mmt-aei+xml","mag":"application/vnd.ecowin.chart","maker":"application/vnd.framemaker","man":"text/troff","manifest":"text/cache-manifest","map":"application/json","mar":"application/octet-stream","markdown":"text/markdown","mathml":"application/mathml+xml","mb":"application/mathematica","mbk":"application/vnd.mobius.mbk","mbox":"application/mbox","mc1":"application/vnd.medcalcdata","mcd":"application/vnd.mcd","mcurl":"text/vnd.curl.mcurl","md":"text/markdown","mdb":"application/x-msaccess","mdi":"image/vnd.ms-modi","mdx":"text/mdx","me":"text/troff","mesh":"model/mesh","meta4":"application/metalink4+xml","metalink":"application/metalink+xml","mets":"application/mets+xml","mfm":"application/vnd.mfmp","mft":"application/rpki-manifest","mgp":"application/vnd.osgeo.mapguide.package","mgz":"application/vnd.proteus.magazine","mid":"audio/midi","midi":"audio/midi","mie":"application/x-mie","mif":"application/vnd.mif","mime":"message/rfc822","mj2":"video/mj2","mjp2":"video/mj2","mjs":"application/javascript","mk3d":"video/x-matroska","mka":"audio/x-matroska","mkd":"text/x-markdown","mks":"video/x-matroska","mkv":"video/x-matroska","mlp":"application/vnd.dolby.mlp","mmd":"application/vnd.chipnuts.karaoke-mmd","mmf":"application/vnd.smaf","mml":"text/mathml","mmr":"image/vnd.fujixerox.edmics-mmr","mng":"video/x-mng","mny":"application/x-msmoney","mobi":"application/x-mobipocket-ebook","mods":"application/mods+xml","mov":"video/quicktime","movie":"video/x-sgi-movie","mp2":"audio/mpeg","mp21":"application/mp21","mp2a":"audio/mpeg","mp3":"audio/mpeg","mp4":"video/mp4","mp4a":"audio/mp4","mp4s":"application/mp4","mp4v":"video/mp4","mpc":"application/vnd.mophun.certificate","mpd":"application/dash+xml","mpe":"video/mpeg","mpeg":"video/mpeg","mpf":"application/media-policy-dataset+xml","mpg":"video/mpeg","mpg4":"video/mp4","mpga":"audio/mpeg","mpkg":"application/vnd.apple.installer+xml","mpm":"application/vnd.blueice.multipass","mpn":"application/vnd.mophun.application","mpp":"application/vnd.ms-project","mpt":"application/vnd.ms-project","mpy":"application/vnd.ibm.minipay","mqy":"application/vnd.mobius.mqy","mrc":"application/marc","mrcx":"application/marcxml+xml","ms":"text/troff","mscml":"application/mediaservercontrol+xml","mseed":"application/vnd.fdsn.mseed","mseq":"application/vnd.mseq","msf":"application/vnd.epson.msf","msg":"application/vnd.ms-outlook","msh":"model/mesh","msi":"application/x-msdownload","msl":"application/vnd.mobius.msl","msm":"application/octet-stream","msp":"application/octet-stream","msty":"application/vnd.muvee.style","mtl":"model/mtl","mts":"model/vnd.mts","mus":"application/vnd.musician","musd":"application/mmt-usd+xml","musicxml":"application/vnd.recordare.musicxml+xml","mvb":"application/x-msmediaview","mvt":"application/vnd.mapbox-vector-tile","mwf":"application/vnd.mfer","mxf":"application/mxf","mxl":"application/vnd.recordare.musicxml","mxmf":"audio/mobile-xmf","mxml":"application/xv+xml","mxs":"application/vnd.triscape.mxs","mxu":"video/vnd.mpegurl","n-gage":"application/vnd.nokia.n-gage.symbian.install","n3":"text/n3","nb":"application/mathematica","nbp":"application/vnd.wolfram.player","nc":"application/x-netcdf","ncx":"application/x-dtbncx+xml","nfo":"text/x-nfo","ngdat":"application/vnd.nokia.n-gage.data","nitf":"application/vnd.nitf","nlu":"application/vnd.neurolanguage.nlu","nml":"application/vnd.enliven","nnd":"application/vnd.noblenet-directory","nns":"application/vnd.noblenet-sealer","nnw":"application/vnd.noblenet-web","npx":"image/vnd.net-fpx","nq":"application/n-quads","nsc":"application/x-conference","nsf":"application/vnd.lotus-notes","nt":"application/n-triples","ntf":"application/vnd.nitf","numbers":"application/x-iwork-numbers-sffnumbers","nzb":"application/x-nzb","oa2":"application/vnd.fujitsu.oasys2","oa3":"application/vnd.fujitsu.oasys3","oas":"application/vnd.fujitsu.oasys","obd":"application/x-msbinder","obgx":"application/vnd.openblox.game+xml","obj":"model/obj","oda":"application/oda","odb":"application/vnd.oasis.opendocument.database","odc":"application/vnd.oasis.opendocument.chart","odf":"application/vnd.oasis.opendocument.formula","odft":"application/vnd.oasis.opendocument.formula-template","odg":"application/vnd.oasis.opendocument.graphics","odi":"application/vnd.oasis.opendocument.image","odm":"application/vnd.oasis.opendocument.text-master","odp":"application/vnd.oasis.opendocument.presentation","ods":"application/vnd.oasis.opendocument.spreadsheet","odt":"application/vnd.oasis.opendocument.text","oga":"audio/ogg","ogex":"model/vnd.opengex","ogg":"audio/ogg","ogv":"video/ogg","ogx":"application/ogg","omdoc":"application/omdoc+xml","onepkg":"application/onenote","onetmp":"application/onenote","onetoc":"application/onenote","onetoc2":"application/onenote","opf":"application/oebps-package+xml","opml":"text/x-opml","oprc":"application/vnd.palm","opus":"audio/ogg","org":"text/x-org","osf":"application/vnd.yamaha.openscoreformat","osfpvg":"application/vnd.yamaha.openscoreformat.osfpvg+xml","osm":"application/vnd.openstreetmap.data+xml","otc":"application/vnd.oasis.opendocument.chart-template","otf":"font/otf","otg":"application/vnd.oasis.opendocument.graphics-template","oth":"application/vnd.oasis.opendocument.text-web","oti":"application/vnd.oasis.opendocument.image-template","otp":"application/vnd.oasis.opendocument.presentation-template","ots":"application/vnd.oasis.opendocument.spreadsheet-template","ott":"application/vnd.oasis.opendocument.text-template","ova":"application/x-virtualbox-ova","ovf":"application/x-virtualbox-ovf","owl":"application/rdf+xml","oxps":"application/oxps","oxt":"application/vnd.openofficeorg.extension","p":"text/x-pascal","p10":"application/pkcs10","p12":"application/x-pkcs12","p7b":"application/x-pkcs7-certificates","p7c":"application/pkcs7-mime","p7m":"application/pkcs7-mime","p7r":"application/x-pkcs7-certreqresp","p7s":"application/pkcs7-signature","p8":"application/pkcs8","pac":"application/x-ns-proxy-autoconfig","pages":"application/x-iwork-pages-sffpages","pas":"text/x-pascal","paw":"application/vnd.pawaafile","pbd":"application/vnd.powerbuilder6","pbm":"image/x-portable-bitmap","pcap":"application/vnd.tcpdump.pcap","pcf":"application/x-font-pcf","pcl":"application/vnd.hp-pcl","pclxl":"application/vnd.hp-pclxl","pct":"image/x-pict","pcurl":"application/vnd.curl.pcurl","pcx":"image/x-pcx","pdb":"application/x-pilot","pde":"text/x-processing","pdf":"application/pdf","pem":"application/x-x509-ca-cert","pfa":"application/x-font-type1","pfb":"application/x-font-type1","pfm":"application/x-font-type1","pfr":"application/font-tdpfr","pfx":"application/x-pkcs12","pgm":"image/x-portable-graymap","pgn":"application/x-chess-pgn","pgp":"application/pgp-encrypted","php":"application/x-httpd-php","pic":"image/x-pict","pkg":"application/octet-stream","pki":"application/pkixcmp","pkipath":"application/pkix-pkipath","pkpass":"application/vnd.apple.pkpass","pl":"application/x-perl","plb":"application/vnd.3gpp.pic-bw-large","plc":"application/vnd.mobius.plc","plf":"application/vnd.pocketlearn","pls":"application/pls+xml","pm":"application/x-perl","pml":"application/vnd.ctc-posml","png":"image/png","pnm":"image/x-portable-anymap","portpkg":"application/vnd.macports.portpkg","pot":"application/vnd.ms-powerpoint","potm":"application/vnd.ms-powerpoint.template.macroenabled.12","potx":"application/vnd.openxmlformats-officedocument.presentationml.template","ppam":"application/vnd.ms-powerpoint.addin.macroenabled.12","ppd":"application/vnd.cups-ppd","ppm":"image/x-portable-pixmap","pps":"application/vnd.ms-powerpoint","ppsm":"application/vnd.ms-powerpoint.slideshow.macroenabled.12","ppsx":"application/vnd.openxmlformats-officedocument.presentationml.slideshow","ppt":"application/vnd.ms-powerpoint","pptm":"application/vnd.ms-powerpoint.presentation.macroenabled.12","pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation","pqa":"application/vnd.palm","prc":"application/x-pilot","pre":"application/vnd.lotus-freelance","prf":"application/pics-rules","provx":"application/provenance+xml","ps":"application/postscript","psb":"application/vnd.3gpp.pic-bw-small","psd":"image/vnd.adobe.photoshop","psf":"application/x-font-linux-psf","pskcxml":"application/pskc+xml","pti":"image/prs.pti","ptid":"application/vnd.pvi.ptid1","pub":"application/x-mspublisher","pvb":"application/vnd.3gpp.pic-bw-var","pwn":"application/vnd.3m.post-it-notes","pya":"audio/vnd.ms-playready.media.pya","pyv":"video/vnd.ms-playready.media.pyv","qam":"application/vnd.epson.quickanime","qbo":"application/vnd.intu.qbo","qfx":"application/vnd.intu.qfx","qps":"application/vnd.publishare-delta-tree","qt":"video/quicktime","qwd":"application/vnd.quark.quarkxpress","qwt":"application/vnd.quark.quarkxpress","qxb":"application/vnd.quark.quarkxpress","qxd":"application/vnd.quark.quarkxpress","qxl":"application/vnd.quark.quarkxpress","qxt":"application/vnd.quark.quarkxpress","ra":"audio/x-realaudio","ram":"audio/x-pn-realaudio","raml":"application/raml+yaml","rapd":"application/route-apd+xml","rar":"application/x-rar-compressed","ras":"image/x-cmu-raster","rcprofile":"application/vnd.ipunplugged.rcprofile","rdf":"application/rdf+xml","rdz":"application/vnd.data-vision.rdz","relo":"application/p2p-overlay+xml","rep":"application/vnd.businessobjects","res":"application/x-dtbresource+xml","rgb":"image/x-rgb","rif":"application/reginfo+xml","rip":"audio/vnd.rip","ris":"application/x-research-info-systems","rl":"application/resource-lists+xml","rlc":"image/vnd.fujixerox.edmics-rlc","rld":"application/resource-lists-diff+xml","rm":"application/vnd.rn-realmedia","rmi":"audio/midi","rmp":"audio/x-pn-realaudio-plugin","rms":"application/vnd.jcp.javame.midlet-rms","rmvb":"application/vnd.rn-realmedia-vbr","rnc":"application/relax-ng-compact-syntax","rng":"application/xml","roa":"application/rpki-roa","roff":"text/troff","rp9":"application/vnd.cloanto.rp9","rpm":"application/x-redhat-package-manager","rpss":"application/vnd.nokia.radio-presets","rpst":"application/vnd.nokia.radio-preset","rq":"application/sparql-query","rs":"application/rls-services+xml","rsat":"application/atsc-rsat+xml","rsd":"application/rsd+xml","rsheet":"application/urc-ressheet+xml","rss":"application/rss+xml","rtf":"text/rtf","rtx":"text/richtext","run":"application/x-makeself","rusd":"application/route-usd+xml","s":"text/x-asm","s3m":"audio/s3m","saf":"application/vnd.yamaha.smaf-audio","sass":"text/x-sass","sbml":"application/sbml+xml","sc":"application/vnd.ibm.secure-container","scd":"application/x-msschedule","scm":"application/vnd.lotus-screencam","scq":"application/scvp-cv-request","scs":"application/scvp-cv-response","scss":"text/x-scss","scurl":"text/vnd.curl.scurl","sda":"application/vnd.stardivision.draw","sdc":"application/vnd.stardivision.calc","sdd":"application/vnd.stardivision.impress","sdkd":"application/vnd.solent.sdkm+xml","sdkm":"application/vnd.solent.sdkm+xml","sdp":"application/sdp","sdw":"application/vnd.stardivision.writer","sea":"application/x-sea","see":"application/vnd.seemail","seed":"application/vnd.fdsn.seed","sema":"application/vnd.sema","semd":"application/vnd.semd","semf":"application/vnd.semf","senmlx":"application/senml+xml","sensmlx":"application/sensml+xml","ser":"application/java-serialized-object","setpay":"application/set-payment-initiation","setreg":"application/set-registration-initiation","sfd-hdstx":"application/vnd.hydrostatix.sof-data","sfs":"application/vnd.spotfire.sfs","sfv":"text/x-sfv","sgi":"image/sgi","sgl":"application/vnd.stardivision.writer-global","sgm":"text/sgml","sgml":"text/sgml","sh":"application/x-sh","shar":"application/x-shar","shex":"text/shex","shf":"application/shf+xml","shtml":"text/html","sid":"image/x-mrsid-image","sieve":"application/sieve","sig":"application/pgp-signature","sil":"audio/silk","silo":"model/mesh","sis":"application/vnd.symbian.install","sisx":"application/vnd.symbian.install","sit":"application/x-stuffit","sitx":"application/x-stuffitx","siv":"application/sieve","skd":"application/vnd.koan","skm":"application/vnd.koan","skp":"application/vnd.koan","skt":"application/vnd.koan","sldm":"application/vnd.ms-powerpoint.slide.macroenabled.12","sldx":"application/vnd.openxmlformats-officedocument.presentationml.slide","slim":"text/slim","slm":"text/slim","sls":"application/route-s-tsid+xml","slt":"application/vnd.epson.salt","sm":"application/vnd.stepmania.stepchart","smf":"application/vnd.stardivision.math","smi":"application/smil+xml","smil":"application/smil+xml","smv":"video/x-smv","smzip":"application/vnd.stepmania.package","snd":"audio/basic","snf":"application/x-font-snf","so":"application/octet-stream","spc":"application/x-pkcs7-certificates","spdx":"text/spdx","spf":"application/vnd.yamaha.smaf-phrase","spl":"application/x-futuresplash","spot":"text/vnd.in3d.spot","spp":"application/scvp-vp-response","spq":"application/scvp-vp-request","spx":"audio/ogg","sql":"application/x-sql","src":"application/x-wais-source","srt":"application/x-subrip","sru":"application/sru+xml","srx":"application/sparql-results+xml","ssdl":"application/ssdl+xml","sse":"application/vnd.kodak-descriptor","ssf":"application/vnd.epson.ssf","ssml":"application/ssml+xml","st":"application/vnd.sailingtracker.track","stc":"application/vnd.sun.xml.calc.template","std":"application/vnd.sun.xml.draw.template","stf":"application/vnd.wt.stf","sti":"application/vnd.sun.xml.impress.template","stk":"application/hyperstudio","stl":"model/stl","stpx":"model/step+xml","stpxz":"model/step-xml+zip","stpz":"model/step+zip","str":"application/vnd.pg.format","stw":"application/vnd.sun.xml.writer.template","styl":"text/stylus","stylus":"text/stylus","sub":"text/vnd.dvb.subtitle","sus":"application/vnd.sus-calendar","susp":"application/vnd.sus-calendar","sv4cpio":"application/x-sv4cpio","sv4crc":"application/x-sv4crc","svc":"application/vnd.dvb.service","svd":"application/vnd.svd","svg":"image/svg+xml","svgz":"image/svg+xml","swa":"application/x-director","swf":"application/x-shockwave-flash","swi":"application/vnd.aristanetworks.swi","swidtag":"application/swid+xml","sxc":"application/vnd.sun.xml.calc","sxd":"application/vnd.sun.xml.draw","sxg":"application/vnd.sun.xml.writer.global","sxi":"application/vnd.sun.xml.impress","sxm":"application/vnd.sun.xml.math","sxw":"application/vnd.sun.xml.writer","t":"text/troff","t3":"application/x-t3vm-image","t38":"image/t38","taglet":"application/vnd.mynfc","tao":"application/vnd.tao.intent-module-archive","tap":"image/vnd.tencent.tap","tar":"application/x-tar","tcap":"application/vnd.3gpp2.tcap","tcl":"application/x-tcl","td":"application/urc-targetdesc+xml","teacher":"application/vnd.smart.teacher","tei":"application/tei+xml","teicorpus":"application/tei+xml","tex":"application/x-tex","texi":"application/x-texinfo","texinfo":"application/x-texinfo","text":"text/plain","tfi":"application/thraud+xml","tfm":"application/x-tex-tfm","tfx":"image/tiff-fx","tga":"image/x-tga","thmx":"application/vnd.ms-officetheme","tif":"image/tiff","tiff":"image/tiff","tk":"application/x-tcl","tmo":"application/vnd.tmobile-livetv","toml":"application/toml","torrent":"application/x-bittorrent","tpl":"application/vnd.groove-tool-template","tpt":"application/vnd.trid.tpt","tr":"text/troff","tra":"application/vnd.trueapp","trig":"application/trig","trm":"application/x-msterminal","ts":"video/mp2t","tsd":"application/timestamped-data","tsv":"text/tab-separated-values","ttc":"font/collection","ttf":"font/ttf","ttl":"text/turtle","ttml":"application/ttml+xml","twd":"application/vnd.simtech-mindmapper","twds":"application/vnd.simtech-mindmapper","txd":"application/vnd.genomatix.tuxedo","txf":"application/vnd.mobius.txf","txt":"text/plain","u32":"application/x-authorware-bin","u8dsn":"message/global-delivery-status","u8hdr":"message/global-headers","u8mdn":"message/global-disposition-notification","u8msg":"message/global","ubj":"application/ubjson","udeb":"application/x-debian-package","ufd":"application/vnd.ufdl","ufdl":"application/vnd.ufdl","ulx":"application/x-glulx","umj":"application/vnd.umajin","unityweb":"application/vnd.unity","uoml":"application/vnd.uoml+xml","uri":"text/uri-list","uris":"text/uri-list","urls":"text/uri-list","usdz":"model/vnd.usdz+zip","ustar":"application/x-ustar","utz":"application/vnd.uiq.theme","uu":"text/x-uuencode","uva":"audio/vnd.dece.audio","uvd":"application/vnd.dece.data","uvf":"application/vnd.dece.data","uvg":"image/vnd.dece.graphic","uvh":"video/vnd.dece.hd","uvi":"image/vnd.dece.graphic","uvm":"video/vnd.dece.mobile","uvp":"video/vnd.dece.pd","uvs":"video/vnd.dece.sd","uvt":"application/vnd.dece.ttml+xml","uvu":"video/vnd.uvvu.mp4","uvv":"video/vnd.dece.video","uvva":"audio/vnd.dece.audio","uvvd":"application/vnd.dece.data","uvvf":"application/vnd.dece.data","uvvg":"image/vnd.dece.graphic","uvvh":"video/vnd.dece.hd","uvvi":"image/vnd.dece.graphic","uvvm":"video/vnd.dece.mobile","uvvp":"video/vnd.dece.pd","uvvs":"video/vnd.dece.sd","uvvt":"application/vnd.dece.ttml+xml","uvvu":"video/vnd.uvvu.mp4","uvvv":"video/vnd.dece.video","uvvx":"application/vnd.dece.unspecified","uvvz":"application/vnd.dece.zip","uvx":"application/vnd.dece.unspecified","uvz":"application/vnd.dece.zip","vbox":"application/x-virtualbox-vbox","vbox-extpack":"application/x-virtualbox-vbox-extpack","vcard":"text/vcard","vcd":"application/x-cdlink","vcf":"text/x-vcard","vcg":"application/vnd.groove-vcard","vcs":"text/x-vcalendar","vcx":"application/vnd.vcx","vdi":"application/x-virtualbox-vdi","vds":"model/vnd.sap.vds","vhd":"application/x-virtualbox-vhd","vis":"application/vnd.visionary","viv":"video/vnd.vivo","vmdk":"application/x-virtualbox-vmdk","vob":"video/x-ms-vob","vor":"application/vnd.stardivision.writer","vox":"application/x-authorware-bin","vrml":"model/vrml","vsd":"application/vnd.visio","vsf":"application/vnd.vsf","vss":"application/vnd.visio","vst":"application/vnd.visio","vsw":"application/vnd.visio","vtf":"image/vnd.valve.source.texture","vtt":"text/vtt","vtu":"model/vnd.vtu","vxml":"application/voicexml+xml","w3d":"application/x-director","wad":"application/x-doom","wadl":"application/vnd.sun.wadl+xml","war":"application/java-archive","wasm":"application/wasm","wav":"audio/x-wav","wax":"audio/x-ms-wax","wbmp":"image/vnd.wap.wbmp","wbs":"application/vnd.criticaltools.wbs+xml","wbxml":"application/vnd.wap.wbxml","wcm":"application/vnd.ms-works","wdb":"application/vnd.ms-works","wdp":"image/vnd.ms-photo","weba":"audio/webm","webapp":"application/x-web-app-manifest+json","webm":"video/webm","webmanifest":"application/manifest+json","webp":"image/webp","wg":"application/vnd.pmi.widget","wgt":"application/widget","wif":"application/watcherinfo+xml","wks":"application/vnd.ms-works","wm":"video/x-ms-wm","wma":"audio/x-ms-wma","wmd":"application/x-ms-wmd","wmf":"image/wmf","wml":"text/vnd.wap.wml","wmlc":"application/vnd.wap.wmlc","wmls":"text/vnd.wap.wmlscript","wmlsc":"application/vnd.wap.wmlscriptc","wmv":"video/x-ms-wmv","wmx":"video/x-ms-wmx","wmz":"application/x-msmetafile","woff":"font/woff","woff2":"font/woff2","wpd":"application/vnd.wordperfect","wpl":"application/vnd.ms-wpl","wps":"application/vnd.ms-works","wqd":"application/vnd.wqd","wri":"application/x-mswrite","wrl":"model/vrml","wsc":"message/vnd.wfa.wsc","wsdl":"application/wsdl+xml","wspolicy":"application/wspolicy+xml","wtb":"application/vnd.webturbo","wvx":"video/x-ms-wvx","x32":"application/x-authorware-bin","x3d":"model/x3d+xml","x3db":"model/x3d+fastinfoset","x3dbz":"model/x3d+binary","x3dv":"model/x3d-vrml","x3dvz":"model/x3d+vrml","x3dz":"model/x3d+xml","x_b":"model/vnd.parasolid.transmit.binary","x_t":"model/vnd.parasolid.transmit.text","xaml":"application/xaml+xml","xap":"application/x-silverlight-app","xar":"application/vnd.xara","xav":"application/xcap-att+xml","xbap":"application/x-ms-xbap","xbd":"application/vnd.fujixerox.docuworks.binder","xbm":"image/x-xbitmap","xca":"application/xcap-caps+xml","xcs":"application/calendar+xml","xdf":"application/xcap-diff+xml","xdm":"application/vnd.syncml.dm+xml","xdp":"application/vnd.adobe.xdp+xml","xdssc":"application/dssc+xml","xdw":"application/vnd.fujixerox.docuworks","xel":"application/xcap-el+xml","xenc":"application/xenc+xml","xer":"application/patch-ops-error+xml","xfdf":"application/vnd.adobe.xfdf","xfdl":"application/vnd.xfdl","xht":"application/xhtml+xml","xhtml":"application/xhtml+xml","xhvml":"application/xv+xml","xif":"image/vnd.xiff","xla":"application/vnd.ms-excel","xlam":"application/vnd.ms-excel.addin.macroenabled.12","xlc":"application/vnd.ms-excel","xlf":"application/xliff+xml","xlm":"application/vnd.ms-excel","xls":"application/vnd.ms-excel","xlsb":"application/vnd.ms-excel.sheet.binary.macroenabled.12","xlsm":"application/vnd.ms-excel.sheet.macroenabled.12","xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","xlt":"application/vnd.ms-excel","xltm":"application/vnd.ms-excel.template.macroenabled.12","xltx":"application/vnd.openxmlformats-officedocument.spreadsheetml.template","xlw":"application/vnd.ms-excel","xm":"audio/xm","xml":"text/xml","xns":"application/xcap-ns+xml","xo":"application/vnd.olpc-sugar","xop":"application/xop+xml","xpi":"application/x-xpinstall","xpl":"application/xproc+xml","xpm":"image/x-xpixmap","xpr":"application/vnd.is-xpr","xps":"application/vnd.ms-xpsdocument","xpw":"application/vnd.intercon.formnet","xpx":"application/vnd.intercon.formnet","xsd":"application/xml","xsl":"application/xslt+xml","xslt":"application/xslt+xml","xsm":"application/vnd.syncml+xml","xspf":"application/xspf+xml","xul":"application/vnd.mozilla.xul+xml","xvm":"application/xv+xml","xvml":"application/xv+xml","xwd":"image/x-xwindowdump","xyz":"chemical/x-xyz","xz":"application/x-xz","yaml":"text/yaml","yang":"application/yang","yin":"application/yin+xml","yml":"text/yaml","ymp":"text/x-suse-ymp","z1":"application/x-zmachine","z2":"application/x-zmachine","z3":"application/x-zmachine","z4":"application/x-zmachine","z5":"application/x-zmachine","z6":"application/x-zmachine","z7":"application/x-zmachine","z8":"application/x-zmachine","zaz":"application/vnd.zzazz.deck+xml","zip":"application/zip","zir":"application/vnd.zul","zirz":"application/vnd.zul","zmm":"application/vnd.handheld-entertainment+xml"};
|
|
258
258
|
|
|
259
|
-
function responseHeaders(headers, httpCache = false) {
|
|
260
|
-
headers = { ...DEFAULT_HEADERS, ...headers };
|
|
261
|
-
if (httpCache) {
|
|
262
|
-
headers['cache-control'] = 'max-age=3600';
|
|
263
|
-
delete headers['date'];
|
|
264
|
-
delete headers['expires'];
|
|
265
|
-
}
|
|
266
|
-
return headers;
|
|
267
|
-
}
|
|
268
|
-
const DEFAULT_HEADERS = {
|
|
269
|
-
'cache-control': 'no-cache, no-store, must-revalidate, max-age=0',
|
|
270
|
-
expires: '0',
|
|
271
|
-
date: 'Wed, 1 Jan 2000 00:00:00 GMT',
|
|
272
|
-
server: 'Rindo Dev Server ' + version,
|
|
273
|
-
'access-control-allow-origin': '*',
|
|
274
|
-
'access-control-expose-headers': '*',
|
|
275
|
-
};
|
|
276
|
-
function getBrowserUrl(protocol, address, port, basePath, pathname) {
|
|
277
|
-
address = address === `0.0.0.0` ? `localhost` : address;
|
|
278
|
-
const portSuffix = !port || port === 80 || port === 443 ? '' : ':' + port;
|
|
279
|
-
let path = basePath;
|
|
280
|
-
if (pathname.startsWith('/')) {
|
|
281
|
-
pathname = pathname.substring(1);
|
|
282
|
-
}
|
|
283
|
-
path += pathname;
|
|
284
|
-
protocol = protocol.replace(/\:/g, '');
|
|
285
|
-
return `${protocol}://${address}${portSuffix}${path}`;
|
|
286
|
-
}
|
|
287
|
-
function getDevServerClientUrl(devServerConfig, host, protocol) {
|
|
288
|
-
let address = devServerConfig.address;
|
|
289
|
-
let port = devServerConfig.port;
|
|
290
|
-
if (host) {
|
|
291
|
-
address = host;
|
|
292
|
-
port = null;
|
|
293
|
-
}
|
|
294
|
-
return getBrowserUrl(protocol !== null && protocol !== void 0 ? protocol : devServerConfig.protocol, address, port, devServerConfig.basePath, DEV_SERVER_URL);
|
|
295
|
-
}
|
|
296
|
-
function getContentType(filePath) {
|
|
297
|
-
const last = filePath.replace(/^.*[/\\]/, '').toLowerCase();
|
|
298
|
-
const ext = last.replace(/^.*\./, '').toLowerCase();
|
|
299
|
-
const hasPath = last.length < filePath.length;
|
|
300
|
-
const hasDot = ext.length < last.length - 1;
|
|
301
|
-
return ((hasDot || !hasPath) && contentTypes[ext]) || 'application/octet-stream';
|
|
302
|
-
}
|
|
303
|
-
function isHtmlFile(filePath) {
|
|
304
|
-
filePath = filePath.toLowerCase().trim();
|
|
305
|
-
return filePath.endsWith('.html') || filePath.endsWith('.htm');
|
|
306
|
-
}
|
|
307
|
-
function isCssFile(filePath) {
|
|
308
|
-
filePath = filePath.toLowerCase().trim();
|
|
309
|
-
return filePath.endsWith('.css');
|
|
310
|
-
}
|
|
311
|
-
const TXT_EXT = ['css', 'html', 'htm', 'js', 'json', 'svg', 'xml'];
|
|
312
|
-
function isSimpleText(filePath) {
|
|
313
|
-
const ext = filePath.toLowerCase().trim().split('.').pop();
|
|
314
|
-
return TXT_EXT.includes(ext);
|
|
315
|
-
}
|
|
316
|
-
function isExtensionLessPath(pathname) {
|
|
317
|
-
const parts = pathname.split('/');
|
|
318
|
-
const lastPart = parts[parts.length - 1];
|
|
319
|
-
return !lastPart.includes('.');
|
|
320
|
-
}
|
|
321
|
-
function isSsrStaticDataPath(pathname) {
|
|
322
|
-
const parts = pathname.split('/');
|
|
323
|
-
const fileName = parts[parts.length - 1].split('?')[0];
|
|
324
|
-
return fileName === 'page.state.json';
|
|
325
|
-
}
|
|
326
|
-
function getSsrStaticDataPath(req) {
|
|
327
|
-
const parts = req.url.href.split('/');
|
|
328
|
-
const fileName = parts[parts.length - 1];
|
|
329
|
-
const fileNameParts = fileName.split('?');
|
|
330
|
-
parts.pop();
|
|
331
|
-
let ssrPath = new URL(parts.join('/')).href;
|
|
332
|
-
if (!ssrPath.endsWith('/') && req.headers) {
|
|
333
|
-
const h = new Headers(req.headers);
|
|
334
|
-
if (h.get('referer').endsWith('/')) {
|
|
335
|
-
ssrPath += '/';
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
return {
|
|
339
|
-
ssrPath,
|
|
340
|
-
fileName: fileNameParts[0],
|
|
341
|
-
hasQueryString: typeof fileNameParts[1] === 'string' && fileNameParts[1].length > 0,
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
function isDevClient(pathname) {
|
|
345
|
-
return pathname.startsWith(DEV_SERVER_URL);
|
|
346
|
-
}
|
|
347
|
-
function isDevModule(pathname) {
|
|
348
|
-
return pathname.includes(DEV_MODULE_URL);
|
|
349
|
-
}
|
|
350
|
-
function isOpenInEditor(pathname) {
|
|
351
|
-
return pathname === OPEN_IN_EDITOR_URL;
|
|
352
|
-
}
|
|
353
|
-
function isInitialDevServerLoad(pathname) {
|
|
354
|
-
return pathname === DEV_SERVER_INIT_URL;
|
|
355
|
-
}
|
|
356
|
-
function isDevServerClient(pathname) {
|
|
357
|
-
return pathname === DEV_SERVER_URL;
|
|
358
|
-
}
|
|
359
|
-
function shouldCompress(devServerConfig, req) {
|
|
360
|
-
if (!devServerConfig.gzip) {
|
|
361
|
-
return false;
|
|
362
|
-
}
|
|
363
|
-
if (req.method !== 'GET') {
|
|
364
|
-
return false;
|
|
365
|
-
}
|
|
366
|
-
const acceptEncoding = req.headers && req.headers['accept-encoding'];
|
|
367
|
-
if (typeof acceptEncoding !== 'string') {
|
|
368
|
-
return false;
|
|
369
|
-
}
|
|
370
|
-
if (!acceptEncoding.includes('gzip')) {
|
|
371
|
-
return false;
|
|
372
|
-
}
|
|
373
|
-
return true;
|
|
259
|
+
function responseHeaders(headers, httpCache = false) {
|
|
260
|
+
headers = { ...DEFAULT_HEADERS, ...headers };
|
|
261
|
+
if (httpCache) {
|
|
262
|
+
headers['cache-control'] = 'max-age=3600';
|
|
263
|
+
delete headers['date'];
|
|
264
|
+
delete headers['expires'];
|
|
265
|
+
}
|
|
266
|
+
return headers;
|
|
267
|
+
}
|
|
268
|
+
const DEFAULT_HEADERS = {
|
|
269
|
+
'cache-control': 'no-cache, no-store, must-revalidate, max-age=0',
|
|
270
|
+
expires: '0',
|
|
271
|
+
date: 'Wed, 1 Jan 2000 00:00:00 GMT',
|
|
272
|
+
server: 'Rindo Dev Server ' + version,
|
|
273
|
+
'access-control-allow-origin': '*',
|
|
274
|
+
'access-control-expose-headers': '*',
|
|
275
|
+
};
|
|
276
|
+
function getBrowserUrl(protocol, address, port, basePath, pathname) {
|
|
277
|
+
address = address === `0.0.0.0` ? `localhost` : address;
|
|
278
|
+
const portSuffix = !port || port === 80 || port === 443 ? '' : ':' + port;
|
|
279
|
+
let path = basePath;
|
|
280
|
+
if (pathname.startsWith('/')) {
|
|
281
|
+
pathname = pathname.substring(1);
|
|
282
|
+
}
|
|
283
|
+
path += pathname;
|
|
284
|
+
protocol = protocol.replace(/\:/g, '');
|
|
285
|
+
return `${protocol}://${address}${portSuffix}${path}`;
|
|
286
|
+
}
|
|
287
|
+
function getDevServerClientUrl(devServerConfig, host, protocol) {
|
|
288
|
+
let address = devServerConfig.address;
|
|
289
|
+
let port = devServerConfig.port;
|
|
290
|
+
if (host) {
|
|
291
|
+
address = host;
|
|
292
|
+
port = null;
|
|
293
|
+
}
|
|
294
|
+
return getBrowserUrl(protocol !== null && protocol !== void 0 ? protocol : devServerConfig.protocol, address, port, devServerConfig.basePath, DEV_SERVER_URL);
|
|
295
|
+
}
|
|
296
|
+
function getContentType(filePath) {
|
|
297
|
+
const last = filePath.replace(/^.*[/\\]/, '').toLowerCase();
|
|
298
|
+
const ext = last.replace(/^.*\./, '').toLowerCase();
|
|
299
|
+
const hasPath = last.length < filePath.length;
|
|
300
|
+
const hasDot = ext.length < last.length - 1;
|
|
301
|
+
return ((hasDot || !hasPath) && contentTypes[ext]) || 'application/octet-stream';
|
|
302
|
+
}
|
|
303
|
+
function isHtmlFile(filePath) {
|
|
304
|
+
filePath = filePath.toLowerCase().trim();
|
|
305
|
+
return filePath.endsWith('.html') || filePath.endsWith('.htm');
|
|
306
|
+
}
|
|
307
|
+
function isCssFile(filePath) {
|
|
308
|
+
filePath = filePath.toLowerCase().trim();
|
|
309
|
+
return filePath.endsWith('.css');
|
|
310
|
+
}
|
|
311
|
+
const TXT_EXT = ['css', 'html', 'htm', 'js', 'json', 'svg', 'xml'];
|
|
312
|
+
function isSimpleText(filePath) {
|
|
313
|
+
const ext = filePath.toLowerCase().trim().split('.').pop();
|
|
314
|
+
return TXT_EXT.includes(ext);
|
|
315
|
+
}
|
|
316
|
+
function isExtensionLessPath(pathname) {
|
|
317
|
+
const parts = pathname.split('/');
|
|
318
|
+
const lastPart = parts[parts.length - 1];
|
|
319
|
+
return !lastPart.includes('.');
|
|
320
|
+
}
|
|
321
|
+
function isSsrStaticDataPath(pathname) {
|
|
322
|
+
const parts = pathname.split('/');
|
|
323
|
+
const fileName = parts[parts.length - 1].split('?')[0];
|
|
324
|
+
return fileName === 'page.state.json';
|
|
325
|
+
}
|
|
326
|
+
function getSsrStaticDataPath(req) {
|
|
327
|
+
const parts = req.url.href.split('/');
|
|
328
|
+
const fileName = parts[parts.length - 1];
|
|
329
|
+
const fileNameParts = fileName.split('?');
|
|
330
|
+
parts.pop();
|
|
331
|
+
let ssrPath = new URL(parts.join('/')).href;
|
|
332
|
+
if (!ssrPath.endsWith('/') && req.headers) {
|
|
333
|
+
const h = new Headers(req.headers);
|
|
334
|
+
if (h.get('referer').endsWith('/')) {
|
|
335
|
+
ssrPath += '/';
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
ssrPath,
|
|
340
|
+
fileName: fileNameParts[0],
|
|
341
|
+
hasQueryString: typeof fileNameParts[1] === 'string' && fileNameParts[1].length > 0,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
function isDevClient(pathname) {
|
|
345
|
+
return pathname.startsWith(DEV_SERVER_URL);
|
|
346
|
+
}
|
|
347
|
+
function isDevModule(pathname) {
|
|
348
|
+
return pathname.includes(DEV_MODULE_URL);
|
|
349
|
+
}
|
|
350
|
+
function isOpenInEditor(pathname) {
|
|
351
|
+
return pathname === OPEN_IN_EDITOR_URL;
|
|
352
|
+
}
|
|
353
|
+
function isInitialDevServerLoad(pathname) {
|
|
354
|
+
return pathname === DEV_SERVER_INIT_URL;
|
|
355
|
+
}
|
|
356
|
+
function isDevServerClient(pathname) {
|
|
357
|
+
return pathname === DEV_SERVER_URL;
|
|
358
|
+
}
|
|
359
|
+
function shouldCompress(devServerConfig, req) {
|
|
360
|
+
if (!devServerConfig.gzip) {
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
if (req.method !== 'GET') {
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
const acceptEncoding = req.headers && req.headers['accept-encoding'];
|
|
367
|
+
if (typeof acceptEncoding !== 'string') {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
if (!acceptEncoding.includes('gzip')) {
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
return true;
|
|
374
374
|
}
|
|
375
375
|
|
|
376
376
|
function createCommonjsModule(fn, basedir, module) {
|
|
@@ -476,6 +476,25 @@ const localXdgOpenPath = path__default['default'].join(__dirname, 'xdg-open');
|
|
|
476
476
|
|
|
477
477
|
const {platform, arch} = process;
|
|
478
478
|
|
|
479
|
+
// Podman detection
|
|
480
|
+
const hasContainerEnv = () => {
|
|
481
|
+
try {
|
|
482
|
+
fs.statSync('/run/.containerenv');
|
|
483
|
+
return true;
|
|
484
|
+
} catch {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
let cachedResult;
|
|
490
|
+
function isInsideContainer() {
|
|
491
|
+
if (cachedResult === undefined) {
|
|
492
|
+
cachedResult = hasContainerEnv() || isDocker_1();
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return cachedResult;
|
|
496
|
+
}
|
|
497
|
+
|
|
479
498
|
/**
|
|
480
499
|
Get the mount point for fixed drives in WSL.
|
|
481
500
|
|
|
@@ -586,7 +605,7 @@ const baseOpen = async options => {
|
|
|
586
605
|
if (app) {
|
|
587
606
|
cliArguments.push('-a', app);
|
|
588
607
|
}
|
|
589
|
-
} else if (platform === 'win32' || (isWsl_1 && !
|
|
608
|
+
} else if (platform === 'win32' || (isWsl_1 && !isInsideContainer() && !app)) {
|
|
590
609
|
const mountPoint = await getWslDrivesMountPoint();
|
|
591
610
|
|
|
592
611
|
command = isWsl_1 ?
|
|
@@ -780,682 +799,682 @@ open.openApp = openApp;
|
|
|
780
799
|
|
|
781
800
|
var open_1 = open;
|
|
782
801
|
|
|
783
|
-
async function openInBrowser(opts) {
|
|
784
|
-
// await open(opts.url, { app: ['google chrome', '--auto-open-devtools-for-tabs'] });
|
|
785
|
-
await open_1(opts.url);
|
|
802
|
+
async function openInBrowser(opts) {
|
|
803
|
+
// await open(opts.url, { app: ['google chrome', '--auto-open-devtools-for-tabs'] });
|
|
804
|
+
await open_1(opts.url);
|
|
786
805
|
}
|
|
787
806
|
|
|
788
|
-
function createServerContext(sys, sendMsg, devServerConfig, buildResultsResolves, compilerRequestResolves) {
|
|
789
|
-
const logRequest = (req, status) => {
|
|
790
|
-
if (devServerConfig) {
|
|
791
|
-
sendMsg({
|
|
792
|
-
requestLog: {
|
|
793
|
-
method: req.method || '?',
|
|
794
|
-
url: req.pathname || '?',
|
|
795
|
-
status,
|
|
796
|
-
},
|
|
797
|
-
});
|
|
798
|
-
}
|
|
799
|
-
};
|
|
800
|
-
const serve500 = (req, res, error, xSource) => {
|
|
801
|
-
try {
|
|
802
|
-
res.writeHead(500, responseHeaders({
|
|
803
|
-
'content-type': 'text/plain; charset=utf-8',
|
|
804
|
-
'x-source': xSource,
|
|
805
|
-
}));
|
|
806
|
-
res.write(util__default['default'].inspect(error));
|
|
807
|
-
res.end();
|
|
808
|
-
logRequest(req, 500);
|
|
809
|
-
}
|
|
810
|
-
catch (e) {
|
|
811
|
-
sendMsg({ error: { message: 'serve500: ' + e } });
|
|
812
|
-
}
|
|
813
|
-
};
|
|
814
|
-
const serve404 = (req, res, xSource, content = null) => {
|
|
815
|
-
try {
|
|
816
|
-
if (req.pathname === '/favicon.ico') {
|
|
817
|
-
const defaultFavicon = path__default['default'].join(devServerConfig.devServerDir, 'static', 'favicon.ico');
|
|
818
|
-
res.writeHead(200, responseHeaders({
|
|
819
|
-
'content-type': 'image/x-icon',
|
|
820
|
-
'x-source': `favicon: ${xSource}`,
|
|
821
|
-
}));
|
|
822
|
-
const rs = fs__default$1['default'].createReadStream(defaultFavicon);
|
|
823
|
-
rs.on('error', (err) => {
|
|
824
|
-
res.writeHead(404, responseHeaders({
|
|
825
|
-
'content-type': 'text/plain; charset=utf-8',
|
|
826
|
-
'x-source': `createReadStream error: ${err}, ${xSource}`,
|
|
827
|
-
}));
|
|
828
|
-
res.write(util__default['default'].inspect(err));
|
|
829
|
-
res.end();
|
|
830
|
-
});
|
|
831
|
-
rs.pipe(res);
|
|
832
|
-
return;
|
|
833
|
-
}
|
|
834
|
-
if (content == null) {
|
|
835
|
-
content = ['404 File Not Found', 'Url: ' + req.pathname, 'File: ' + req.filePath].join('\n');
|
|
836
|
-
}
|
|
837
|
-
res.writeHead(404, responseHeaders({
|
|
838
|
-
'content-type': 'text/plain; charset=utf-8',
|
|
839
|
-
'x-source': xSource,
|
|
840
|
-
}));
|
|
841
|
-
res.write(content);
|
|
842
|
-
res.end();
|
|
843
|
-
logRequest(req, 400);
|
|
844
|
-
}
|
|
845
|
-
catch (e) {
|
|
846
|
-
serve500(req, res, e, xSource);
|
|
847
|
-
}
|
|
848
|
-
};
|
|
849
|
-
const serve302 = (req, res, pathname = null) => {
|
|
850
|
-
logRequest(req, 302);
|
|
851
|
-
res.writeHead(302, { location: pathname || devServerConfig.basePath || '/' });
|
|
852
|
-
res.end();
|
|
853
|
-
};
|
|
854
|
-
const getBuildResults = () => new Promise((resolve, reject) => {
|
|
855
|
-
if (serverCtx.isServerListening) {
|
|
856
|
-
buildResultsResolves.push({ resolve, reject });
|
|
857
|
-
sendMsg({ requestBuildResults: true });
|
|
858
|
-
}
|
|
859
|
-
else {
|
|
860
|
-
reject('dev server closed');
|
|
861
|
-
}
|
|
862
|
-
});
|
|
863
|
-
const getCompilerRequest = (compilerRequestPath) => new Promise((resolve, reject) => {
|
|
864
|
-
if (serverCtx.isServerListening) {
|
|
865
|
-
compilerRequestResolves.push({
|
|
866
|
-
path: compilerRequestPath,
|
|
867
|
-
resolve,
|
|
868
|
-
reject,
|
|
869
|
-
});
|
|
870
|
-
sendMsg({ compilerRequestPath });
|
|
871
|
-
}
|
|
872
|
-
else {
|
|
873
|
-
reject('dev server closed');
|
|
874
|
-
}
|
|
875
|
-
});
|
|
876
|
-
const serverCtx = {
|
|
877
|
-
connectorHtml: null,
|
|
878
|
-
dirTemplate: null,
|
|
879
|
-
getBuildResults,
|
|
880
|
-
getCompilerRequest,
|
|
881
|
-
isServerListening: false,
|
|
882
|
-
logRequest,
|
|
883
|
-
prerenderConfig: null,
|
|
884
|
-
serve302,
|
|
885
|
-
serve404,
|
|
886
|
-
serve500,
|
|
887
|
-
sys,
|
|
888
|
-
};
|
|
889
|
-
return serverCtx;
|
|
807
|
+
function createServerContext(sys, sendMsg, devServerConfig, buildResultsResolves, compilerRequestResolves) {
|
|
808
|
+
const logRequest = (req, status) => {
|
|
809
|
+
if (devServerConfig) {
|
|
810
|
+
sendMsg({
|
|
811
|
+
requestLog: {
|
|
812
|
+
method: req.method || '?',
|
|
813
|
+
url: req.pathname || '?',
|
|
814
|
+
status,
|
|
815
|
+
},
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
const serve500 = (req, res, error, xSource) => {
|
|
820
|
+
try {
|
|
821
|
+
res.writeHead(500, responseHeaders({
|
|
822
|
+
'content-type': 'text/plain; charset=utf-8',
|
|
823
|
+
'x-source': xSource,
|
|
824
|
+
}));
|
|
825
|
+
res.write(util__default['default'].inspect(error));
|
|
826
|
+
res.end();
|
|
827
|
+
logRequest(req, 500);
|
|
828
|
+
}
|
|
829
|
+
catch (e) {
|
|
830
|
+
sendMsg({ error: { message: 'serve500: ' + e } });
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
const serve404 = (req, res, xSource, content = null) => {
|
|
834
|
+
try {
|
|
835
|
+
if (req.pathname === '/favicon.ico') {
|
|
836
|
+
const defaultFavicon = path__default['default'].join(devServerConfig.devServerDir, 'static', 'favicon.ico');
|
|
837
|
+
res.writeHead(200, responseHeaders({
|
|
838
|
+
'content-type': 'image/x-icon',
|
|
839
|
+
'x-source': `favicon: ${xSource}`,
|
|
840
|
+
}));
|
|
841
|
+
const rs = fs__default$1['default'].createReadStream(defaultFavicon);
|
|
842
|
+
rs.on('error', (err) => {
|
|
843
|
+
res.writeHead(404, responseHeaders({
|
|
844
|
+
'content-type': 'text/plain; charset=utf-8',
|
|
845
|
+
'x-source': `createReadStream error: ${err}, ${xSource}`,
|
|
846
|
+
}));
|
|
847
|
+
res.write(util__default['default'].inspect(err));
|
|
848
|
+
res.end();
|
|
849
|
+
});
|
|
850
|
+
rs.pipe(res);
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
if (content == null) {
|
|
854
|
+
content = ['404 File Not Found', 'Url: ' + req.pathname, 'File: ' + req.filePath].join('\n');
|
|
855
|
+
}
|
|
856
|
+
res.writeHead(404, responseHeaders({
|
|
857
|
+
'content-type': 'text/plain; charset=utf-8',
|
|
858
|
+
'x-source': xSource,
|
|
859
|
+
}));
|
|
860
|
+
res.write(content);
|
|
861
|
+
res.end();
|
|
862
|
+
logRequest(req, 400);
|
|
863
|
+
}
|
|
864
|
+
catch (e) {
|
|
865
|
+
serve500(req, res, e, xSource);
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
const serve302 = (req, res, pathname = null) => {
|
|
869
|
+
logRequest(req, 302);
|
|
870
|
+
res.writeHead(302, { location: pathname || devServerConfig.basePath || '/' });
|
|
871
|
+
res.end();
|
|
872
|
+
};
|
|
873
|
+
const getBuildResults = () => new Promise((resolve, reject) => {
|
|
874
|
+
if (serverCtx.isServerListening) {
|
|
875
|
+
buildResultsResolves.push({ resolve, reject });
|
|
876
|
+
sendMsg({ requestBuildResults: true });
|
|
877
|
+
}
|
|
878
|
+
else {
|
|
879
|
+
reject('dev server closed');
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
const getCompilerRequest = (compilerRequestPath) => new Promise((resolve, reject) => {
|
|
883
|
+
if (serverCtx.isServerListening) {
|
|
884
|
+
compilerRequestResolves.push({
|
|
885
|
+
path: compilerRequestPath,
|
|
886
|
+
resolve,
|
|
887
|
+
reject,
|
|
888
|
+
});
|
|
889
|
+
sendMsg({ compilerRequestPath });
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
reject('dev server closed');
|
|
893
|
+
}
|
|
894
|
+
});
|
|
895
|
+
const serverCtx = {
|
|
896
|
+
connectorHtml: null,
|
|
897
|
+
dirTemplate: null,
|
|
898
|
+
getBuildResults,
|
|
899
|
+
getCompilerRequest,
|
|
900
|
+
isServerListening: false,
|
|
901
|
+
logRequest,
|
|
902
|
+
prerenderConfig: null,
|
|
903
|
+
serve302,
|
|
904
|
+
serve404,
|
|
905
|
+
serve500,
|
|
906
|
+
sys,
|
|
907
|
+
};
|
|
908
|
+
return serverCtx;
|
|
890
909
|
}
|
|
891
910
|
|
|
892
|
-
async function serveOpenInEditor(serverCtx, req, res) {
|
|
893
|
-
let status = 200;
|
|
894
|
-
const data = {};
|
|
895
|
-
try {
|
|
896
|
-
const editors = await getEditors();
|
|
897
|
-
if (editors.length > 0) {
|
|
898
|
-
await parseData(editors, serverCtx.sys, req, data);
|
|
899
|
-
await openDataInEditor(data);
|
|
900
|
-
}
|
|
901
|
-
else {
|
|
902
|
-
data.error = `no editors available`;
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
catch (e) {
|
|
906
|
-
data.error = e + '';
|
|
907
|
-
status = 500;
|
|
908
|
-
}
|
|
909
|
-
serverCtx.logRequest(req, status);
|
|
910
|
-
res.writeHead(status, responseHeaders({
|
|
911
|
-
'content-type': 'application/json; charset=utf-8',
|
|
912
|
-
}));
|
|
913
|
-
res.write(JSON.stringify(data, null, 2));
|
|
914
|
-
res.end();
|
|
915
|
-
}
|
|
916
|
-
async function parseData(editors, sys, req, data) {
|
|
917
|
-
const qs = req.searchParams;
|
|
918
|
-
if (!qs.has('file')) {
|
|
919
|
-
data.error = `missing file`;
|
|
920
|
-
return;
|
|
921
|
-
}
|
|
922
|
-
data.file = qs.get('file');
|
|
923
|
-
if (qs.has('line') && !isNaN(qs.get('line'))) {
|
|
924
|
-
data.line = parseInt(qs.get('line'), 10);
|
|
925
|
-
}
|
|
926
|
-
if (typeof data.line !== 'number' || data.line < 1) {
|
|
927
|
-
data.line = 1;
|
|
928
|
-
}
|
|
929
|
-
if (qs.has('column') && !isNaN(qs.get('column'))) {
|
|
930
|
-
data.column = parseInt(qs.get('column'), 10);
|
|
931
|
-
}
|
|
932
|
-
if (typeof data.column !== 'number' || data.column < 1) {
|
|
933
|
-
data.column = 1;
|
|
934
|
-
}
|
|
935
|
-
let editor = qs.get('editor');
|
|
936
|
-
if (typeof editor === 'string') {
|
|
937
|
-
editor = editor.trim().toLowerCase();
|
|
938
|
-
if (editors.some((e) => e.id === editor)) {
|
|
939
|
-
data.editor = editor;
|
|
940
|
-
}
|
|
941
|
-
else {
|
|
942
|
-
data.error = `invalid editor: ${editor}`;
|
|
943
|
-
return;
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
else {
|
|
947
|
-
data.editor = editors[0].id;
|
|
948
|
-
}
|
|
949
|
-
const stat = await sys.stat(data.file);
|
|
950
|
-
data.exists = stat.isFile;
|
|
951
|
-
}
|
|
952
|
-
async function openDataInEditor(data) {
|
|
953
|
-
if (!data.exists || data.error) {
|
|
954
|
-
return;
|
|
955
|
-
}
|
|
956
|
-
try {
|
|
957
|
-
const opts = {
|
|
958
|
-
editor: data.editor,
|
|
959
|
-
};
|
|
960
|
-
const editor = openInEditorApi__default['default'].configure(opts, (err) => (data.error = err + ''));
|
|
961
|
-
if (data.error) {
|
|
962
|
-
return;
|
|
963
|
-
}
|
|
964
|
-
data.open = `${data.file}:${data.line}:${data.column}`;
|
|
965
|
-
await editor.open(data.open);
|
|
966
|
-
}
|
|
967
|
-
catch (e) {
|
|
968
|
-
data.error = e + '';
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
let editors = null;
|
|
972
|
-
function getEditors() {
|
|
973
|
-
if (!editors) {
|
|
974
|
-
editors = new Promise(async (resolve) => {
|
|
975
|
-
const editors = [];
|
|
976
|
-
try {
|
|
977
|
-
await Promise.all(Object.keys(openInEditorApi__default['default'].editors).map(async (editorId) => {
|
|
978
|
-
const isSupported = await isEditorSupported(editorId);
|
|
979
|
-
editors.push({
|
|
980
|
-
id: editorId,
|
|
981
|
-
priority: EDITOR_PRIORITY[editorId],
|
|
982
|
-
supported: isSupported,
|
|
983
|
-
});
|
|
984
|
-
}));
|
|
985
|
-
}
|
|
986
|
-
catch (e) { }
|
|
987
|
-
resolve(editors
|
|
988
|
-
.filter((e) => e.supported)
|
|
989
|
-
.sort((a, b) => {
|
|
990
|
-
if (a.priority < b.priority)
|
|
991
|
-
return -1;
|
|
992
|
-
if (a.priority > b.priority)
|
|
993
|
-
return 1;
|
|
994
|
-
return 0;
|
|
995
|
-
})
|
|
996
|
-
.map((e) => {
|
|
997
|
-
return {
|
|
998
|
-
id: e.id,
|
|
999
|
-
name: EDITORS[e.id],
|
|
1000
|
-
};
|
|
1001
|
-
}));
|
|
1002
|
-
});
|
|
1003
|
-
}
|
|
1004
|
-
return editors;
|
|
1005
|
-
}
|
|
1006
|
-
async function isEditorSupported(editorId) {
|
|
1007
|
-
let isSupported = false;
|
|
1008
|
-
try {
|
|
1009
|
-
await openInEditorApi__default['default'].editors[editorId].detect();
|
|
1010
|
-
isSupported = true;
|
|
1011
|
-
}
|
|
1012
|
-
catch (e) { }
|
|
1013
|
-
return isSupported;
|
|
1014
|
-
}
|
|
1015
|
-
const EDITORS = {
|
|
1016
|
-
atom: 'Atom',
|
|
1017
|
-
code: 'Code',
|
|
1018
|
-
emacs: 'Emacs',
|
|
1019
|
-
idea14ce: 'IDEA 14 Community Edition',
|
|
1020
|
-
phpstorm: 'PhpStorm',
|
|
1021
|
-
sublime: 'Sublime',
|
|
1022
|
-
webstorm: 'WebStorm',
|
|
1023
|
-
vim: 'Vim',
|
|
1024
|
-
visualstudio: 'Visual Studio',
|
|
1025
|
-
};
|
|
1026
|
-
const EDITOR_PRIORITY = {
|
|
1027
|
-
code: 1,
|
|
1028
|
-
atom: 2,
|
|
1029
|
-
sublime: 3,
|
|
1030
|
-
visualstudio: 4,
|
|
1031
|
-
idea14ce: 5,
|
|
1032
|
-
webstorm: 6,
|
|
1033
|
-
phpstorm: 7,
|
|
1034
|
-
vim: 8,
|
|
1035
|
-
emacs: 9,
|
|
911
|
+
async function serveOpenInEditor(serverCtx, req, res) {
|
|
912
|
+
let status = 200;
|
|
913
|
+
const data = {};
|
|
914
|
+
try {
|
|
915
|
+
const editors = await getEditors();
|
|
916
|
+
if (editors.length > 0) {
|
|
917
|
+
await parseData(editors, serverCtx.sys, req, data);
|
|
918
|
+
await openDataInEditor(data);
|
|
919
|
+
}
|
|
920
|
+
else {
|
|
921
|
+
data.error = `no editors available`;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
catch (e) {
|
|
925
|
+
data.error = e + '';
|
|
926
|
+
status = 500;
|
|
927
|
+
}
|
|
928
|
+
serverCtx.logRequest(req, status);
|
|
929
|
+
res.writeHead(status, responseHeaders({
|
|
930
|
+
'content-type': 'application/json; charset=utf-8',
|
|
931
|
+
}));
|
|
932
|
+
res.write(JSON.stringify(data, null, 2));
|
|
933
|
+
res.end();
|
|
934
|
+
}
|
|
935
|
+
async function parseData(editors, sys, req, data) {
|
|
936
|
+
const qs = req.searchParams;
|
|
937
|
+
if (!qs.has('file')) {
|
|
938
|
+
data.error = `missing file`;
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
data.file = qs.get('file');
|
|
942
|
+
if (qs.has('line') && !isNaN(qs.get('line'))) {
|
|
943
|
+
data.line = parseInt(qs.get('line'), 10);
|
|
944
|
+
}
|
|
945
|
+
if (typeof data.line !== 'number' || data.line < 1) {
|
|
946
|
+
data.line = 1;
|
|
947
|
+
}
|
|
948
|
+
if (qs.has('column') && !isNaN(qs.get('column'))) {
|
|
949
|
+
data.column = parseInt(qs.get('column'), 10);
|
|
950
|
+
}
|
|
951
|
+
if (typeof data.column !== 'number' || data.column < 1) {
|
|
952
|
+
data.column = 1;
|
|
953
|
+
}
|
|
954
|
+
let editor = qs.get('editor');
|
|
955
|
+
if (typeof editor === 'string') {
|
|
956
|
+
editor = editor.trim().toLowerCase();
|
|
957
|
+
if (editors.some((e) => e.id === editor)) {
|
|
958
|
+
data.editor = editor;
|
|
959
|
+
}
|
|
960
|
+
else {
|
|
961
|
+
data.error = `invalid editor: ${editor}`;
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
else {
|
|
966
|
+
data.editor = editors[0].id;
|
|
967
|
+
}
|
|
968
|
+
const stat = await sys.stat(data.file);
|
|
969
|
+
data.exists = stat.isFile;
|
|
970
|
+
}
|
|
971
|
+
async function openDataInEditor(data) {
|
|
972
|
+
if (!data.exists || data.error) {
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
try {
|
|
976
|
+
const opts = {
|
|
977
|
+
editor: data.editor,
|
|
978
|
+
};
|
|
979
|
+
const editor = openInEditorApi__default['default'].configure(opts, (err) => (data.error = err + ''));
|
|
980
|
+
if (data.error) {
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
data.open = `${data.file}:${data.line}:${data.column}`;
|
|
984
|
+
await editor.open(data.open);
|
|
985
|
+
}
|
|
986
|
+
catch (e) {
|
|
987
|
+
data.error = e + '';
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
let editors = null;
|
|
991
|
+
function getEditors() {
|
|
992
|
+
if (!editors) {
|
|
993
|
+
editors = new Promise(async (resolve) => {
|
|
994
|
+
const editors = [];
|
|
995
|
+
try {
|
|
996
|
+
await Promise.all(Object.keys(openInEditorApi__default['default'].editors).map(async (editorId) => {
|
|
997
|
+
const isSupported = await isEditorSupported(editorId);
|
|
998
|
+
editors.push({
|
|
999
|
+
id: editorId,
|
|
1000
|
+
priority: EDITOR_PRIORITY[editorId],
|
|
1001
|
+
supported: isSupported,
|
|
1002
|
+
});
|
|
1003
|
+
}));
|
|
1004
|
+
}
|
|
1005
|
+
catch (e) { }
|
|
1006
|
+
resolve(editors
|
|
1007
|
+
.filter((e) => e.supported)
|
|
1008
|
+
.sort((a, b) => {
|
|
1009
|
+
if (a.priority < b.priority)
|
|
1010
|
+
return -1;
|
|
1011
|
+
if (a.priority > b.priority)
|
|
1012
|
+
return 1;
|
|
1013
|
+
return 0;
|
|
1014
|
+
})
|
|
1015
|
+
.map((e) => {
|
|
1016
|
+
return {
|
|
1017
|
+
id: e.id,
|
|
1018
|
+
name: EDITORS[e.id],
|
|
1019
|
+
};
|
|
1020
|
+
}));
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
return editors;
|
|
1024
|
+
}
|
|
1025
|
+
async function isEditorSupported(editorId) {
|
|
1026
|
+
let isSupported = false;
|
|
1027
|
+
try {
|
|
1028
|
+
await openInEditorApi__default['default'].editors[editorId].detect();
|
|
1029
|
+
isSupported = true;
|
|
1030
|
+
}
|
|
1031
|
+
catch (e) { }
|
|
1032
|
+
return isSupported;
|
|
1033
|
+
}
|
|
1034
|
+
const EDITORS = {
|
|
1035
|
+
atom: 'Atom',
|
|
1036
|
+
code: 'Code',
|
|
1037
|
+
emacs: 'Emacs',
|
|
1038
|
+
idea14ce: 'IDEA 14 Community Edition',
|
|
1039
|
+
phpstorm: 'PhpStorm',
|
|
1040
|
+
sublime: 'Sublime',
|
|
1041
|
+
webstorm: 'WebStorm',
|
|
1042
|
+
vim: 'Vim',
|
|
1043
|
+
visualstudio: 'Visual Studio',
|
|
1044
|
+
};
|
|
1045
|
+
const EDITOR_PRIORITY = {
|
|
1046
|
+
code: 1,
|
|
1047
|
+
atom: 2,
|
|
1048
|
+
sublime: 3,
|
|
1049
|
+
visualstudio: 4,
|
|
1050
|
+
idea14ce: 5,
|
|
1051
|
+
webstorm: 6,
|
|
1052
|
+
phpstorm: 7,
|
|
1053
|
+
vim: 8,
|
|
1054
|
+
emacs: 9,
|
|
1036
1055
|
};
|
|
1037
1056
|
|
|
1038
|
-
async function serveFile(devServerConfig, serverCtx, req, res) {
|
|
1039
|
-
try {
|
|
1040
|
-
if (isSimpleText(req.filePath)) {
|
|
1041
|
-
// easy text file, use the internal cache
|
|
1042
|
-
let content = await serverCtx.sys.readFile(req.filePath, 'utf8');
|
|
1043
|
-
if (devServerConfig.websocket && isHtmlFile(req.filePath) && !isDevServerClient(req.pathname)) {
|
|
1044
|
-
// auto inject our dev server script
|
|
1045
|
-
content = appendDevServerClientScript(devServerConfig, req, content);
|
|
1046
|
-
}
|
|
1047
|
-
else if (isCssFile(req.filePath)) {
|
|
1048
|
-
content = updateStyleUrls(req.url, content);
|
|
1049
|
-
}
|
|
1050
|
-
if (shouldCompress(devServerConfig, req)) {
|
|
1051
|
-
// let's gzip this well known web dev text file
|
|
1052
|
-
res.writeHead(200, responseHeaders({
|
|
1053
|
-
'content-type': getContentType(req.filePath) + '; charset=utf-8',
|
|
1054
|
-
'content-encoding': 'gzip',
|
|
1055
|
-
vary: 'Accept-Encoding',
|
|
1056
|
-
}));
|
|
1057
|
-
zlib__namespace.gzip(content, { level: 9 }, (_, data) => {
|
|
1058
|
-
res.end(data);
|
|
1059
|
-
});
|
|
1060
|
-
}
|
|
1061
|
-
else {
|
|
1062
|
-
// let's not gzip this file
|
|
1063
|
-
res.writeHead(200, responseHeaders({
|
|
1064
|
-
'content-type': getContentType(req.filePath) + '; charset=utf-8',
|
|
1065
|
-
'content-length': buffer.Buffer.byteLength(content, 'utf8'),
|
|
1066
|
-
}));
|
|
1067
|
-
res.write(content);
|
|
1068
|
-
res.end();
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
else {
|
|
1072
|
-
// non-well-known text file or other file, probably best we use a stream
|
|
1073
|
-
// but don't bother trying to gzip this file for the dev server
|
|
1074
|
-
res.writeHead(200, responseHeaders({
|
|
1075
|
-
'content-type': getContentType(req.filePath),
|
|
1076
|
-
'content-length': req.stats.size,
|
|
1077
|
-
}));
|
|
1078
|
-
fs__default$1['default'].createReadStream(req.filePath).pipe(res);
|
|
1079
|
-
}
|
|
1080
|
-
serverCtx.logRequest(req, 200);
|
|
1081
|
-
}
|
|
1082
|
-
catch (e) {
|
|
1083
|
-
serverCtx.serve500(req, res, e, 'serveFile');
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
function updateStyleUrls(url, oldCss) {
|
|
1087
|
-
const versionId = url.searchParams.get('s-hmr');
|
|
1088
|
-
const hmrUrls = url.searchParams.get('s-hmr-urls');
|
|
1089
|
-
if (versionId && hmrUrls) {
|
|
1090
|
-
hmrUrls.split(',').forEach((hmrUrl) => {
|
|
1091
|
-
urlVersionIds.set(hmrUrl, versionId);
|
|
1092
|
-
});
|
|
1093
|
-
}
|
|
1094
|
-
const reg = /url\((['"]?)(.*)\1\)/gi;
|
|
1095
|
-
let result;
|
|
1096
|
-
let newCss = oldCss;
|
|
1097
|
-
while ((result = reg.exec(oldCss)) !== null) {
|
|
1098
|
-
const oldUrl = result[2];
|
|
1099
|
-
const parsedUrl = new URL(oldUrl, url);
|
|
1100
|
-
const fileName = path__default['default'].basename(parsedUrl.pathname);
|
|
1101
|
-
const versionId = urlVersionIds.get(fileName);
|
|
1102
|
-
if (!versionId) {
|
|
1103
|
-
continue;
|
|
1104
|
-
}
|
|
1105
|
-
parsedUrl.searchParams.set('s-hmr', versionId);
|
|
1106
|
-
newCss = newCss.replace(oldUrl, parsedUrl.pathname);
|
|
1107
|
-
}
|
|
1108
|
-
return newCss;
|
|
1109
|
-
}
|
|
1110
|
-
const urlVersionIds = new Map();
|
|
1111
|
-
function appendDevServerClientScript(devServerConfig, req, content) {
|
|
1112
|
-
var _a, _b, _c;
|
|
1113
|
-
const devServerClientUrl = getDevServerClientUrl(devServerConfig, (_b = (_a = req.headers) === null || _a === void 0 ? void 0 : _a['x-forwarded-host']) !== null && _b !== void 0 ? _b : req.host, (_c = req.headers) === null || _c === void 0 ? void 0 : _c['x-forwarded-proto']);
|
|
1114
|
-
const iframe = `<iframe title="Rindo Dev Server Connector ${version} ⚡" src="${devServerClientUrl}" style="display:block;width:0;height:0;border:0;visibility:hidden" aria-hidden="true"></iframe>`;
|
|
1115
|
-
return appendDevServerClientIframe(content, iframe);
|
|
1116
|
-
}
|
|
1117
|
-
function appendDevServerClientIframe(content, iframe) {
|
|
1118
|
-
if (content.includes('</body>')) {
|
|
1119
|
-
return content.replace('</body>', `${iframe}</body>`);
|
|
1120
|
-
}
|
|
1121
|
-
if (content.includes('</html>')) {
|
|
1122
|
-
return content.replace('</html>', `${iframe}</html>`);
|
|
1123
|
-
}
|
|
1124
|
-
return `${content}${iframe}`;
|
|
1057
|
+
async function serveFile(devServerConfig, serverCtx, req, res) {
|
|
1058
|
+
try {
|
|
1059
|
+
if (isSimpleText(req.filePath)) {
|
|
1060
|
+
// easy text file, use the internal cache
|
|
1061
|
+
let content = await serverCtx.sys.readFile(req.filePath, 'utf8');
|
|
1062
|
+
if (devServerConfig.websocket && isHtmlFile(req.filePath) && !isDevServerClient(req.pathname)) {
|
|
1063
|
+
// auto inject our dev server script
|
|
1064
|
+
content = appendDevServerClientScript(devServerConfig, req, content);
|
|
1065
|
+
}
|
|
1066
|
+
else if (isCssFile(req.filePath)) {
|
|
1067
|
+
content = updateStyleUrls(req.url, content);
|
|
1068
|
+
}
|
|
1069
|
+
if (shouldCompress(devServerConfig, req)) {
|
|
1070
|
+
// let's gzip this well known web dev text file
|
|
1071
|
+
res.writeHead(200, responseHeaders({
|
|
1072
|
+
'content-type': getContentType(req.filePath) + '; charset=utf-8',
|
|
1073
|
+
'content-encoding': 'gzip',
|
|
1074
|
+
vary: 'Accept-Encoding',
|
|
1075
|
+
}));
|
|
1076
|
+
zlib__namespace.gzip(content, { level: 9 }, (_, data) => {
|
|
1077
|
+
res.end(data);
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
else {
|
|
1081
|
+
// let's not gzip this file
|
|
1082
|
+
res.writeHead(200, responseHeaders({
|
|
1083
|
+
'content-type': getContentType(req.filePath) + '; charset=utf-8',
|
|
1084
|
+
'content-length': buffer.Buffer.byteLength(content, 'utf8'),
|
|
1085
|
+
}));
|
|
1086
|
+
res.write(content);
|
|
1087
|
+
res.end();
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
else {
|
|
1091
|
+
// non-well-known text file or other file, probably best we use a stream
|
|
1092
|
+
// but don't bother trying to gzip this file for the dev server
|
|
1093
|
+
res.writeHead(200, responseHeaders({
|
|
1094
|
+
'content-type': getContentType(req.filePath),
|
|
1095
|
+
'content-length': req.stats.size,
|
|
1096
|
+
}));
|
|
1097
|
+
fs__default$1['default'].createReadStream(req.filePath).pipe(res);
|
|
1098
|
+
}
|
|
1099
|
+
serverCtx.logRequest(req, 200);
|
|
1100
|
+
}
|
|
1101
|
+
catch (e) {
|
|
1102
|
+
serverCtx.serve500(req, res, e, 'serveFile');
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
function updateStyleUrls(url, oldCss) {
|
|
1106
|
+
const versionId = url.searchParams.get('s-hmr');
|
|
1107
|
+
const hmrUrls = url.searchParams.get('s-hmr-urls');
|
|
1108
|
+
if (versionId && hmrUrls) {
|
|
1109
|
+
hmrUrls.split(',').forEach((hmrUrl) => {
|
|
1110
|
+
urlVersionIds.set(hmrUrl, versionId);
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
const reg = /url\((['"]?)(.*)\1\)/gi;
|
|
1114
|
+
let result;
|
|
1115
|
+
let newCss = oldCss;
|
|
1116
|
+
while ((result = reg.exec(oldCss)) !== null) {
|
|
1117
|
+
const oldUrl = result[2];
|
|
1118
|
+
const parsedUrl = new URL(oldUrl, url);
|
|
1119
|
+
const fileName = path__default['default'].basename(parsedUrl.pathname);
|
|
1120
|
+
const versionId = urlVersionIds.get(fileName);
|
|
1121
|
+
if (!versionId) {
|
|
1122
|
+
continue;
|
|
1123
|
+
}
|
|
1124
|
+
parsedUrl.searchParams.set('s-hmr', versionId);
|
|
1125
|
+
newCss = newCss.replace(oldUrl, parsedUrl.pathname);
|
|
1126
|
+
}
|
|
1127
|
+
return newCss;
|
|
1128
|
+
}
|
|
1129
|
+
const urlVersionIds = new Map();
|
|
1130
|
+
function appendDevServerClientScript(devServerConfig, req, content) {
|
|
1131
|
+
var _a, _b, _c;
|
|
1132
|
+
const devServerClientUrl = getDevServerClientUrl(devServerConfig, (_b = (_a = req.headers) === null || _a === void 0 ? void 0 : _a['x-forwarded-host']) !== null && _b !== void 0 ? _b : req.host, (_c = req.headers) === null || _c === void 0 ? void 0 : _c['x-forwarded-proto']);
|
|
1133
|
+
const iframe = `<iframe title="Rindo Dev Server Connector ${version} ⚡" src="${devServerClientUrl}" style="display:block;width:0;height:0;border:0;visibility:hidden" aria-hidden="true"></iframe>`;
|
|
1134
|
+
return appendDevServerClientIframe(content, iframe);
|
|
1135
|
+
}
|
|
1136
|
+
function appendDevServerClientIframe(content, iframe) {
|
|
1137
|
+
if (content.includes('</body>')) {
|
|
1138
|
+
return content.replace('</body>', `${iframe}</body>`);
|
|
1139
|
+
}
|
|
1140
|
+
if (content.includes('</html>')) {
|
|
1141
|
+
return content.replace('</html>', `${iframe}</html>`);
|
|
1142
|
+
}
|
|
1143
|
+
return `${content}${iframe}`;
|
|
1125
1144
|
}
|
|
1126
1145
|
|
|
1127
|
-
async function serveDevClient(devServerConfig, serverCtx, req, res) {
|
|
1128
|
-
try {
|
|
1129
|
-
if (isOpenInEditor(req.pathname)) {
|
|
1130
|
-
return serveOpenInEditor(serverCtx, req, res);
|
|
1131
|
-
}
|
|
1132
|
-
if (isDevServerClient(req.pathname)) {
|
|
1133
|
-
return serveDevClientScript(devServerConfig, serverCtx, req, res);
|
|
1134
|
-
}
|
|
1135
|
-
if (isInitialDevServerLoad(req.pathname)) {
|
|
1136
|
-
req.filePath = path__default['default'].join(devServerConfig.devServerDir, 'templates', 'initial-load.html');
|
|
1137
|
-
}
|
|
1138
|
-
else {
|
|
1139
|
-
const staticFile = req.pathname.replace(DEV_SERVER_URL + '/', '');
|
|
1140
|
-
req.filePath = path__default['default'].join(devServerConfig.devServerDir, 'static', staticFile);
|
|
1141
|
-
}
|
|
1142
|
-
try {
|
|
1143
|
-
req.stats = await serverCtx.sys.stat(req.filePath);
|
|
1144
|
-
if (req.stats.isFile) {
|
|
1145
|
-
return serveFile(devServerConfig, serverCtx, req, res);
|
|
1146
|
-
}
|
|
1147
|
-
return serverCtx.serve404(req, res, 'serveDevClient not file');
|
|
1148
|
-
}
|
|
1149
|
-
catch (e) {
|
|
1150
|
-
return serverCtx.serve404(req, res, `serveDevClient stats error ${e}`);
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
catch (e) {
|
|
1154
|
-
return serverCtx.serve500(req, res, e, 'serveDevClient');
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
async function serveDevClientScript(devServerConfig, serverCtx, req, res) {
|
|
1158
|
-
try {
|
|
1159
|
-
if (serverCtx.connectorHtml == null) {
|
|
1160
|
-
const filePath = path__default['default'].join(devServerConfig.devServerDir, 'connector.html');
|
|
1161
|
-
serverCtx.connectorHtml = serverCtx.sys.readFileSync(filePath, 'utf8');
|
|
1162
|
-
if (typeof serverCtx.connectorHtml !== 'string') {
|
|
1163
|
-
return serverCtx.serve404(req, res, `serveDevClientScript`);
|
|
1164
|
-
}
|
|
1165
|
-
const devClientConfig = {
|
|
1166
|
-
basePath: devServerConfig.basePath,
|
|
1167
|
-
editors: await getEditors(),
|
|
1168
|
-
reloadStrategy: devServerConfig.reloadStrategy,
|
|
1169
|
-
};
|
|
1170
|
-
serverCtx.connectorHtml = serverCtx.connectorHtml.replace('window.__DEV_CLIENT_CONFIG__', JSON.stringify(devClientConfig));
|
|
1171
|
-
}
|
|
1172
|
-
res.writeHead(200, responseHeaders({
|
|
1173
|
-
'content-type': 'text/html; charset=utf-8',
|
|
1174
|
-
}));
|
|
1175
|
-
res.write(serverCtx.connectorHtml);
|
|
1176
|
-
res.end();
|
|
1177
|
-
}
|
|
1178
|
-
catch (e) {
|
|
1179
|
-
return serverCtx.serve500(req, res, e, `serveDevClientScript`);
|
|
1180
|
-
}
|
|
1146
|
+
async function serveDevClient(devServerConfig, serverCtx, req, res) {
|
|
1147
|
+
try {
|
|
1148
|
+
if (isOpenInEditor(req.pathname)) {
|
|
1149
|
+
return serveOpenInEditor(serverCtx, req, res);
|
|
1150
|
+
}
|
|
1151
|
+
if (isDevServerClient(req.pathname)) {
|
|
1152
|
+
return serveDevClientScript(devServerConfig, serverCtx, req, res);
|
|
1153
|
+
}
|
|
1154
|
+
if (isInitialDevServerLoad(req.pathname)) {
|
|
1155
|
+
req.filePath = path__default['default'].join(devServerConfig.devServerDir, 'templates', 'initial-load.html');
|
|
1156
|
+
}
|
|
1157
|
+
else {
|
|
1158
|
+
const staticFile = req.pathname.replace(DEV_SERVER_URL + '/', '');
|
|
1159
|
+
req.filePath = path__default['default'].join(devServerConfig.devServerDir, 'static', staticFile);
|
|
1160
|
+
}
|
|
1161
|
+
try {
|
|
1162
|
+
req.stats = await serverCtx.sys.stat(req.filePath);
|
|
1163
|
+
if (req.stats.isFile) {
|
|
1164
|
+
return serveFile(devServerConfig, serverCtx, req, res);
|
|
1165
|
+
}
|
|
1166
|
+
return serverCtx.serve404(req, res, 'serveDevClient not file');
|
|
1167
|
+
}
|
|
1168
|
+
catch (e) {
|
|
1169
|
+
return serverCtx.serve404(req, res, `serveDevClient stats error ${e}`);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
catch (e) {
|
|
1173
|
+
return serverCtx.serve500(req, res, e, 'serveDevClient');
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
async function serveDevClientScript(devServerConfig, serverCtx, req, res) {
|
|
1177
|
+
try {
|
|
1178
|
+
if (serverCtx.connectorHtml == null) {
|
|
1179
|
+
const filePath = path__default['default'].join(devServerConfig.devServerDir, 'connector.html');
|
|
1180
|
+
serverCtx.connectorHtml = serverCtx.sys.readFileSync(filePath, 'utf8');
|
|
1181
|
+
if (typeof serverCtx.connectorHtml !== 'string') {
|
|
1182
|
+
return serverCtx.serve404(req, res, `serveDevClientScript`);
|
|
1183
|
+
}
|
|
1184
|
+
const devClientConfig = {
|
|
1185
|
+
basePath: devServerConfig.basePath,
|
|
1186
|
+
editors: await getEditors(),
|
|
1187
|
+
reloadStrategy: devServerConfig.reloadStrategy,
|
|
1188
|
+
};
|
|
1189
|
+
serverCtx.connectorHtml = serverCtx.connectorHtml.replace('window.__DEV_CLIENT_CONFIG__', JSON.stringify(devClientConfig));
|
|
1190
|
+
}
|
|
1191
|
+
res.writeHead(200, responseHeaders({
|
|
1192
|
+
'content-type': 'text/html; charset=utf-8',
|
|
1193
|
+
}));
|
|
1194
|
+
res.write(serverCtx.connectorHtml);
|
|
1195
|
+
res.end();
|
|
1196
|
+
}
|
|
1197
|
+
catch (e) {
|
|
1198
|
+
return serverCtx.serve500(req, res, e, `serveDevClientScript`);
|
|
1199
|
+
}
|
|
1181
1200
|
}
|
|
1182
1201
|
|
|
1183
|
-
async function serveDevNodeModule(serverCtx, req, res) {
|
|
1184
|
-
try {
|
|
1185
|
-
const results = await serverCtx.getCompilerRequest(req.pathname);
|
|
1186
|
-
const headers = {
|
|
1187
|
-
'content-type': 'application/javascript; charset=utf-8',
|
|
1188
|
-
'content-length': Buffer.byteLength(results.content, 'utf8'),
|
|
1189
|
-
'x-dev-node-module-id': results.nodeModuleId,
|
|
1190
|
-
'x-dev-node-module-version': results.nodeModuleVersion,
|
|
1191
|
-
'x-dev-node-module-resolved-path': results.nodeResolvedPath,
|
|
1192
|
-
'x-dev-node-module-cache-path': results.cachePath,
|
|
1193
|
-
'x-dev-node-module-cache-hit': results.cacheHit,
|
|
1194
|
-
};
|
|
1195
|
-
res.writeHead(results.status, responseHeaders(headers));
|
|
1196
|
-
res.write(results.content);
|
|
1197
|
-
res.end();
|
|
1198
|
-
}
|
|
1199
|
-
catch (e) {
|
|
1200
|
-
serverCtx.serve500(req, res, e, `serveDevNodeModule`);
|
|
1201
|
-
}
|
|
1202
|
+
async function serveDevNodeModule(serverCtx, req, res) {
|
|
1203
|
+
try {
|
|
1204
|
+
const results = await serverCtx.getCompilerRequest(req.pathname);
|
|
1205
|
+
const headers = {
|
|
1206
|
+
'content-type': 'application/javascript; charset=utf-8',
|
|
1207
|
+
'content-length': Buffer.byteLength(results.content, 'utf8'),
|
|
1208
|
+
'x-dev-node-module-id': results.nodeModuleId,
|
|
1209
|
+
'x-dev-node-module-version': results.nodeModuleVersion,
|
|
1210
|
+
'x-dev-node-module-resolved-path': results.nodeResolvedPath,
|
|
1211
|
+
'x-dev-node-module-cache-path': results.cachePath,
|
|
1212
|
+
'x-dev-node-module-cache-hit': results.cacheHit,
|
|
1213
|
+
};
|
|
1214
|
+
res.writeHead(results.status, responseHeaders(headers));
|
|
1215
|
+
res.write(results.content);
|
|
1216
|
+
res.end();
|
|
1217
|
+
}
|
|
1218
|
+
catch (e) {
|
|
1219
|
+
serverCtx.serve500(req, res, e, `serveDevNodeModule`);
|
|
1220
|
+
}
|
|
1202
1221
|
}
|
|
1203
1222
|
|
|
1204
|
-
async function serveDirectoryIndex(devServerConfig, serverCtx, req, res) {
|
|
1205
|
-
const indexFilePath = path__default['default'].join(req.filePath, 'index.html');
|
|
1206
|
-
req.stats = await serverCtx.sys.stat(indexFilePath);
|
|
1207
|
-
if (req.stats.isFile) {
|
|
1208
|
-
req.filePath = indexFilePath;
|
|
1209
|
-
return serveFile(devServerConfig, serverCtx, req, res);
|
|
1210
|
-
}
|
|
1211
|
-
if (!req.pathname.endsWith('/')) {
|
|
1212
|
-
return serverCtx.serve302(req, res, req.pathname + '/');
|
|
1213
|
-
}
|
|
1214
|
-
try {
|
|
1215
|
-
const dirFilePaths = await serverCtx.sys.readDir(req.filePath);
|
|
1216
|
-
try {
|
|
1217
|
-
if (serverCtx.dirTemplate == null) {
|
|
1218
|
-
const dirTemplatePath = path__default['default'].join(devServerConfig.devServerDir, 'templates', 'directory-index.html');
|
|
1219
|
-
serverCtx.dirTemplate = serverCtx.sys.readFileSync(dirTemplatePath);
|
|
1220
|
-
}
|
|
1221
|
-
const files = await getFiles(serverCtx.sys, req.url, dirFilePaths);
|
|
1222
|
-
const templateHtml = serverCtx.dirTemplate
|
|
1223
|
-
.replace('{{title}}', getTitle(req.pathname))
|
|
1224
|
-
.replace('{{nav}}', getName(req.pathname))
|
|
1225
|
-
.replace('{{files}}', files);
|
|
1226
|
-
serverCtx.logRequest(req, 200);
|
|
1227
|
-
res.writeHead(200, responseHeaders({
|
|
1228
|
-
'content-type': 'text/html; charset=utf-8',
|
|
1229
|
-
'x-directory-index': req.pathname,
|
|
1230
|
-
}));
|
|
1231
|
-
res.write(templateHtml);
|
|
1232
|
-
res.end();
|
|
1233
|
-
}
|
|
1234
|
-
catch (e) {
|
|
1235
|
-
return serverCtx.serve500(req, res, e, 'serveDirectoryIndex');
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
catch (e) {
|
|
1239
|
-
return serverCtx.serve404(req, res, 'serveDirectoryIndex');
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
async function getFiles(sys, baseUrl, dirItemNames) {
|
|
1243
|
-
const items = await getDirectoryItems(sys, baseUrl, dirItemNames);
|
|
1244
|
-
if (baseUrl.pathname !== '/') {
|
|
1245
|
-
items.unshift({
|
|
1246
|
-
isDirectory: true,
|
|
1247
|
-
pathname: '../',
|
|
1248
|
-
name: '..',
|
|
1249
|
-
});
|
|
1250
|
-
}
|
|
1251
|
-
return items
|
|
1252
|
-
.map((item) => {
|
|
1223
|
+
async function serveDirectoryIndex(devServerConfig, serverCtx, req, res) {
|
|
1224
|
+
const indexFilePath = path__default['default'].join(req.filePath, 'index.html');
|
|
1225
|
+
req.stats = await serverCtx.sys.stat(indexFilePath);
|
|
1226
|
+
if (req.stats.isFile) {
|
|
1227
|
+
req.filePath = indexFilePath;
|
|
1228
|
+
return serveFile(devServerConfig, serverCtx, req, res);
|
|
1229
|
+
}
|
|
1230
|
+
if (!req.pathname.endsWith('/')) {
|
|
1231
|
+
return serverCtx.serve302(req, res, req.pathname + '/');
|
|
1232
|
+
}
|
|
1233
|
+
try {
|
|
1234
|
+
const dirFilePaths = await serverCtx.sys.readDir(req.filePath);
|
|
1235
|
+
try {
|
|
1236
|
+
if (serverCtx.dirTemplate == null) {
|
|
1237
|
+
const dirTemplatePath = path__default['default'].join(devServerConfig.devServerDir, 'templates', 'directory-index.html');
|
|
1238
|
+
serverCtx.dirTemplate = serverCtx.sys.readFileSync(dirTemplatePath);
|
|
1239
|
+
}
|
|
1240
|
+
const files = await getFiles(serverCtx.sys, req.url, dirFilePaths);
|
|
1241
|
+
const templateHtml = serverCtx.dirTemplate
|
|
1242
|
+
.replace('{{title}}', getTitle(req.pathname))
|
|
1243
|
+
.replace('{{nav}}', getName(req.pathname))
|
|
1244
|
+
.replace('{{files}}', files);
|
|
1245
|
+
serverCtx.logRequest(req, 200);
|
|
1246
|
+
res.writeHead(200, responseHeaders({
|
|
1247
|
+
'content-type': 'text/html; charset=utf-8',
|
|
1248
|
+
'x-directory-index': req.pathname,
|
|
1249
|
+
}));
|
|
1250
|
+
res.write(templateHtml);
|
|
1251
|
+
res.end();
|
|
1252
|
+
}
|
|
1253
|
+
catch (e) {
|
|
1254
|
+
return serverCtx.serve500(req, res, e, 'serveDirectoryIndex');
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
catch (e) {
|
|
1258
|
+
return serverCtx.serve404(req, res, 'serveDirectoryIndex');
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
async function getFiles(sys, baseUrl, dirItemNames) {
|
|
1262
|
+
const items = await getDirectoryItems(sys, baseUrl, dirItemNames);
|
|
1263
|
+
if (baseUrl.pathname !== '/') {
|
|
1264
|
+
items.unshift({
|
|
1265
|
+
isDirectory: true,
|
|
1266
|
+
pathname: '../',
|
|
1267
|
+
name: '..',
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
return items
|
|
1271
|
+
.map((item) => {
|
|
1253
1272
|
return `
|
|
1254
1273
|
<li class="${item.isDirectory ? 'directory' : 'file'}">
|
|
1255
1274
|
<a href="${item.pathname}">
|
|
1256
1275
|
<span class="icon"></span>
|
|
1257
1276
|
<span>${item.name}</span>
|
|
1258
1277
|
</a>
|
|
1259
|
-
</li>`;
|
|
1260
|
-
})
|
|
1261
|
-
.join('');
|
|
1262
|
-
}
|
|
1263
|
-
async function getDirectoryItems(sys, baseUrl, dirFilePaths) {
|
|
1264
|
-
const items = await Promise.all(dirFilePaths.map(async (dirFilePath) => {
|
|
1265
|
-
const fileName = path__default['default'].basename(dirFilePath);
|
|
1266
|
-
const url = new URL(fileName, baseUrl);
|
|
1267
|
-
const stats = await sys.stat(dirFilePath);
|
|
1268
|
-
const item = {
|
|
1269
|
-
name: fileName,
|
|
1270
|
-
pathname: url.pathname,
|
|
1271
|
-
isDirectory: stats.isDirectory,
|
|
1272
|
-
};
|
|
1273
|
-
return item;
|
|
1274
|
-
}));
|
|
1275
|
-
return items;
|
|
1276
|
-
}
|
|
1277
|
-
function getTitle(pathName) {
|
|
1278
|
-
return pathName;
|
|
1279
|
-
}
|
|
1280
|
-
function getName(pathName) {
|
|
1281
|
-
const dirs = pathName.split('/');
|
|
1282
|
-
dirs.pop();
|
|
1283
|
-
let url = '';
|
|
1284
|
-
return (dirs
|
|
1285
|
-
.map((dir, index) => {
|
|
1286
|
-
url += dir + '/';
|
|
1287
|
-
const text = index === 0 ? `~` : dir;
|
|
1288
|
-
return `<a href="${url}">${text}</a>`;
|
|
1289
|
-
})
|
|
1290
|
-
.join('<span>/</span>') + '<span>/</span>');
|
|
1278
|
+
</li>`;
|
|
1279
|
+
})
|
|
1280
|
+
.join('');
|
|
1281
|
+
}
|
|
1282
|
+
async function getDirectoryItems(sys, baseUrl, dirFilePaths) {
|
|
1283
|
+
const items = await Promise.all(dirFilePaths.map(async (dirFilePath) => {
|
|
1284
|
+
const fileName = path__default['default'].basename(dirFilePath);
|
|
1285
|
+
const url = new URL(fileName, baseUrl);
|
|
1286
|
+
const stats = await sys.stat(dirFilePath);
|
|
1287
|
+
const item = {
|
|
1288
|
+
name: fileName,
|
|
1289
|
+
pathname: url.pathname,
|
|
1290
|
+
isDirectory: stats.isDirectory,
|
|
1291
|
+
};
|
|
1292
|
+
return item;
|
|
1293
|
+
}));
|
|
1294
|
+
return items;
|
|
1295
|
+
}
|
|
1296
|
+
function getTitle(pathName) {
|
|
1297
|
+
return pathName;
|
|
1298
|
+
}
|
|
1299
|
+
function getName(pathName) {
|
|
1300
|
+
const dirs = pathName.split('/');
|
|
1301
|
+
dirs.pop();
|
|
1302
|
+
let url = '';
|
|
1303
|
+
return (dirs
|
|
1304
|
+
.map((dir, index) => {
|
|
1305
|
+
url += dir + '/';
|
|
1306
|
+
const text = index === 0 ? `~` : dir;
|
|
1307
|
+
return `<a href="${url}">${text}</a>`;
|
|
1308
|
+
})
|
|
1309
|
+
.join('<span>/</span>') + '<span>/</span>');
|
|
1291
1310
|
}
|
|
1292
1311
|
|
|
1293
|
-
async function ssrPageRequest(devServerConfig, serverCtx, req, res) {
|
|
1294
|
-
try {
|
|
1295
|
-
let status = 500;
|
|
1296
|
-
let content = '';
|
|
1297
|
-
const { hydrateApp, srcIndexHtml, diagnostics } = await setupHydrateApp(devServerConfig, serverCtx);
|
|
1298
|
-
if (!diagnostics.some((diagnostic) => diagnostic.level === 'error')) {
|
|
1299
|
-
try {
|
|
1300
|
-
const opts = getSsrHydrateOptions(devServerConfig, serverCtx, req.url);
|
|
1301
|
-
const ssrResults = await hydrateApp.renderToString(srcIndexHtml, opts);
|
|
1302
|
-
diagnostics.push(...ssrResults.diagnostics);
|
|
1303
|
-
status = ssrResults.httpStatus;
|
|
1304
|
-
content = ssrResults.html;
|
|
1305
|
-
}
|
|
1306
|
-
catch (e) {
|
|
1307
|
-
catchError(diagnostics, e);
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
if (diagnostics.some((diagnostic) => diagnostic.level === 'error')) {
|
|
1311
|
-
content = getSsrErrorContent(diagnostics);
|
|
1312
|
-
status = 500;
|
|
1313
|
-
}
|
|
1314
|
-
if (devServerConfig.websocket) {
|
|
1315
|
-
content = appendDevServerClientScript(devServerConfig, req, content);
|
|
1316
|
-
}
|
|
1317
|
-
serverCtx.logRequest(req, status);
|
|
1318
|
-
res.writeHead(status, responseHeaders({
|
|
1319
|
-
'content-type': 'text/html; charset=utf-8',
|
|
1320
|
-
'content-length': Buffer.byteLength(content, 'utf8'),
|
|
1321
|
-
}));
|
|
1322
|
-
res.write(content);
|
|
1323
|
-
res.end();
|
|
1324
|
-
}
|
|
1325
|
-
catch (e) {
|
|
1326
|
-
serverCtx.serve500(req, res, e, `ssrPageRequest`);
|
|
1327
|
-
}
|
|
1328
|
-
}
|
|
1329
|
-
async function ssrStaticDataRequest(devServerConfig, serverCtx, req, res) {
|
|
1330
|
-
try {
|
|
1331
|
-
const data = {};
|
|
1332
|
-
let httpCache = false;
|
|
1333
|
-
const { hydrateApp, srcIndexHtml, diagnostics } = await setupHydrateApp(devServerConfig, serverCtx);
|
|
1334
|
-
if (!diagnostics.some((diagnostic) => diagnostic.level === 'error')) {
|
|
1335
|
-
try {
|
|
1336
|
-
const { ssrPath, hasQueryString } = getSsrStaticDataPath(req);
|
|
1337
|
-
const url = new URL(ssrPath, req.url);
|
|
1338
|
-
const opts = getSsrHydrateOptions(devServerConfig, serverCtx, url);
|
|
1339
|
-
const ssrResults = await hydrateApp.renderToString(srcIndexHtml, opts);
|
|
1340
|
-
diagnostics.push(...ssrResults.diagnostics);
|
|
1341
|
-
ssrResults.staticData.forEach((s) => {
|
|
1342
|
-
if (s.type === 'application/json') {
|
|
1343
|
-
data[s.id] = JSON.parse(s.content);
|
|
1344
|
-
}
|
|
1345
|
-
else {
|
|
1346
|
-
data[s.id] = s.content;
|
|
1347
|
-
}
|
|
1348
|
-
});
|
|
1349
|
-
data.components = ssrResults.components.map((c) => c.tag).sort();
|
|
1350
|
-
httpCache = hasQueryString;
|
|
1351
|
-
}
|
|
1352
|
-
catch (e) {
|
|
1353
|
-
catchError(diagnostics, e);
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
if (diagnostics.length > 0) {
|
|
1357
|
-
data.diagnostics = diagnostics;
|
|
1358
|
-
}
|
|
1359
|
-
const status = diagnostics.some((diagnostic) => diagnostic.level === 'error') ? 500 : 200;
|
|
1360
|
-
const content = JSON.stringify(data);
|
|
1361
|
-
serverCtx.logRequest(req, status);
|
|
1362
|
-
res.writeHead(status, responseHeaders({
|
|
1363
|
-
'content-type': 'application/json; charset=utf-8',
|
|
1364
|
-
'content-length': Buffer.byteLength(content, 'utf8'),
|
|
1365
|
-
}, httpCache && status === 200));
|
|
1366
|
-
res.write(content);
|
|
1367
|
-
res.end();
|
|
1368
|
-
}
|
|
1369
|
-
catch (e) {
|
|
1370
|
-
serverCtx.serve500(req, res, e, `ssrStaticDataRequest`);
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
async function setupHydrateApp(devServerConfig, serverCtx) {
|
|
1374
|
-
let srcIndexHtml = null;
|
|
1375
|
-
let hydrateApp = null;
|
|
1376
|
-
const buildResults = await serverCtx.getBuildResults();
|
|
1377
|
-
const diagnostics = [];
|
|
1378
|
-
if (serverCtx.prerenderConfig == null && isString(devServerConfig.prerenderConfig)) {
|
|
1379
|
-
const compilerPath = path__default['default'].join(devServerConfig.devServerDir, '..', 'compiler', 'rindo.js');
|
|
1380
|
-
const compiler = require(compilerPath);
|
|
1381
|
-
const prerenderConfigResults = compiler.nodeRequire(devServerConfig.prerenderConfig);
|
|
1382
|
-
diagnostics.push(...prerenderConfigResults.diagnostics);
|
|
1383
|
-
if (prerenderConfigResults.module && prerenderConfigResults.module.config) {
|
|
1384
|
-
serverCtx.prerenderConfig = prerenderConfigResults.module.config;
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
if (!isString(buildResults.hydrateAppFilePath)) {
|
|
1388
|
-
diagnostics.push({ messageText: `Missing hydrateAppFilePath`, level: `error`, type: `ssr`, lines: [] });
|
|
1389
|
-
}
|
|
1390
|
-
else if (!isString(devServerConfig.srcIndexHtml)) {
|
|
1391
|
-
diagnostics.push({ messageText: `Missing srcIndexHtml`, level: `error`, type: `ssr`, lines: [] });
|
|
1392
|
-
}
|
|
1393
|
-
else {
|
|
1394
|
-
srcIndexHtml = await serverCtx.sys.readFile(devServerConfig.srcIndexHtml);
|
|
1395
|
-
if (!isString(srcIndexHtml)) {
|
|
1396
|
-
diagnostics.push({
|
|
1397
|
-
level: `error`,
|
|
1398
|
-
lines: [],
|
|
1399
|
-
messageText: `Unable to load src index html: ${devServerConfig.srcIndexHtml}`,
|
|
1400
|
-
type: `ssr`,
|
|
1401
|
-
});
|
|
1402
|
-
}
|
|
1403
|
-
else {
|
|
1404
|
-
// ensure we cleared out node's internal require() cache for this file
|
|
1405
|
-
const hydrateAppFilePath = path__default['default'].resolve(buildResults.hydrateAppFilePath);
|
|
1406
|
-
// brute force way of clearning node's module cache
|
|
1407
|
-
// not using `delete require.cache[id]` since it'll cause memory leaks
|
|
1408
|
-
require.cache = {};
|
|
1409
|
-
const Module = require('module');
|
|
1410
|
-
Module._cache[hydrateAppFilePath] = undefined;
|
|
1411
|
-
hydrateApp = require(hydrateAppFilePath);
|
|
1412
|
-
}
|
|
1413
|
-
}
|
|
1414
|
-
return {
|
|
1415
|
-
hydrateApp,
|
|
1416
|
-
srcIndexHtml,
|
|
1417
|
-
diagnostics,
|
|
1418
|
-
};
|
|
1419
|
-
}
|
|
1420
|
-
function getSsrHydrateOptions(devServerConfig, serverCtx, url) {
|
|
1421
|
-
const opts = {
|
|
1422
|
-
url: url.href,
|
|
1423
|
-
addModulePreloads: false,
|
|
1424
|
-
approximateLineWidth: 120,
|
|
1425
|
-
inlineExternalStyleSheets: false,
|
|
1426
|
-
minifyScriptElements: false,
|
|
1427
|
-
minifyStyleElements: false,
|
|
1428
|
-
removeAttributeQuotes: false,
|
|
1429
|
-
removeBooleanAttributeQuotes: false,
|
|
1430
|
-
removeEmptyAttributes: false,
|
|
1431
|
-
removeHtmlComments: false,
|
|
1432
|
-
prettyHtml: true,
|
|
1433
|
-
};
|
|
1434
|
-
const prerenderConfig = serverCtx === null || serverCtx === void 0 ? void 0 : serverCtx.prerenderConfig;
|
|
1435
|
-
if (isFunction(prerenderConfig === null || prerenderConfig === void 0 ? void 0 : prerenderConfig.hydrateOptions)) {
|
|
1436
|
-
const userOpts = prerenderConfig.hydrateOptions(url);
|
|
1437
|
-
if (userOpts) {
|
|
1438
|
-
Object.assign(opts, userOpts);
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
|
-
if (isFunction(serverCtx.sys.applyPrerenderGlobalPatch)) {
|
|
1442
|
-
const orgBeforeHydrate = opts.beforeHydrate;
|
|
1443
|
-
opts.beforeHydrate = (document) => {
|
|
1444
|
-
// patch this new window with the fetch global from node-fetch
|
|
1445
|
-
const devServerBaseUrl = new URL(devServerConfig.browserUrl);
|
|
1446
|
-
const devServerHostUrl = devServerBaseUrl.origin;
|
|
1447
|
-
serverCtx.sys.applyPrerenderGlobalPatch({
|
|
1448
|
-
devServerHostUrl: devServerHostUrl,
|
|
1449
|
-
window: document.defaultView,
|
|
1450
|
-
});
|
|
1451
|
-
if (typeof orgBeforeHydrate === 'function') {
|
|
1452
|
-
return orgBeforeHydrate(document);
|
|
1453
|
-
}
|
|
1454
|
-
};
|
|
1455
|
-
}
|
|
1456
|
-
return opts;
|
|
1457
|
-
}
|
|
1458
|
-
function getSsrErrorContent(diagnostics) {
|
|
1312
|
+
async function ssrPageRequest(devServerConfig, serverCtx, req, res) {
|
|
1313
|
+
try {
|
|
1314
|
+
let status = 500;
|
|
1315
|
+
let content = '';
|
|
1316
|
+
const { hydrateApp, srcIndexHtml, diagnostics } = await setupHydrateApp(devServerConfig, serverCtx);
|
|
1317
|
+
if (!diagnostics.some((diagnostic) => diagnostic.level === 'error')) {
|
|
1318
|
+
try {
|
|
1319
|
+
const opts = getSsrHydrateOptions(devServerConfig, serverCtx, req.url);
|
|
1320
|
+
const ssrResults = await hydrateApp.renderToString(srcIndexHtml, opts);
|
|
1321
|
+
diagnostics.push(...ssrResults.diagnostics);
|
|
1322
|
+
status = ssrResults.httpStatus;
|
|
1323
|
+
content = ssrResults.html;
|
|
1324
|
+
}
|
|
1325
|
+
catch (e) {
|
|
1326
|
+
catchError(diagnostics, e);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
if (diagnostics.some((diagnostic) => diagnostic.level === 'error')) {
|
|
1330
|
+
content = getSsrErrorContent(diagnostics);
|
|
1331
|
+
status = 500;
|
|
1332
|
+
}
|
|
1333
|
+
if (devServerConfig.websocket) {
|
|
1334
|
+
content = appendDevServerClientScript(devServerConfig, req, content);
|
|
1335
|
+
}
|
|
1336
|
+
serverCtx.logRequest(req, status);
|
|
1337
|
+
res.writeHead(status, responseHeaders({
|
|
1338
|
+
'content-type': 'text/html; charset=utf-8',
|
|
1339
|
+
'content-length': Buffer.byteLength(content, 'utf8'),
|
|
1340
|
+
}));
|
|
1341
|
+
res.write(content);
|
|
1342
|
+
res.end();
|
|
1343
|
+
}
|
|
1344
|
+
catch (e) {
|
|
1345
|
+
serverCtx.serve500(req, res, e, `ssrPageRequest`);
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
async function ssrStaticDataRequest(devServerConfig, serverCtx, req, res) {
|
|
1349
|
+
try {
|
|
1350
|
+
const data = {};
|
|
1351
|
+
let httpCache = false;
|
|
1352
|
+
const { hydrateApp, srcIndexHtml, diagnostics } = await setupHydrateApp(devServerConfig, serverCtx);
|
|
1353
|
+
if (!diagnostics.some((diagnostic) => diagnostic.level === 'error')) {
|
|
1354
|
+
try {
|
|
1355
|
+
const { ssrPath, hasQueryString } = getSsrStaticDataPath(req);
|
|
1356
|
+
const url = new URL(ssrPath, req.url);
|
|
1357
|
+
const opts = getSsrHydrateOptions(devServerConfig, serverCtx, url);
|
|
1358
|
+
const ssrResults = await hydrateApp.renderToString(srcIndexHtml, opts);
|
|
1359
|
+
diagnostics.push(...ssrResults.diagnostics);
|
|
1360
|
+
ssrResults.staticData.forEach((s) => {
|
|
1361
|
+
if (s.type === 'application/json') {
|
|
1362
|
+
data[s.id] = JSON.parse(s.content);
|
|
1363
|
+
}
|
|
1364
|
+
else {
|
|
1365
|
+
data[s.id] = s.content;
|
|
1366
|
+
}
|
|
1367
|
+
});
|
|
1368
|
+
data.components = ssrResults.components.map((c) => c.tag).sort();
|
|
1369
|
+
httpCache = hasQueryString;
|
|
1370
|
+
}
|
|
1371
|
+
catch (e) {
|
|
1372
|
+
catchError(diagnostics, e);
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
if (diagnostics.length > 0) {
|
|
1376
|
+
data.diagnostics = diagnostics;
|
|
1377
|
+
}
|
|
1378
|
+
const status = diagnostics.some((diagnostic) => diagnostic.level === 'error') ? 500 : 200;
|
|
1379
|
+
const content = JSON.stringify(data);
|
|
1380
|
+
serverCtx.logRequest(req, status);
|
|
1381
|
+
res.writeHead(status, responseHeaders({
|
|
1382
|
+
'content-type': 'application/json; charset=utf-8',
|
|
1383
|
+
'content-length': Buffer.byteLength(content, 'utf8'),
|
|
1384
|
+
}, httpCache && status === 200));
|
|
1385
|
+
res.write(content);
|
|
1386
|
+
res.end();
|
|
1387
|
+
}
|
|
1388
|
+
catch (e) {
|
|
1389
|
+
serverCtx.serve500(req, res, e, `ssrStaticDataRequest`);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
async function setupHydrateApp(devServerConfig, serverCtx) {
|
|
1393
|
+
let srcIndexHtml = null;
|
|
1394
|
+
let hydrateApp = null;
|
|
1395
|
+
const buildResults = await serverCtx.getBuildResults();
|
|
1396
|
+
const diagnostics = [];
|
|
1397
|
+
if (serverCtx.prerenderConfig == null && isString(devServerConfig.prerenderConfig)) {
|
|
1398
|
+
const compilerPath = path__default['default'].join(devServerConfig.devServerDir, '..', 'compiler', 'rindo.js');
|
|
1399
|
+
const compiler = require(compilerPath);
|
|
1400
|
+
const prerenderConfigResults = compiler.nodeRequire(devServerConfig.prerenderConfig);
|
|
1401
|
+
diagnostics.push(...prerenderConfigResults.diagnostics);
|
|
1402
|
+
if (prerenderConfigResults.module && prerenderConfigResults.module.config) {
|
|
1403
|
+
serverCtx.prerenderConfig = prerenderConfigResults.module.config;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
if (!isString(buildResults.hydrateAppFilePath)) {
|
|
1407
|
+
diagnostics.push({ messageText: `Missing hydrateAppFilePath`, level: `error`, type: `ssr`, lines: [] });
|
|
1408
|
+
}
|
|
1409
|
+
else if (!isString(devServerConfig.srcIndexHtml)) {
|
|
1410
|
+
diagnostics.push({ messageText: `Missing srcIndexHtml`, level: `error`, type: `ssr`, lines: [] });
|
|
1411
|
+
}
|
|
1412
|
+
else {
|
|
1413
|
+
srcIndexHtml = await serverCtx.sys.readFile(devServerConfig.srcIndexHtml);
|
|
1414
|
+
if (!isString(srcIndexHtml)) {
|
|
1415
|
+
diagnostics.push({
|
|
1416
|
+
level: `error`,
|
|
1417
|
+
lines: [],
|
|
1418
|
+
messageText: `Unable to load src index html: ${devServerConfig.srcIndexHtml}`,
|
|
1419
|
+
type: `ssr`,
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
else {
|
|
1423
|
+
// ensure we cleared out node's internal require() cache for this file
|
|
1424
|
+
const hydrateAppFilePath = path__default['default'].resolve(buildResults.hydrateAppFilePath);
|
|
1425
|
+
// brute force way of clearning node's module cache
|
|
1426
|
+
// not using `delete require.cache[id]` since it'll cause memory leaks
|
|
1427
|
+
require.cache = {};
|
|
1428
|
+
const Module = require('module');
|
|
1429
|
+
Module._cache[hydrateAppFilePath] = undefined;
|
|
1430
|
+
hydrateApp = require(hydrateAppFilePath);
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
return {
|
|
1434
|
+
hydrateApp,
|
|
1435
|
+
srcIndexHtml,
|
|
1436
|
+
diagnostics,
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
function getSsrHydrateOptions(devServerConfig, serverCtx, url) {
|
|
1440
|
+
const opts = {
|
|
1441
|
+
url: url.href,
|
|
1442
|
+
addModulePreloads: false,
|
|
1443
|
+
approximateLineWidth: 120,
|
|
1444
|
+
inlineExternalStyleSheets: false,
|
|
1445
|
+
minifyScriptElements: false,
|
|
1446
|
+
minifyStyleElements: false,
|
|
1447
|
+
removeAttributeQuotes: false,
|
|
1448
|
+
removeBooleanAttributeQuotes: false,
|
|
1449
|
+
removeEmptyAttributes: false,
|
|
1450
|
+
removeHtmlComments: false,
|
|
1451
|
+
prettyHtml: true,
|
|
1452
|
+
};
|
|
1453
|
+
const prerenderConfig = serverCtx === null || serverCtx === void 0 ? void 0 : serverCtx.prerenderConfig;
|
|
1454
|
+
if (isFunction(prerenderConfig === null || prerenderConfig === void 0 ? void 0 : prerenderConfig.hydrateOptions)) {
|
|
1455
|
+
const userOpts = prerenderConfig.hydrateOptions(url);
|
|
1456
|
+
if (userOpts) {
|
|
1457
|
+
Object.assign(opts, userOpts);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
if (isFunction(serverCtx.sys.applyPrerenderGlobalPatch)) {
|
|
1461
|
+
const orgBeforeHydrate = opts.beforeHydrate;
|
|
1462
|
+
opts.beforeHydrate = (document) => {
|
|
1463
|
+
// patch this new window with the fetch global from node-fetch
|
|
1464
|
+
const devServerBaseUrl = new URL(devServerConfig.browserUrl);
|
|
1465
|
+
const devServerHostUrl = devServerBaseUrl.origin;
|
|
1466
|
+
serverCtx.sys.applyPrerenderGlobalPatch({
|
|
1467
|
+
devServerHostUrl: devServerHostUrl,
|
|
1468
|
+
window: document.defaultView,
|
|
1469
|
+
});
|
|
1470
|
+
if (typeof orgBeforeHydrate === 'function') {
|
|
1471
|
+
return orgBeforeHydrate(document);
|
|
1472
|
+
}
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
return opts;
|
|
1476
|
+
}
|
|
1477
|
+
function getSsrErrorContent(diagnostics) {
|
|
1459
1478
|
return `<!doctype html>
|
|
1460
1479
|
<html>
|
|
1461
1480
|
<head>
|
|
@@ -1474,330 +1493,330 @@ function getSsrErrorContent(diagnostics) {
|
|
|
1474
1493
|
</p>
|
|
1475
1494
|
`)}
|
|
1476
1495
|
</body>
|
|
1477
|
-
</html>`;
|
|
1496
|
+
</html>`;
|
|
1478
1497
|
}
|
|
1479
1498
|
|
|
1480
|
-
function createRequestHandler(devServerConfig, serverCtx) {
|
|
1481
|
-
let userRequestHandler = null;
|
|
1482
|
-
if (typeof devServerConfig.requestListenerPath === 'string') {
|
|
1483
|
-
userRequestHandler = require(devServerConfig.requestListenerPath);
|
|
1484
|
-
}
|
|
1485
|
-
return async function (incomingReq, res) {
|
|
1486
|
-
async function defaultHandler() {
|
|
1487
|
-
try {
|
|
1488
|
-
const req = normalizeHttpRequest(devServerConfig, incomingReq);
|
|
1489
|
-
if (!req.url) {
|
|
1490
|
-
return serverCtx.serve302(req, res);
|
|
1491
|
-
}
|
|
1492
|
-
if (isDevClient(req.pathname) && devServerConfig.websocket) {
|
|
1493
|
-
return serveDevClient(devServerConfig, serverCtx, req, res);
|
|
1494
|
-
}
|
|
1495
|
-
if (isDevModule(req.pathname)) {
|
|
1496
|
-
return serveDevNodeModule(serverCtx, req, res);
|
|
1497
|
-
}
|
|
1498
|
-
if (!isValidUrlBasePath(devServerConfig.basePath, req.url)) {
|
|
1499
|
-
return serverCtx.serve404(req, res, `invalid basePath`, `404 File Not Found, base path: ${devServerConfig.basePath}`);
|
|
1500
|
-
}
|
|
1501
|
-
if (devServerConfig.ssr) {
|
|
1502
|
-
if (isExtensionLessPath(req.url.pathname)) {
|
|
1503
|
-
return ssrPageRequest(devServerConfig, serverCtx, req, res);
|
|
1504
|
-
}
|
|
1505
|
-
if (isSsrStaticDataPath(req.url.pathname)) {
|
|
1506
|
-
return ssrStaticDataRequest(devServerConfig, serverCtx, req, res);
|
|
1507
|
-
}
|
|
1508
|
-
}
|
|
1509
|
-
req.stats = await serverCtx.sys.stat(req.filePath);
|
|
1510
|
-
if (req.stats.isFile) {
|
|
1511
|
-
return serveFile(devServerConfig, serverCtx, req, res);
|
|
1512
|
-
}
|
|
1513
|
-
if (req.stats.isDirectory) {
|
|
1514
|
-
return serveDirectoryIndex(devServerConfig, serverCtx, req, res);
|
|
1515
|
-
}
|
|
1516
|
-
const xSource = ['notfound'];
|
|
1517
|
-
const validHistoryApi = isValidHistoryApi(devServerConfig, req);
|
|
1518
|
-
xSource.push(`validHistoryApi: ${validHistoryApi}`);
|
|
1519
|
-
if (validHistoryApi) {
|
|
1520
|
-
try {
|
|
1521
|
-
const indexFilePath = path__default['default'].join(devServerConfig.root, devServerConfig.historyApiFallback.index);
|
|
1522
|
-
xSource.push(`indexFilePath: ${indexFilePath}`);
|
|
1523
|
-
req.stats = await serverCtx.sys.stat(indexFilePath);
|
|
1524
|
-
if (req.stats.isFile) {
|
|
1525
|
-
req.filePath = indexFilePath;
|
|
1526
|
-
return serveFile(devServerConfig, serverCtx, req, res);
|
|
1527
|
-
}
|
|
1528
|
-
}
|
|
1529
|
-
catch (e) {
|
|
1530
|
-
xSource.push(`notfound error: ${e}`);
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1533
|
-
return serverCtx.serve404(req, res, xSource.join(', '));
|
|
1534
|
-
}
|
|
1535
|
-
catch (e) {
|
|
1536
|
-
return serverCtx.serve500(incomingReq, res, e, `not found error`);
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1539
|
-
if (typeof userRequestHandler === 'function') {
|
|
1540
|
-
await userRequestHandler(incomingReq, res, defaultHandler);
|
|
1541
|
-
}
|
|
1542
|
-
else {
|
|
1543
|
-
await defaultHandler();
|
|
1544
|
-
}
|
|
1545
|
-
};
|
|
1546
|
-
}
|
|
1547
|
-
function isValidUrlBasePath(basePath, url) {
|
|
1548
|
-
// normalize the paths to always end with a slash for the check
|
|
1549
|
-
let pathname = url.pathname;
|
|
1550
|
-
if (!pathname.endsWith('/')) {
|
|
1551
|
-
pathname += '/';
|
|
1552
|
-
}
|
|
1553
|
-
if (!basePath.endsWith('/')) {
|
|
1554
|
-
basePath += '/';
|
|
1555
|
-
}
|
|
1556
|
-
return pathname.startsWith(basePath);
|
|
1557
|
-
}
|
|
1558
|
-
function normalizeHttpRequest(devServerConfig, incomingReq) {
|
|
1559
|
-
const req = {
|
|
1560
|
-
method: (incomingReq.method || 'GET').toUpperCase(),
|
|
1561
|
-
headers: incomingReq.headers,
|
|
1562
|
-
acceptHeader: (incomingReq.headers && typeof incomingReq.headers.accept === 'string' && incomingReq.headers.accept) || '',
|
|
1563
|
-
host: (incomingReq.headers && typeof incomingReq.headers.host === 'string' && incomingReq.headers.host) || null,
|
|
1564
|
-
url: null,
|
|
1565
|
-
searchParams: null,
|
|
1566
|
-
};
|
|
1567
|
-
const incomingUrl = (incomingReq.url || '').trim() || null;
|
|
1568
|
-
if (incomingUrl) {
|
|
1569
|
-
if (req.host) {
|
|
1570
|
-
req.url = new URL(incomingReq.url, `http://${req.host}`);
|
|
1571
|
-
}
|
|
1572
|
-
else {
|
|
1573
|
-
req.url = new URL(incomingReq.url, `http://rindojs-dev.web.app`);
|
|
1574
|
-
}
|
|
1575
|
-
req.searchParams = req.url.searchParams;
|
|
1576
|
-
}
|
|
1577
|
-
if (req.url) {
|
|
1578
|
-
const parts = req.url.pathname.replace(/\\/g, '/').split('/');
|
|
1579
|
-
req.pathname = parts.map((part) => decodeURIComponent(part)).join('/');
|
|
1580
|
-
if (req.pathname.length > 0 && !isDevClient(req.pathname)) {
|
|
1581
|
-
req.pathname = '/' + req.pathname.substring(devServerConfig.basePath.length);
|
|
1582
|
-
}
|
|
1583
|
-
req.filePath = normalizePath(path__default['default'].normalize(path__default['default'].join(devServerConfig.root, path__default['default'].relative('/', req.pathname))));
|
|
1584
|
-
}
|
|
1585
|
-
return req;
|
|
1586
|
-
}
|
|
1587
|
-
function isValidHistoryApi(devServerConfig, req) {
|
|
1588
|
-
if (!devServerConfig.historyApiFallback) {
|
|
1589
|
-
return false;
|
|
1590
|
-
}
|
|
1591
|
-
if (req.method !== 'GET') {
|
|
1592
|
-
return false;
|
|
1593
|
-
}
|
|
1594
|
-
if (!req.acceptHeader.includes('text/html')) {
|
|
1595
|
-
return false;
|
|
1596
|
-
}
|
|
1597
|
-
if (!devServerConfig.historyApiFallback.disableDotRule && req.pathname.includes('.')) {
|
|
1598
|
-
return false;
|
|
1599
|
-
}
|
|
1600
|
-
return true;
|
|
1499
|
+
function createRequestHandler(devServerConfig, serverCtx) {
|
|
1500
|
+
let userRequestHandler = null;
|
|
1501
|
+
if (typeof devServerConfig.requestListenerPath === 'string') {
|
|
1502
|
+
userRequestHandler = require(devServerConfig.requestListenerPath);
|
|
1503
|
+
}
|
|
1504
|
+
return async function (incomingReq, res) {
|
|
1505
|
+
async function defaultHandler() {
|
|
1506
|
+
try {
|
|
1507
|
+
const req = normalizeHttpRequest(devServerConfig, incomingReq);
|
|
1508
|
+
if (!req.url) {
|
|
1509
|
+
return serverCtx.serve302(req, res);
|
|
1510
|
+
}
|
|
1511
|
+
if (isDevClient(req.pathname) && devServerConfig.websocket) {
|
|
1512
|
+
return serveDevClient(devServerConfig, serverCtx, req, res);
|
|
1513
|
+
}
|
|
1514
|
+
if (isDevModule(req.pathname)) {
|
|
1515
|
+
return serveDevNodeModule(serverCtx, req, res);
|
|
1516
|
+
}
|
|
1517
|
+
if (!isValidUrlBasePath(devServerConfig.basePath, req.url)) {
|
|
1518
|
+
return serverCtx.serve404(req, res, `invalid basePath`, `404 File Not Found, base path: ${devServerConfig.basePath}`);
|
|
1519
|
+
}
|
|
1520
|
+
if (devServerConfig.ssr) {
|
|
1521
|
+
if (isExtensionLessPath(req.url.pathname)) {
|
|
1522
|
+
return ssrPageRequest(devServerConfig, serverCtx, req, res);
|
|
1523
|
+
}
|
|
1524
|
+
if (isSsrStaticDataPath(req.url.pathname)) {
|
|
1525
|
+
return ssrStaticDataRequest(devServerConfig, serverCtx, req, res);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
req.stats = await serverCtx.sys.stat(req.filePath);
|
|
1529
|
+
if (req.stats.isFile) {
|
|
1530
|
+
return serveFile(devServerConfig, serverCtx, req, res);
|
|
1531
|
+
}
|
|
1532
|
+
if (req.stats.isDirectory) {
|
|
1533
|
+
return serveDirectoryIndex(devServerConfig, serverCtx, req, res);
|
|
1534
|
+
}
|
|
1535
|
+
const xSource = ['notfound'];
|
|
1536
|
+
const validHistoryApi = isValidHistoryApi(devServerConfig, req);
|
|
1537
|
+
xSource.push(`validHistoryApi: ${validHistoryApi}`);
|
|
1538
|
+
if (validHistoryApi) {
|
|
1539
|
+
try {
|
|
1540
|
+
const indexFilePath = path__default['default'].join(devServerConfig.root, devServerConfig.historyApiFallback.index);
|
|
1541
|
+
xSource.push(`indexFilePath: ${indexFilePath}`);
|
|
1542
|
+
req.stats = await serverCtx.sys.stat(indexFilePath);
|
|
1543
|
+
if (req.stats.isFile) {
|
|
1544
|
+
req.filePath = indexFilePath;
|
|
1545
|
+
return serveFile(devServerConfig, serverCtx, req, res);
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
catch (e) {
|
|
1549
|
+
xSource.push(`notfound error: ${e}`);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
return serverCtx.serve404(req, res, xSource.join(', '));
|
|
1553
|
+
}
|
|
1554
|
+
catch (e) {
|
|
1555
|
+
return serverCtx.serve500(incomingReq, res, e, `not found error`);
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
if (typeof userRequestHandler === 'function') {
|
|
1559
|
+
await userRequestHandler(incomingReq, res, defaultHandler);
|
|
1560
|
+
}
|
|
1561
|
+
else {
|
|
1562
|
+
await defaultHandler();
|
|
1563
|
+
}
|
|
1564
|
+
};
|
|
1565
|
+
}
|
|
1566
|
+
function isValidUrlBasePath(basePath, url) {
|
|
1567
|
+
// normalize the paths to always end with a slash for the check
|
|
1568
|
+
let pathname = url.pathname;
|
|
1569
|
+
if (!pathname.endsWith('/')) {
|
|
1570
|
+
pathname += '/';
|
|
1571
|
+
}
|
|
1572
|
+
if (!basePath.endsWith('/')) {
|
|
1573
|
+
basePath += '/';
|
|
1574
|
+
}
|
|
1575
|
+
return pathname.startsWith(basePath);
|
|
1576
|
+
}
|
|
1577
|
+
function normalizeHttpRequest(devServerConfig, incomingReq) {
|
|
1578
|
+
const req = {
|
|
1579
|
+
method: (incomingReq.method || 'GET').toUpperCase(),
|
|
1580
|
+
headers: incomingReq.headers,
|
|
1581
|
+
acceptHeader: (incomingReq.headers && typeof incomingReq.headers.accept === 'string' && incomingReq.headers.accept) || '',
|
|
1582
|
+
host: (incomingReq.headers && typeof incomingReq.headers.host === 'string' && incomingReq.headers.host) || null,
|
|
1583
|
+
url: null,
|
|
1584
|
+
searchParams: null,
|
|
1585
|
+
};
|
|
1586
|
+
const incomingUrl = (incomingReq.url || '').trim() || null;
|
|
1587
|
+
if (incomingUrl) {
|
|
1588
|
+
if (req.host) {
|
|
1589
|
+
req.url = new URL(incomingReq.url, `http://${req.host}`);
|
|
1590
|
+
}
|
|
1591
|
+
else {
|
|
1592
|
+
req.url = new URL(incomingReq.url, `http://rindojs-dev.web.app`);
|
|
1593
|
+
}
|
|
1594
|
+
req.searchParams = req.url.searchParams;
|
|
1595
|
+
}
|
|
1596
|
+
if (req.url) {
|
|
1597
|
+
const parts = req.url.pathname.replace(/\\/g, '/').split('/');
|
|
1598
|
+
req.pathname = parts.map((part) => decodeURIComponent(part)).join('/');
|
|
1599
|
+
if (req.pathname.length > 0 && !isDevClient(req.pathname)) {
|
|
1600
|
+
req.pathname = '/' + req.pathname.substring(devServerConfig.basePath.length);
|
|
1601
|
+
}
|
|
1602
|
+
req.filePath = normalizePath(path__default['default'].normalize(path__default['default'].join(devServerConfig.root, path__default['default'].relative('/', req.pathname))));
|
|
1603
|
+
}
|
|
1604
|
+
return req;
|
|
1605
|
+
}
|
|
1606
|
+
function isValidHistoryApi(devServerConfig, req) {
|
|
1607
|
+
if (!devServerConfig.historyApiFallback) {
|
|
1608
|
+
return false;
|
|
1609
|
+
}
|
|
1610
|
+
if (req.method !== 'GET') {
|
|
1611
|
+
return false;
|
|
1612
|
+
}
|
|
1613
|
+
if (!req.acceptHeader.includes('text/html')) {
|
|
1614
|
+
return false;
|
|
1615
|
+
}
|
|
1616
|
+
if (!devServerConfig.historyApiFallback.disableDotRule && req.pathname.includes('.')) {
|
|
1617
|
+
return false;
|
|
1618
|
+
}
|
|
1619
|
+
return true;
|
|
1601
1620
|
}
|
|
1602
1621
|
|
|
1603
|
-
function createHttpServer(devServerConfig, serverCtx) {
|
|
1604
|
-
// create our request handler
|
|
1605
|
-
const reqHandler = createRequestHandler(devServerConfig, serverCtx);
|
|
1606
|
-
const credentials = devServerConfig.https;
|
|
1607
|
-
return credentials ? https__namespace.createServer(credentials, reqHandler) : http__namespace.createServer(reqHandler);
|
|
1608
|
-
}
|
|
1609
|
-
async function findClosestOpenPort(host, port) {
|
|
1610
|
-
async function t(portToCheck) {
|
|
1611
|
-
const isTaken = await isPortTaken(host, portToCheck);
|
|
1612
|
-
if (!isTaken) {
|
|
1613
|
-
return portToCheck;
|
|
1614
|
-
}
|
|
1615
|
-
return t(portToCheck + 1);
|
|
1616
|
-
}
|
|
1617
|
-
return t(port);
|
|
1618
|
-
}
|
|
1619
|
-
function isPortTaken(host, port) {
|
|
1620
|
-
return new Promise((resolve, reject) => {
|
|
1621
|
-
const tester = net__namespace
|
|
1622
|
-
.createServer()
|
|
1623
|
-
.once('error', () => {
|
|
1624
|
-
resolve(true);
|
|
1625
|
-
})
|
|
1626
|
-
.once('listening', () => {
|
|
1627
|
-
tester
|
|
1628
|
-
.once('close', () => {
|
|
1629
|
-
resolve(false);
|
|
1630
|
-
})
|
|
1631
|
-
.close();
|
|
1632
|
-
})
|
|
1633
|
-
.on('error', (err) => {
|
|
1634
|
-
reject(err);
|
|
1635
|
-
})
|
|
1636
|
-
.listen(port, host);
|
|
1637
|
-
});
|
|
1622
|
+
function createHttpServer(devServerConfig, serverCtx) {
|
|
1623
|
+
// create our request handler
|
|
1624
|
+
const reqHandler = createRequestHandler(devServerConfig, serverCtx);
|
|
1625
|
+
const credentials = devServerConfig.https;
|
|
1626
|
+
return credentials ? https__namespace.createServer(credentials, reqHandler) : http__namespace.createServer(reqHandler);
|
|
1627
|
+
}
|
|
1628
|
+
async function findClosestOpenPort(host, port) {
|
|
1629
|
+
async function t(portToCheck) {
|
|
1630
|
+
const isTaken = await isPortTaken(host, portToCheck);
|
|
1631
|
+
if (!isTaken) {
|
|
1632
|
+
return portToCheck;
|
|
1633
|
+
}
|
|
1634
|
+
return t(portToCheck + 1);
|
|
1635
|
+
}
|
|
1636
|
+
return t(port);
|
|
1637
|
+
}
|
|
1638
|
+
function isPortTaken(host, port) {
|
|
1639
|
+
return new Promise((resolve, reject) => {
|
|
1640
|
+
const tester = net__namespace
|
|
1641
|
+
.createServer()
|
|
1642
|
+
.once('error', () => {
|
|
1643
|
+
resolve(true);
|
|
1644
|
+
})
|
|
1645
|
+
.once('listening', () => {
|
|
1646
|
+
tester
|
|
1647
|
+
.once('close', () => {
|
|
1648
|
+
resolve(false);
|
|
1649
|
+
})
|
|
1650
|
+
.close();
|
|
1651
|
+
})
|
|
1652
|
+
.on('error', (err) => {
|
|
1653
|
+
reject(err);
|
|
1654
|
+
})
|
|
1655
|
+
.listen(port, host);
|
|
1656
|
+
});
|
|
1638
1657
|
}
|
|
1639
1658
|
|
|
1640
|
-
function createWebSocket(httpServer, onMessageFromClient) {
|
|
1641
|
-
const wsConfig = {
|
|
1642
|
-
server: httpServer,
|
|
1643
|
-
};
|
|
1644
|
-
const wsServer = new ws__namespace.Server(wsConfig);
|
|
1645
|
-
function heartbeat() {
|
|
1646
|
-
// we need to coerce the `ws` type to our custom `DevWS` type here, since
|
|
1647
|
-
// this function is going to be passed in to `ws.on('pong'` which expects
|
|
1648
|
-
// to be passed a functon where `this` is bound to `ws`.
|
|
1649
|
-
this.isAlive = true;
|
|
1650
|
-
}
|
|
1651
|
-
wsServer.on('connection', (ws) => {
|
|
1652
|
-
ws.on('message', (data) => {
|
|
1653
|
-
// the server process has received a message from the browser
|
|
1654
|
-
// pass the message received from the browser to the main cli process
|
|
1655
|
-
try {
|
|
1656
|
-
onMessageFromClient(JSON.parse(data.toString()));
|
|
1657
|
-
}
|
|
1658
|
-
catch (e) {
|
|
1659
|
-
console.error(e);
|
|
1660
|
-
}
|
|
1661
|
-
});
|
|
1662
|
-
ws.isAlive = true;
|
|
1663
|
-
ws.on('pong', heartbeat);
|
|
1664
|
-
// ignore invalid close frames sent by Safari 15
|
|
1665
|
-
ws.on('error', console.error);
|
|
1666
|
-
});
|
|
1667
|
-
const pingInternval = setInterval(() => {
|
|
1668
|
-
wsServer.clients.forEach((ws) => {
|
|
1669
|
-
if (!ws.isAlive) {
|
|
1670
|
-
return ws.close(1000);
|
|
1671
|
-
}
|
|
1672
|
-
ws.isAlive = false;
|
|
1673
|
-
ws.ping(noop);
|
|
1674
|
-
});
|
|
1675
|
-
}, 10000);
|
|
1676
|
-
return {
|
|
1677
|
-
sendToBrowser: (msg) => {
|
|
1678
|
-
if (msg && wsServer && wsServer.clients) {
|
|
1679
|
-
const data = JSON.stringify(msg);
|
|
1680
|
-
wsServer.clients.forEach((ws) => {
|
|
1681
|
-
if (ws.readyState === ws.OPEN) {
|
|
1682
|
-
ws.send(data);
|
|
1683
|
-
}
|
|
1684
|
-
});
|
|
1685
|
-
}
|
|
1686
|
-
},
|
|
1687
|
-
close: () => {
|
|
1688
|
-
return new Promise((resolve, reject) => {
|
|
1689
|
-
clearInterval(pingInternval);
|
|
1690
|
-
wsServer.clients.forEach((ws) => {
|
|
1691
|
-
ws.close(1000);
|
|
1692
|
-
});
|
|
1693
|
-
wsServer.close((err) => {
|
|
1694
|
-
if (err) {
|
|
1695
|
-
reject(err);
|
|
1696
|
-
}
|
|
1697
|
-
else {
|
|
1698
|
-
resolve();
|
|
1699
|
-
}
|
|
1700
|
-
});
|
|
1701
|
-
});
|
|
1702
|
-
},
|
|
1703
|
-
};
|
|
1659
|
+
function createWebSocket(httpServer, onMessageFromClient) {
|
|
1660
|
+
const wsConfig = {
|
|
1661
|
+
server: httpServer,
|
|
1662
|
+
};
|
|
1663
|
+
const wsServer = new ws__namespace.Server(wsConfig);
|
|
1664
|
+
function heartbeat() {
|
|
1665
|
+
// we need to coerce the `ws` type to our custom `DevWS` type here, since
|
|
1666
|
+
// this function is going to be passed in to `ws.on('pong'` which expects
|
|
1667
|
+
// to be passed a functon where `this` is bound to `ws`.
|
|
1668
|
+
this.isAlive = true;
|
|
1669
|
+
}
|
|
1670
|
+
wsServer.on('connection', (ws) => {
|
|
1671
|
+
ws.on('message', (data) => {
|
|
1672
|
+
// the server process has received a message from the browser
|
|
1673
|
+
// pass the message received from the browser to the main cli process
|
|
1674
|
+
try {
|
|
1675
|
+
onMessageFromClient(JSON.parse(data.toString()));
|
|
1676
|
+
}
|
|
1677
|
+
catch (e) {
|
|
1678
|
+
console.error(e);
|
|
1679
|
+
}
|
|
1680
|
+
});
|
|
1681
|
+
ws.isAlive = true;
|
|
1682
|
+
ws.on('pong', heartbeat);
|
|
1683
|
+
// ignore invalid close frames sent by Safari 15
|
|
1684
|
+
ws.on('error', console.error);
|
|
1685
|
+
});
|
|
1686
|
+
const pingInternval = setInterval(() => {
|
|
1687
|
+
wsServer.clients.forEach((ws) => {
|
|
1688
|
+
if (!ws.isAlive) {
|
|
1689
|
+
return ws.close(1000);
|
|
1690
|
+
}
|
|
1691
|
+
ws.isAlive = false;
|
|
1692
|
+
ws.ping(noop);
|
|
1693
|
+
});
|
|
1694
|
+
}, 10000);
|
|
1695
|
+
return {
|
|
1696
|
+
sendToBrowser: (msg) => {
|
|
1697
|
+
if (msg && wsServer && wsServer.clients) {
|
|
1698
|
+
const data = JSON.stringify(msg);
|
|
1699
|
+
wsServer.clients.forEach((ws) => {
|
|
1700
|
+
if (ws.readyState === ws.OPEN) {
|
|
1701
|
+
ws.send(data);
|
|
1702
|
+
}
|
|
1703
|
+
});
|
|
1704
|
+
}
|
|
1705
|
+
},
|
|
1706
|
+
close: () => {
|
|
1707
|
+
return new Promise((resolve, reject) => {
|
|
1708
|
+
clearInterval(pingInternval);
|
|
1709
|
+
wsServer.clients.forEach((ws) => {
|
|
1710
|
+
ws.close(1000);
|
|
1711
|
+
});
|
|
1712
|
+
wsServer.close((err) => {
|
|
1713
|
+
if (err) {
|
|
1714
|
+
reject(err);
|
|
1715
|
+
}
|
|
1716
|
+
else {
|
|
1717
|
+
resolve();
|
|
1718
|
+
}
|
|
1719
|
+
});
|
|
1720
|
+
});
|
|
1721
|
+
},
|
|
1722
|
+
};
|
|
1704
1723
|
}
|
|
1705
1724
|
|
|
1706
|
-
function initServerProcess(sendMsg) {
|
|
1707
|
-
let server = null;
|
|
1708
|
-
let webSocket = null;
|
|
1709
|
-
let serverCtx = null;
|
|
1710
|
-
const buildResultsResolves = [];
|
|
1711
|
-
const compilerRequestResolves = [];
|
|
1712
|
-
const startServer = async (msg) => {
|
|
1713
|
-
const devServerConfig = msg.startServer;
|
|
1714
|
-
devServerConfig.port = await findClosestOpenPort(devServerConfig.address, devServerConfig.port);
|
|
1715
|
-
devServerConfig.browserUrl = getBrowserUrl(devServerConfig.protocol, devServerConfig.address, devServerConfig.port, devServerConfig.basePath, '/');
|
|
1716
|
-
devServerConfig.root = normalizePath(devServerConfig.root);
|
|
1717
|
-
const sys = index_js.createNodeSys({ process });
|
|
1718
|
-
serverCtx = createServerContext(sys, sendMsg, devServerConfig, buildResultsResolves, compilerRequestResolves);
|
|
1719
|
-
server = createHttpServer(devServerConfig, serverCtx);
|
|
1720
|
-
webSocket = devServerConfig.websocket ? createWebSocket(server, sendMsg) : null;
|
|
1721
|
-
server.listen(devServerConfig.port, devServerConfig.address);
|
|
1722
|
-
serverCtx.isServerListening = true;
|
|
1723
|
-
if (devServerConfig.openBrowser) {
|
|
1724
|
-
const initialLoadUrl = getBrowserUrl(devServerConfig.protocol, devServerConfig.address, devServerConfig.port, devServerConfig.basePath, devServerConfig.initialLoadUrl || DEV_SERVER_INIT_URL);
|
|
1725
|
-
openInBrowser({ url: initialLoadUrl });
|
|
1726
|
-
}
|
|
1727
|
-
sendMsg({ serverStarted: devServerConfig });
|
|
1728
|
-
};
|
|
1729
|
-
const closeServer = () => {
|
|
1730
|
-
const promises = [];
|
|
1731
|
-
buildResultsResolves.forEach((r) => r.reject('dev server closed'));
|
|
1732
|
-
buildResultsResolves.length = 0;
|
|
1733
|
-
compilerRequestResolves.forEach((r) => r.reject('dev server closed'));
|
|
1734
|
-
compilerRequestResolves.length = 0;
|
|
1735
|
-
if (serverCtx) {
|
|
1736
|
-
if (serverCtx.sys) {
|
|
1737
|
-
promises.push(serverCtx.sys.destroy());
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1740
|
-
if (webSocket) {
|
|
1741
|
-
promises.push(webSocket.close());
|
|
1742
|
-
webSocket = null;
|
|
1743
|
-
}
|
|
1744
|
-
if (server) {
|
|
1745
|
-
promises.push(new Promise((resolve) => {
|
|
1746
|
-
server.close((err) => {
|
|
1747
|
-
if (err) {
|
|
1748
|
-
console.error(`close error: ${err}`);
|
|
1749
|
-
}
|
|
1750
|
-
resolve();
|
|
1751
|
-
});
|
|
1752
|
-
}));
|
|
1753
|
-
}
|
|
1754
|
-
Promise.all(promises).finally(() => {
|
|
1755
|
-
sendMsg({
|
|
1756
|
-
serverClosed: true,
|
|
1757
|
-
});
|
|
1758
|
-
});
|
|
1759
|
-
};
|
|
1760
|
-
const receiveMessageFromMain = (msg) => {
|
|
1761
|
-
// the server process received a message from main thread
|
|
1762
|
-
try {
|
|
1763
|
-
if (msg) {
|
|
1764
|
-
if (msg.startServer) {
|
|
1765
|
-
startServer(msg);
|
|
1766
|
-
}
|
|
1767
|
-
else if (msg.closeServer) {
|
|
1768
|
-
closeServer();
|
|
1769
|
-
}
|
|
1770
|
-
else if (msg.compilerRequestResults) {
|
|
1771
|
-
for (let i = compilerRequestResolves.length - 1; i >= 0; i--) {
|
|
1772
|
-
const r = compilerRequestResolves[i];
|
|
1773
|
-
if (r.path === msg.compilerRequestResults.path) {
|
|
1774
|
-
r.resolve(msg.compilerRequestResults);
|
|
1775
|
-
compilerRequestResolves.splice(i, 1);
|
|
1776
|
-
}
|
|
1777
|
-
}
|
|
1778
|
-
}
|
|
1779
|
-
else if (serverCtx) {
|
|
1780
|
-
if (msg.buildResults && !msg.isActivelyBuilding) {
|
|
1781
|
-
buildResultsResolves.forEach((r) => r.resolve(msg.buildResults));
|
|
1782
|
-
buildResultsResolves.length = 0;
|
|
1783
|
-
}
|
|
1784
|
-
if (webSocket) {
|
|
1785
|
-
webSocket.sendToBrowser(msg);
|
|
1786
|
-
}
|
|
1787
|
-
}
|
|
1788
|
-
}
|
|
1789
|
-
}
|
|
1790
|
-
catch (e) {
|
|
1791
|
-
let stack = null;
|
|
1792
|
-
if (e instanceof Error) {
|
|
1793
|
-
stack = e.stack;
|
|
1794
|
-
}
|
|
1795
|
-
sendMsg({
|
|
1796
|
-
error: { message: e + '', stack },
|
|
1797
|
-
});
|
|
1798
|
-
}
|
|
1799
|
-
};
|
|
1800
|
-
return receiveMessageFromMain;
|
|
1725
|
+
function initServerProcess(sendMsg) {
|
|
1726
|
+
let server = null;
|
|
1727
|
+
let webSocket = null;
|
|
1728
|
+
let serverCtx = null;
|
|
1729
|
+
const buildResultsResolves = [];
|
|
1730
|
+
const compilerRequestResolves = [];
|
|
1731
|
+
const startServer = async (msg) => {
|
|
1732
|
+
const devServerConfig = msg.startServer;
|
|
1733
|
+
devServerConfig.port = await findClosestOpenPort(devServerConfig.address, devServerConfig.port);
|
|
1734
|
+
devServerConfig.browserUrl = getBrowserUrl(devServerConfig.protocol, devServerConfig.address, devServerConfig.port, devServerConfig.basePath, '/');
|
|
1735
|
+
devServerConfig.root = normalizePath(devServerConfig.root);
|
|
1736
|
+
const sys = index_js.createNodeSys({ process });
|
|
1737
|
+
serverCtx = createServerContext(sys, sendMsg, devServerConfig, buildResultsResolves, compilerRequestResolves);
|
|
1738
|
+
server = createHttpServer(devServerConfig, serverCtx);
|
|
1739
|
+
webSocket = devServerConfig.websocket ? createWebSocket(server, sendMsg) : null;
|
|
1740
|
+
server.listen(devServerConfig.port, devServerConfig.address);
|
|
1741
|
+
serverCtx.isServerListening = true;
|
|
1742
|
+
if (devServerConfig.openBrowser) {
|
|
1743
|
+
const initialLoadUrl = getBrowserUrl(devServerConfig.protocol, devServerConfig.address, devServerConfig.port, devServerConfig.basePath, devServerConfig.initialLoadUrl || DEV_SERVER_INIT_URL);
|
|
1744
|
+
openInBrowser({ url: initialLoadUrl });
|
|
1745
|
+
}
|
|
1746
|
+
sendMsg({ serverStarted: devServerConfig });
|
|
1747
|
+
};
|
|
1748
|
+
const closeServer = () => {
|
|
1749
|
+
const promises = [];
|
|
1750
|
+
buildResultsResolves.forEach((r) => r.reject('dev server closed'));
|
|
1751
|
+
buildResultsResolves.length = 0;
|
|
1752
|
+
compilerRequestResolves.forEach((r) => r.reject('dev server closed'));
|
|
1753
|
+
compilerRequestResolves.length = 0;
|
|
1754
|
+
if (serverCtx) {
|
|
1755
|
+
if (serverCtx.sys) {
|
|
1756
|
+
promises.push(serverCtx.sys.destroy());
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
if (webSocket) {
|
|
1760
|
+
promises.push(webSocket.close());
|
|
1761
|
+
webSocket = null;
|
|
1762
|
+
}
|
|
1763
|
+
if (server) {
|
|
1764
|
+
promises.push(new Promise((resolve) => {
|
|
1765
|
+
server.close((err) => {
|
|
1766
|
+
if (err) {
|
|
1767
|
+
console.error(`close error: ${err}`);
|
|
1768
|
+
}
|
|
1769
|
+
resolve();
|
|
1770
|
+
});
|
|
1771
|
+
}));
|
|
1772
|
+
}
|
|
1773
|
+
Promise.all(promises).finally(() => {
|
|
1774
|
+
sendMsg({
|
|
1775
|
+
serverClosed: true,
|
|
1776
|
+
});
|
|
1777
|
+
});
|
|
1778
|
+
};
|
|
1779
|
+
const receiveMessageFromMain = (msg) => {
|
|
1780
|
+
// the server process received a message from main thread
|
|
1781
|
+
try {
|
|
1782
|
+
if (msg) {
|
|
1783
|
+
if (msg.startServer) {
|
|
1784
|
+
startServer(msg);
|
|
1785
|
+
}
|
|
1786
|
+
else if (msg.closeServer) {
|
|
1787
|
+
closeServer();
|
|
1788
|
+
}
|
|
1789
|
+
else if (msg.compilerRequestResults) {
|
|
1790
|
+
for (let i = compilerRequestResolves.length - 1; i >= 0; i--) {
|
|
1791
|
+
const r = compilerRequestResolves[i];
|
|
1792
|
+
if (r.path === msg.compilerRequestResults.path) {
|
|
1793
|
+
r.resolve(msg.compilerRequestResults);
|
|
1794
|
+
compilerRequestResolves.splice(i, 1);
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
else if (serverCtx) {
|
|
1799
|
+
if (msg.buildResults && !msg.isActivelyBuilding) {
|
|
1800
|
+
buildResultsResolves.forEach((r) => r.resolve(msg.buildResults));
|
|
1801
|
+
buildResultsResolves.length = 0;
|
|
1802
|
+
}
|
|
1803
|
+
if (webSocket) {
|
|
1804
|
+
webSocket.sendToBrowser(msg);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
catch (e) {
|
|
1810
|
+
let stack = null;
|
|
1811
|
+
if (e instanceof Error) {
|
|
1812
|
+
stack = e.stack;
|
|
1813
|
+
}
|
|
1814
|
+
sendMsg({
|
|
1815
|
+
error: { message: e + '', stack },
|
|
1816
|
+
});
|
|
1817
|
+
}
|
|
1818
|
+
};
|
|
1819
|
+
return receiveMessageFromMain;
|
|
1801
1820
|
}
|
|
1802
1821
|
|
|
1803
1822
|
exports.initServerProcess = initServerProcess;
|