@jsenv/core 40.12.12 → 40.12.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/build.js +259 -469
- package/dist/client/import_meta_css/import_meta_css_build.js +41 -12
- package/dist/client/import_meta_css/import_meta_css_dev.js +43 -31
- package/dist/start_build_server/jsenv_core_packages.js +1 -71
- package/dist/start_build_server/start_build_server.js +11 -56
- package/dist/start_dev_server/start_dev_server.js +247 -448
- package/package.json +2 -2
- package/src/build/build.js +16 -15
- package/src/build/build_specifier_manager.js +11 -10
- package/src/build/mappings_injection.js +12 -11
- package/src/build/start_build_server.js +12 -58
- package/src/dev/start_dev_server.js +26 -26
- package/src/kitchen/errors.js +11 -11
- package/src/kitchen/kitchen.js +29 -21
- package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +1 -1
- package/src/plugins/autoreload_on_server_restart/jsenv_plugin_autoreload_on_server_restart.js +1 -1
- package/src/plugins/chrome_devtools_json/jsenv_plugin_chrome_devtools_json.js +1 -1
- package/src/plugins/import_meta_css/client/import_meta_css_build.js +41 -12
- package/src/plugins/import_meta_css/client/import_meta_css_dev.js +43 -31
- package/src/plugins/import_meta_css/jsenv_plugin_import_meta_css.js +70 -17
- package/src/plugins/jsenv_plugins_controller.js +197 -0
- package/src/plugins/protocol_file/jsenv_plugin_directory_listing.js +1 -1
- package/src/plugins/server_events/jsenv_plugin_server_events.js +1 -1
- package/src/plugins/plugin_controller.js +0 -458
package/src/kitchen/kitchen.js
CHANGED
|
@@ -132,14 +132,14 @@ export const createKitchen = ({
|
|
|
132
132
|
},
|
|
133
133
|
graph: null,
|
|
134
134
|
urlInfoTransformer: null,
|
|
135
|
-
|
|
135
|
+
jsenvPluginsController: null,
|
|
136
136
|
};
|
|
137
137
|
const kitchenContext = kitchen.context;
|
|
138
138
|
kitchenContext.kitchen = kitchen;
|
|
139
139
|
|
|
140
|
-
let
|
|
141
|
-
kitchen.
|
|
142
|
-
|
|
140
|
+
let jsenvPluginsController;
|
|
141
|
+
kitchen.setJsenvPluginsController = (value) => {
|
|
142
|
+
jsenvPluginsController = kitchen.jsenvPluginsController = value;
|
|
143
143
|
};
|
|
144
144
|
|
|
145
145
|
const graph = createUrlGraph({
|
|
@@ -148,7 +148,11 @@ export const createKitchen = ({
|
|
|
148
148
|
kitchen,
|
|
149
149
|
});
|
|
150
150
|
graph.urlInfoCreatedEventEmitter.on((urlInfoCreated) => {
|
|
151
|
-
|
|
151
|
+
jsenvPluginsController.callHooks(
|
|
152
|
+
"urlInfoCreated",
|
|
153
|
+
urlInfoCreated,
|
|
154
|
+
() => {},
|
|
155
|
+
);
|
|
152
156
|
});
|
|
153
157
|
kitchen.graph = graph;
|
|
154
158
|
|
|
@@ -322,7 +326,7 @@ export const createKitchen = ({
|
|
|
322
326
|
setReferenceUrl(reference.url);
|
|
323
327
|
break resolve;
|
|
324
328
|
}
|
|
325
|
-
const resolvedUrl =
|
|
329
|
+
const resolvedUrl = jsenvPluginsController.callHooksUntil(
|
|
326
330
|
"resolveReference",
|
|
327
331
|
reference,
|
|
328
332
|
);
|
|
@@ -336,7 +340,7 @@ export const createKitchen = ({
|
|
|
336
340
|
setReferenceUrl(normalizedUrl);
|
|
337
341
|
if (reference.debug) {
|
|
338
342
|
logger.debug(`url resolved by "${
|
|
339
|
-
|
|
343
|
+
jsenvPluginsController.getLastPluginUsed().name
|
|
340
344
|
}"
|
|
341
345
|
${ANSI.color(reference.specifier, ANSI.GREY)} ->
|
|
342
346
|
${ANSI.color(reference.url, ANSI.YELLOW)}
|
|
@@ -350,7 +354,7 @@ ${ANSI.color(reference.url, ANSI.YELLOW)}
|
|
|
350
354
|
// - side_effect_file references injected in entry points or at the top of files
|
|
351
355
|
break redirect;
|
|
352
356
|
}
|
|
353
|
-
|
|
357
|
+
jsenvPluginsController.callHooks(
|
|
354
358
|
"redirectReference",
|
|
355
359
|
reference,
|
|
356
360
|
(returnValue, plugin, setReference) => {
|
|
@@ -395,7 +399,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
395
399
|
return reference;
|
|
396
400
|
} catch (error) {
|
|
397
401
|
throw createResolveUrlError({
|
|
398
|
-
|
|
402
|
+
jsenvPluginsController,
|
|
399
403
|
reference,
|
|
400
404
|
error,
|
|
401
405
|
});
|
|
@@ -422,7 +426,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
422
426
|
// But do not represent an other resource, it is considered as
|
|
423
427
|
// the same resource under the hood
|
|
424
428
|
const searchParamTransformationMap = new Map();
|
|
425
|
-
|
|
429
|
+
jsenvPluginsController.callHooks(
|
|
426
430
|
"transformReferenceSearchParams",
|
|
427
431
|
reference,
|
|
428
432
|
(returnValue) => {
|
|
@@ -450,7 +454,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
450
454
|
}
|
|
451
455
|
}
|
|
452
456
|
format: {
|
|
453
|
-
const returnValue =
|
|
457
|
+
const returnValue = jsenvPluginsController.callHooksUntil(
|
|
454
458
|
"formatReference",
|
|
455
459
|
reference,
|
|
456
460
|
);
|
|
@@ -471,7 +475,10 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
471
475
|
const fetchUrlContent = async (urlInfo) => {
|
|
472
476
|
try {
|
|
473
477
|
const fetchUrlContentReturnValue =
|
|
474
|
-
await
|
|
478
|
+
await jsenvPluginsController.callAsyncHooksUntil(
|
|
479
|
+
"fetchUrlContent",
|
|
480
|
+
urlInfo,
|
|
481
|
+
);
|
|
475
482
|
if (!fetchUrlContentReturnValue) {
|
|
476
483
|
logger.warn(
|
|
477
484
|
createDetailedMessage(
|
|
@@ -570,7 +577,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
570
577
|
});
|
|
571
578
|
} catch (error) {
|
|
572
579
|
throw createFetchUrlContentError({
|
|
573
|
-
|
|
580
|
+
jsenvPluginsController,
|
|
574
581
|
urlInfo,
|
|
575
582
|
error,
|
|
576
583
|
});
|
|
@@ -580,7 +587,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
580
587
|
|
|
581
588
|
const transformUrlContent = async (urlInfo) => {
|
|
582
589
|
try {
|
|
583
|
-
await
|
|
590
|
+
await jsenvPluginsController.callAsyncHooks(
|
|
584
591
|
"transformUrlContent",
|
|
585
592
|
urlInfo,
|
|
586
593
|
(transformReturnValue) => {
|
|
@@ -592,7 +599,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
592
599
|
);
|
|
593
600
|
} catch (error) {
|
|
594
601
|
const transformError = createTransformUrlContentError({
|
|
595
|
-
|
|
602
|
+
jsenvPluginsController,
|
|
596
603
|
urlInfo,
|
|
597
604
|
error,
|
|
598
605
|
});
|
|
@@ -604,14 +611,15 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
|
|
|
604
611
|
const finalizeUrlContent = async (urlInfo) => {
|
|
605
612
|
try {
|
|
606
613
|
await urlInfo.applyContentTransformationCallbacks();
|
|
607
|
-
const finalizeReturnValue =
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
614
|
+
const finalizeReturnValue =
|
|
615
|
+
await jsenvPluginsController.callAsyncHooksUntil(
|
|
616
|
+
"finalizeUrlContent",
|
|
617
|
+
urlInfo,
|
|
618
|
+
);
|
|
611
619
|
urlInfoTransformer.endTransformations(urlInfo, finalizeReturnValue);
|
|
612
620
|
} catch (error) {
|
|
613
621
|
throw createFinalizeUrlContentError({
|
|
614
|
-
|
|
622
|
+
jsenvPluginsController,
|
|
615
623
|
urlInfo,
|
|
616
624
|
error,
|
|
617
625
|
});
|
|
@@ -692,7 +700,7 @@ ${urlInfo.firstReference.trace.message}`;
|
|
|
692
700
|
}
|
|
693
701
|
|
|
694
702
|
// "cooked" hook
|
|
695
|
-
|
|
703
|
+
jsenvPluginsController.callHooks("cooked", urlInfo, (cookedReturnValue) => {
|
|
696
704
|
if (typeof cookedReturnValue === "function") {
|
|
697
705
|
const removeCallback = urlInfo.graph.urlInfoDereferencedEventEmitter.on(
|
|
698
706
|
(urlInfoDereferenced, lastReferenceFromOther) => {
|
package/src/plugins/autoreload_on_server_restart/jsenv_plugin_autoreload_on_server_restart.js
CHANGED
|
@@ -2,7 +2,7 @@ import { injectJsenvScript, parseHtml, stringifyHtmlAst } from "@jsenv/ast";
|
|
|
2
2
|
|
|
3
3
|
export const jsenvPluginAutoreloadOnServerRestart = () => {
|
|
4
4
|
const autoreloadOnRestartClientFileUrl = import.meta
|
|
5
|
-
.resolve("@jsenv/server/src/
|
|
5
|
+
.resolve("@jsenv/server/src/plugins/autoreload_on_server_restart/client/autoreload_on_server_restart.js");
|
|
6
6
|
|
|
7
7
|
return {
|
|
8
8
|
name: "jsenv:autoreload_on_server_restart",
|
|
@@ -25,7 +25,7 @@ export const jsenvPluginChromeDevtoolsJson = () => {
|
|
|
25
25
|
return {
|
|
26
26
|
name: "jsenv_plugin_chrome_devtools_json",
|
|
27
27
|
appliesDuring: "dev",
|
|
28
|
-
|
|
28
|
+
serverRoutes: [
|
|
29
29
|
{
|
|
30
30
|
endpoint: "GET /.well-known/appspecific/com.chrome.devtools.json",
|
|
31
31
|
declarationSource: import.meta.url,
|
|
@@ -1,20 +1,49 @@
|
|
|
1
1
|
export const installImportMetaCssBuild = (importMeta) => {
|
|
2
|
-
const
|
|
2
|
+
const IMPORT_META_CSS_BUILD = "jsenv_import_meta_css_build";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
if (importMeta.css === IMPORT_META_CSS_BUILD) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const stylesheetMap = new Map();
|
|
9
|
+
const adopt = (url, value) => {
|
|
10
|
+
const stylesheet = new CSSStyleSheet({ baseUrl: importMeta.url });
|
|
11
|
+
stylesheet.replaceSync(value);
|
|
12
|
+
stylesheetMap.set(url, stylesheet);
|
|
13
|
+
document.adoptedStyleSheets = [...document.adoptedStyleSheets, stylesheet];
|
|
14
|
+
};
|
|
15
|
+
const update = (url, value) => {
|
|
16
|
+
stylesheetMap.get(url).replaceSync(value);
|
|
17
|
+
};
|
|
18
|
+
const remove = (url) => {
|
|
19
|
+
const stylesheet = stylesheetMap.get(url);
|
|
20
|
+
document.adoptedStyleSheets = document.adoptedStyleSheets.filter(
|
|
21
|
+
(s) => s !== stylesheet,
|
|
22
|
+
);
|
|
23
|
+
stylesheetMap.delete(url);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const currentCssSourceMap = new Map();
|
|
6
27
|
Object.defineProperty(importMeta, "css", {
|
|
7
28
|
configurable: true,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
29
|
+
get() {
|
|
30
|
+
return IMPORT_META_CSS_BUILD;
|
|
31
|
+
},
|
|
32
|
+
set([value, url]) {
|
|
33
|
+
if (value === undefined) {
|
|
34
|
+
if (stylesheetMap.has(url)) {
|
|
35
|
+
remove(url);
|
|
36
|
+
currentCssSourceMap.delete(url);
|
|
37
|
+
}
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!stylesheetMap.has(url)) {
|
|
41
|
+
adopt(url, value);
|
|
42
|
+
currentCssSourceMap.set(url, value);
|
|
43
|
+
} else if (currentCssSourceMap.get(url) !== value) {
|
|
44
|
+
update(url, value);
|
|
45
|
+
currentCssSourceMap.set(url, value);
|
|
11
46
|
}
|
|
12
|
-
called = true;
|
|
13
|
-
stylesheet.replaceSync(value);
|
|
14
|
-
document.adoptedStyleSheets = [
|
|
15
|
-
...document.adoptedStyleSheets,
|
|
16
|
-
stylesheet,
|
|
17
|
-
];
|
|
18
47
|
},
|
|
19
48
|
});
|
|
20
49
|
};
|
|
@@ -1,46 +1,58 @@
|
|
|
1
1
|
export const installImportMetaCssDev = (importMeta) => {
|
|
2
|
-
|
|
3
|
-
let stylesheet = new CSSStyleSheet({ baseUrl: importMeta.url });
|
|
4
|
-
let adopted = false;
|
|
2
|
+
const IMPORT_META_CSS_DEV = "jsenv_import_meta_css_dev";
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
cssText += `
|
|
4
|
+
// useless today but browser might catch up to display it in devtools
|
|
5
|
+
const addUrlInfo = (cssText) => {
|
|
6
|
+
let cssTextWithUrlInfo = cssText;
|
|
7
|
+
cssTextWithUrlInfo += `
|
|
11
8
|
/* sourceURL=${importMeta.url} */
|
|
12
9
|
/* inlined from ${importMeta.url} */`;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
adopted = false;
|
|
30
|
-
}
|
|
31
|
-
},
|
|
10
|
+
return cssTextWithUrlInfo;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
let stylesheet;
|
|
14
|
+
const adopt = (value) => {
|
|
15
|
+
stylesheet = new CSSStyleSheet({ baseUrl: importMeta.url });
|
|
16
|
+
stylesheet.replaceSync(addUrlInfo(value));
|
|
17
|
+
document.adoptedStyleSheets = [...document.adoptedStyleSheets, stylesheet];
|
|
18
|
+
};
|
|
19
|
+
const update = (value) => {
|
|
20
|
+
stylesheet.replaceSync(addUrlInfo(value));
|
|
21
|
+
};
|
|
22
|
+
const remove = () => {
|
|
23
|
+
document.adoptedStyleSheets = document.adoptedStyleSheets.filter(
|
|
24
|
+
(s) => s !== stylesheet,
|
|
25
|
+
);
|
|
32
26
|
};
|
|
33
27
|
|
|
28
|
+
let currentCssSource;
|
|
34
29
|
Object.defineProperty(importMeta, "css", {
|
|
35
30
|
configurable: true,
|
|
36
31
|
get() {
|
|
37
|
-
return
|
|
32
|
+
return IMPORT_META_CSS_DEV;
|
|
38
33
|
},
|
|
39
34
|
set(value) {
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
if (value === undefined) {
|
|
36
|
+
if (stylesheet) {
|
|
37
|
+
remove();
|
|
38
|
+
stylesheet = undefined;
|
|
39
|
+
currentCssSource = undefined;
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (!stylesheet) {
|
|
44
|
+
adopt(value);
|
|
45
|
+
currentCssSource = value;
|
|
46
|
+
} else if (currentCssSource !== value) {
|
|
47
|
+
update(value);
|
|
48
|
+
currentCssSource = value;
|
|
49
|
+
}
|
|
42
50
|
},
|
|
43
51
|
});
|
|
44
52
|
|
|
45
|
-
return
|
|
53
|
+
return () => {
|
|
54
|
+
remove();
|
|
55
|
+
stylesheet = undefined;
|
|
56
|
+
currentCssSource = undefined;
|
|
57
|
+
};
|
|
46
58
|
};
|
|
@@ -36,11 +36,7 @@ export const jsenvPluginImportMetaCss = () => {
|
|
|
36
36
|
appliesDuring: "*",
|
|
37
37
|
transformUrlContent: {
|
|
38
38
|
js_module: async (urlInfo) => {
|
|
39
|
-
if (
|
|
40
|
-
!urlInfo.content.includes("import.meta.css") ||
|
|
41
|
-
// there is already our installImportMetaCssBuild in the file
|
|
42
|
-
urlInfo.content.includes("installImportMetaCssBuild")
|
|
43
|
-
) {
|
|
39
|
+
if (!urlInfo.content.includes("import.meta.css")) {
|
|
44
40
|
return null;
|
|
45
41
|
}
|
|
46
42
|
const { metadata } = await applyBabelPlugins({
|
|
@@ -54,22 +50,70 @@ export const jsenvPluginImportMetaCss = () => {
|
|
|
54
50
|
if (!usesImportMetaCss) {
|
|
55
51
|
return null;
|
|
56
52
|
}
|
|
53
|
+
if (urlInfo.context.build) {
|
|
54
|
+
const rootDirectoryUrl = urlInfo.context.rootDirectoryUrl;
|
|
55
|
+
const relativeUrl = urlInfo.originalUrl.slice(
|
|
56
|
+
rootDirectoryUrl.length - 1,
|
|
57
|
+
);
|
|
58
|
+
const { code } = await applyBabelPlugins({
|
|
59
|
+
babelPlugins: [
|
|
60
|
+
[babelPluginRewriteImportMetaCssAssignment, { relativeUrl }],
|
|
61
|
+
],
|
|
62
|
+
input: urlInfo.content,
|
|
63
|
+
inputIsJsModule: true,
|
|
64
|
+
inputUrl: urlInfo.originalUrl,
|
|
65
|
+
outputUrl: urlInfo.generatedUrl,
|
|
66
|
+
});
|
|
67
|
+
return injectImportMetaCss(urlInfo, {
|
|
68
|
+
content: code,
|
|
69
|
+
importFrom: importMetaCssBuildClientFileUrl,
|
|
70
|
+
importName: "installImportMetaCssBuild",
|
|
71
|
+
importAs: "__installImportMetaCssBuild__",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
57
74
|
return injectImportMetaCss(urlInfo, {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
: "installImportMetaCssDev",
|
|
64
|
-
importAs: urlInfo.context.build
|
|
65
|
-
? "__installImportMetaCssBuild__"
|
|
66
|
-
: "__installImportMetaCssDev__",
|
|
75
|
+
content: urlInfo.content,
|
|
76
|
+
importFrom: importMetaCssDevClientFileUrl,
|
|
77
|
+
importName: "installImportMetaCssDev",
|
|
78
|
+
importAs: "__installImportMetaCssDev__",
|
|
79
|
+
hot: true,
|
|
67
80
|
});
|
|
68
81
|
},
|
|
69
82
|
},
|
|
70
83
|
};
|
|
71
84
|
};
|
|
72
85
|
|
|
86
|
+
const babelPluginRewriteImportMetaCssAssignment = (
|
|
87
|
+
{ types: t },
|
|
88
|
+
{ relativeUrl },
|
|
89
|
+
) => {
|
|
90
|
+
return {
|
|
91
|
+
name: "rewrite-import-meta-css-assignment",
|
|
92
|
+
visitor: {
|
|
93
|
+
AssignmentExpression(path) {
|
|
94
|
+
const { left, right } = path.node;
|
|
95
|
+
if (left.type !== "MemberExpression") {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const { object, property } = left;
|
|
99
|
+
if (object.type !== "MetaProperty") {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (object.meta.name !== "import" || object.property.name !== "meta") {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (property.name !== "css") {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
path.node.right = t.arrayExpression([
|
|
109
|
+
right,
|
|
110
|
+
t.stringLiteral(relativeUrl),
|
|
111
|
+
]);
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
|
|
73
117
|
const babelPluginMetadataUsesImportMetaCss = () => {
|
|
74
118
|
return {
|
|
75
119
|
name: "metadata-uses-import-meta-css",
|
|
@@ -101,7 +145,10 @@ const babelPluginMetadataUsesImportMetaCss = () => {
|
|
|
101
145
|
};
|
|
102
146
|
};
|
|
103
147
|
|
|
104
|
-
const injectImportMetaCss = (
|
|
148
|
+
const injectImportMetaCss = (
|
|
149
|
+
urlInfo,
|
|
150
|
+
{ content, importFrom, importName, importAs, hot },
|
|
151
|
+
) => {
|
|
105
152
|
const importMetaCssClientFileReference = urlInfo.dependencies.inject({
|
|
106
153
|
parentUrl: urlInfo.url,
|
|
107
154
|
type: "js_import",
|
|
@@ -117,7 +164,9 @@ const injectImportMetaCss = (urlInfo, { importFrom, importName, importAs }) => {
|
|
|
117
164
|
importBeforeFrom = `{ ${importName} } }`;
|
|
118
165
|
importVariableName = importName;
|
|
119
166
|
}
|
|
120
|
-
|
|
167
|
+
|
|
168
|
+
const prelude = hot
|
|
169
|
+
? `import ${importBeforeFrom} from ${importMetaCssClientFileReference.generatedSpecifier};
|
|
121
170
|
|
|
122
171
|
const remove = ${importVariableName}(import.meta);
|
|
123
172
|
if (import.meta.hot) {
|
|
@@ -126,9 +175,13 @@ if (import.meta.hot) {
|
|
|
126
175
|
});
|
|
127
176
|
}
|
|
128
177
|
|
|
178
|
+
`
|
|
179
|
+
: `import ${importBeforeFrom} from ${importMetaCssClientFileReference.generatedSpecifier};
|
|
180
|
+
|
|
181
|
+
${importVariableName}(import.meta);
|
|
182
|
+
|
|
129
183
|
`;
|
|
130
184
|
|
|
131
|
-
let content = urlInfo.content;
|
|
132
185
|
return {
|
|
133
186
|
content: `${prelude.replace(/\n/g, "")}${content}`,
|
|
134
187
|
};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { createPluginsController } from "@jsenv/server/src/plugins_controller.js";
|
|
2
|
+
|
|
3
|
+
import { jsenvPluginHtmlSyntaxErrorFallback } from "./html_syntax_error_fallback/jsenv_plugin_html_syntax_error_fallback.js";
|
|
4
|
+
|
|
5
|
+
export const createJsenvPluginStore = async (plugins) => {
|
|
6
|
+
const allServerRoutes = [];
|
|
7
|
+
const allServerPlugins = [];
|
|
8
|
+
const pluginArray = [];
|
|
9
|
+
|
|
10
|
+
const pluginPromises = [];
|
|
11
|
+
const addPlugin = async (plugin) => {
|
|
12
|
+
if (plugin && typeof plugin.then === "function") {
|
|
13
|
+
pluginPromises.push(plugin);
|
|
14
|
+
const value = await plugin;
|
|
15
|
+
addPlugin(value);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (Array.isArray(plugin)) {
|
|
19
|
+
for (const subplugin of plugin) {
|
|
20
|
+
addPlugin(subplugin);
|
|
21
|
+
}
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (plugin === null || typeof plugin !== "object") {
|
|
25
|
+
throw new TypeError(`plugin must be objects, got ${plugin}`);
|
|
26
|
+
}
|
|
27
|
+
if (!plugin.name) {
|
|
28
|
+
plugin.name = "anonymous";
|
|
29
|
+
}
|
|
30
|
+
const { serverRoutes } = plugin;
|
|
31
|
+
if (serverRoutes) {
|
|
32
|
+
for (const serverRoute of serverRoutes) {
|
|
33
|
+
allServerRoutes.push(serverRoute);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const { serverPlugins } = plugin;
|
|
37
|
+
if (serverPlugins) {
|
|
38
|
+
const serverPlugins = plugin.serverPlugins;
|
|
39
|
+
for (const serverPlugin of serverPlugins) {
|
|
40
|
+
allServerPlugins.push(serverPlugin);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
pluginArray.push(plugin);
|
|
44
|
+
};
|
|
45
|
+
addPlugin(jsenvPluginHtmlSyntaxErrorFallback());
|
|
46
|
+
for (const plugin of plugins) {
|
|
47
|
+
addPlugin(plugin);
|
|
48
|
+
}
|
|
49
|
+
await Promise.all(pluginPromises);
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
pluginArray,
|
|
53
|
+
allServerRoutes,
|
|
54
|
+
allServerPlugins,
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const createJsenvPluginsController = async (
|
|
59
|
+
pluginStore,
|
|
60
|
+
kitchen,
|
|
61
|
+
{ meta } = {},
|
|
62
|
+
) => {
|
|
63
|
+
kitchen.context.getPluginMeta = (id) => pluginsController.getPluginMeta(id);
|
|
64
|
+
const pluginsController = await createPluginsController({
|
|
65
|
+
plugins: pluginStore.pluginArray,
|
|
66
|
+
pluginDescription: JSENV_PLUGIN_DESCRIPTION,
|
|
67
|
+
filterPlugin: (plugin) => testAppliesDuring(plugin, kitchen),
|
|
68
|
+
getInitPluginArgs: (plugin) => [kitchen.context, { plugin }],
|
|
69
|
+
getEffectArgs: ({ otherPlugins }) => [
|
|
70
|
+
{ kitchenContext: kitchen.context, otherPlugins },
|
|
71
|
+
],
|
|
72
|
+
meta,
|
|
73
|
+
});
|
|
74
|
+
return pluginsController;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const hook = { type: "hook" };
|
|
78
|
+
const nonHook = {};
|
|
79
|
+
|
|
80
|
+
const assertUrlReturnValue = (valueReturned, urlInfo, { hook }) => {
|
|
81
|
+
if (valueReturned instanceof URL) {
|
|
82
|
+
return valueReturned.href;
|
|
83
|
+
}
|
|
84
|
+
if (typeof valueReturned === "string") {
|
|
85
|
+
return valueReturned;
|
|
86
|
+
}
|
|
87
|
+
throw new Error(
|
|
88
|
+
`Unexpected value returned by hook "${hook.plugin.name}.${hook.name}()": it must be a string; got ${valueReturned}`,
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
const assertContentReturnValue = (valueReturned, urlInfo, { hook }) => {
|
|
92
|
+
if (typeof valueReturned === "string" || Buffer.isBuffer(valueReturned)) {
|
|
93
|
+
return { content: valueReturned };
|
|
94
|
+
}
|
|
95
|
+
if (typeof valueReturned === "object") {
|
|
96
|
+
const { content, body } = valueReturned;
|
|
97
|
+
if (urlInfo.url.startsWith("ignore:")) {
|
|
98
|
+
return valueReturned;
|
|
99
|
+
}
|
|
100
|
+
if (typeof content !== "string" && !Buffer.isBuffer(content) && !body) {
|
|
101
|
+
if (Object.hasOwn(valueReturned, "contentInjections")) {
|
|
102
|
+
return valueReturned;
|
|
103
|
+
}
|
|
104
|
+
throw new Error(
|
|
105
|
+
`Unexpected "content" returned by hook "${hook.plugin.name}.${hook.name}()": it must be a string or a buffer; got ${content}`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
return valueReturned;
|
|
109
|
+
}
|
|
110
|
+
throw new Error(
|
|
111
|
+
`Unexpected value returned by hook "${hook.plugin.name}.${hook.name}()": it must be a string, a buffer or an object; got ${valueReturned}`,
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const JSENV_PLUGIN_DESCRIPTION = {
|
|
116
|
+
name: "jsenv plugin",
|
|
117
|
+
properties: {
|
|
118
|
+
// non-hook properties (silently skipped)
|
|
119
|
+
appliesDuring: nonHook,
|
|
120
|
+
serverEvents: nonHook,
|
|
121
|
+
mustStayFirst: nonHook,
|
|
122
|
+
serverRoutes: nonHook,
|
|
123
|
+
serverPlugins: nonHook,
|
|
124
|
+
// hooks
|
|
125
|
+
init: hook,
|
|
126
|
+
resolveReference: {
|
|
127
|
+
type: "hook",
|
|
128
|
+
assertAndNormalize: assertUrlReturnValue,
|
|
129
|
+
},
|
|
130
|
+
redirectReference: {
|
|
131
|
+
type: "hook",
|
|
132
|
+
assertAndNormalize: assertUrlReturnValue,
|
|
133
|
+
},
|
|
134
|
+
transformReferenceSearchParams: hook,
|
|
135
|
+
formatReference: hook,
|
|
136
|
+
urlInfoCreated: hook,
|
|
137
|
+
fetchUrlContent: {
|
|
138
|
+
type: "hook",
|
|
139
|
+
assertAndNormalize: assertContentReturnValue,
|
|
140
|
+
},
|
|
141
|
+
transformUrlContent: {
|
|
142
|
+
type: "hook",
|
|
143
|
+
assertAndNormalize: assertContentReturnValue,
|
|
144
|
+
},
|
|
145
|
+
finalizeUrlContent: {
|
|
146
|
+
type: "hook",
|
|
147
|
+
assertAndNormalize: assertContentReturnValue,
|
|
148
|
+
},
|
|
149
|
+
bundle: hook,
|
|
150
|
+
optimizeBuildUrlContent: {
|
|
151
|
+
type: "hook",
|
|
152
|
+
assertAndNormalize: assertContentReturnValue,
|
|
153
|
+
},
|
|
154
|
+
cooked: hook,
|
|
155
|
+
augmentResponse: hook,
|
|
156
|
+
destroy: hook,
|
|
157
|
+
effect: hook,
|
|
158
|
+
refineBuildUrlContent: hook,
|
|
159
|
+
refineBuild: hook,
|
|
160
|
+
// serverRoutes and serverPlugins are nonHook above
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const testAppliesDuring = (plugin, kitchen) => {
|
|
165
|
+
const { appliesDuring } = plugin;
|
|
166
|
+
if (appliesDuring === undefined) {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
if (appliesDuring === "*") {
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
if (typeof appliesDuring === "string") {
|
|
173
|
+
if (appliesDuring !== "dev" && appliesDuring !== "build") {
|
|
174
|
+
throw new TypeError(
|
|
175
|
+
`"appliesDuring" must be "dev" or "build", got ${appliesDuring}`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
if (kitchen.context[appliesDuring]) {
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
if (typeof appliesDuring === "object") {
|
|
184
|
+
for (const key of Object.keys(appliesDuring)) {
|
|
185
|
+
if (!appliesDuring[key] && kitchen.context[key]) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
if (appliesDuring[key] && kitchen.context[key]) {
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
throw new TypeError(
|
|
195
|
+
`"appliesDuring" must be an object or a string, got ${appliesDuring}`,
|
|
196
|
+
);
|
|
197
|
+
};
|
|
@@ -90,7 +90,7 @@ export const jsenvPluginServerEvents = ({ clientAutoreload }) => {
|
|
|
90
90
|
return stringifyHtmlAst(htmlAst);
|
|
91
91
|
},
|
|
92
92
|
},
|
|
93
|
-
|
|
93
|
+
serverRoutes: [
|
|
94
94
|
{
|
|
95
95
|
endpoint: "GET /.internal/events.websocket",
|
|
96
96
|
description: `Jsenv dev server emit server events on this endpoint. When a file is saved the "reload" event is sent here.`,
|