@jsenv/core 27.0.0-alpha.6 → 27.0.0-alpha.60
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/event_source_client.js +545 -0
- package/dist/event_source_client.js.map +187 -0
- package/dist/html_supervisor_installer.js +1236 -0
- package/dist/html_supervisor_installer.js.map +337 -0
- package/dist/html_supervisor_setup.js +95 -0
- package/dist/html_supervisor_setup.js.map +57 -0
- package/dist/import_meta_hot.js +86 -0
- package/dist/import_meta_hot.js.map +42 -0
- package/main.js +8 -1
- package/package.json +30 -28
- package/readme.md +6 -14
- package/src/build/build.js +943 -555
- package/src/build/build_urls_generator.js +48 -23
- package/src/build/graph_utils.js +31 -0
- package/src/build/{inject_version_mappings.js → inject_global_version_mappings.js} +33 -15
- package/src/build/inject_service_worker_urls.js +79 -0
- package/src/build/resync_ressource_hints.js +68 -0
- package/src/build/start_build_server.js +192 -0
- package/src/dev/plugins/explorer/jsenv_plugin_explorer.js +2 -2
- package/src/dev/plugins/toolbar/jsenv_plugin_toolbar.js +3 -1
- package/src/dev/start_dev_server.js +136 -30
- package/src/execute/execute.js +31 -6
- package/src/execute/run.js +19 -56
- package/src/execute/runtimes/browsers/from_playwright.js +207 -147
- package/src/execute/runtimes/node/controllable_file.mjs +26 -10
- package/src/execute/runtimes/node/node_execution_performance.js +67 -0
- package/src/execute/runtimes/node/node_process.js +280 -39
- package/src/jsenv_root_directory_url.js +1 -0
- package/src/omega/{runtime_support/default_runtime_support.js → compat/default_runtime_compat.js} +3 -5
- package/src/omega/{runtime_support/features_compatibility.js → compat/features_compats.js} +66 -4
- package/src/omega/compat/runtime_compat.js +50 -0
- package/src/omega/errors.js +51 -58
- package/src/omega/fetched_content_compliance.js +24 -0
- package/src/omega/file_url_converter.js +8 -50
- package/src/omega/kitchen.js +482 -304
- package/src/omega/omega_server.js +2 -3
- package/src/omega/server/file_service.js +53 -25
- package/src/omega/server/user_agent.js +4 -2
- package/src/omega/url_graph/url_graph_load.js +22 -7
- package/src/omega/url_graph/url_graph_report.js +98 -48
- package/src/omega/url_graph/url_info_transformations.js +26 -9
- package/src/omega/url_graph.js +80 -16
- package/src/omega/web_workers.js +42 -0
- package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/autoreload_preference.js +0 -0
- package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/event_source_client.js +2 -2
- package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/reload.js +0 -0
- package/src/{dev/plugins/autoreload → plugins/autoreload/dev_sse}/client/url_helpers.js +0 -0
- package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_client.js +46 -0
- package/src/plugins/autoreload/dev_sse/jsenv_plugin_dev_sse_server.js +204 -0
- package/src/plugins/autoreload/jsenv_plugin_autoreload.js +27 -0
- package/src/plugins/autoreload/jsenv_plugin_hmr.js +35 -0
- package/src/plugins/bundling/css/bundle_css.js +140 -0
- package/src/plugins/bundling/js_classic_workers/bundle_js_classic_workers.js +13 -0
- package/src/plugins/bundling/js_module/bundle_js_module.js +309 -0
- package/src/plugins/bundling/jsenv_plugin_bundling.js +54 -0
- package/src/plugins/cache_control/jsenv_plugin_cache_control.js +34 -0
- package/src/{omega/core_plugins → plugins}/commonjs_globals/jsenv_plugin_commonjs_globals.js +54 -41
- package/src/plugins/file_urls/jsenv_plugin_file_urls.js +66 -0
- package/src/{omega/core_plugins → plugins}/filesystem_magic/jsenv_plugin_filesystem_magic.js +8 -5
- package/src/{omega/core_plugins → plugins}/html_supervisor/client/error_in_document.js +0 -0
- package/src/{omega/core_plugins → plugins}/html_supervisor/client/error_in_notification.js +0 -0
- package/src/plugins/html_supervisor/client/html_supervisor_installer.js +242 -0
- package/src/plugins/html_supervisor/client/html_supervisor_setup.js +79 -0
- package/src/{omega/core_plugins → plugins}/html_supervisor/client/perf_browser.js +0 -0
- package/src/{omega/core_plugins → plugins}/html_supervisor/client/uneval_exception.js +0 -0
- package/src/{omega/core_plugins → plugins}/html_supervisor/jsenv_plugin_html_supervisor.js +83 -61
- package/src/plugins/http_urls/jsenv_plugin_http_urls.js +12 -0
- package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/babel_plugin_metadata_import_meta_hot.js +4 -5
- package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/client/import_meta_hot.js +3 -1
- package/src/{dev/plugins/autoreload → plugins/import_meta_hot}/html_hot_dependencies.js +2 -2
- package/src/plugins/import_meta_hot/jsenv_plugin_import_meta_hot.js +105 -0
- package/src/{omega/core_plugins → plugins}/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +33 -8
- package/src/plugins/import_meta_url/client/import_meta_url_browser.js +52 -0
- package/src/plugins/import_meta_url/client/import_meta_url_commonjs.mjs +9 -0
- package/src/{omega/core_plugins → plugins}/importmap/jsenv_plugin_importmap.js +39 -33
- package/src/plugins/inject_globals/jsenv_plugin_inject_globals.js +67 -0
- package/src/{omega/core_plugins → plugins}/inline/client/inline_content.js +0 -0
- package/src/{omega/core_plugins → plugins}/inline/jsenv_plugin_data_urls.js +18 -14
- package/src/{omega/core_plugins/inline/jsenv_plugin_js_and_css_inside_html.js → plugins/inline/jsenv_plugin_html_inline_content.js} +65 -44
- package/src/plugins/inline/jsenv_plugin_inline.js +36 -0
- package/src/{omega/core_plugins → plugins}/inline/jsenv_plugin_inline_query_param.js +6 -6
- package/src/plugins/inline/jsenv_plugin_js_inline_content.js +297 -0
- package/src/plugins/leading_slash/jsenv_plugin_leading_slash.js +13 -0
- package/src/plugins/minification/css/minify_css.js +9 -0
- package/src/plugins/minification/html/minify_html.js +15 -0
- package/src/{build/plugins/minify_js/jsenv_plugin_minify_js.js → plugins/minification/js/minify_js.js} +6 -22
- package/src/plugins/minification/jsenv_plugin_minification.js +78 -0
- package/src/plugins/minification/json/minify_json.js +8 -0
- package/src/plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +146 -0
- package/src/{omega → plugins}/plugin_controller.js +42 -11
- package/src/plugins/plugins.js +92 -0
- package/src/plugins/transpilation/as_js_classic/client/s.js +874 -0
- package/src/plugins/transpilation/as_js_classic/client/s.js.md +1 -0
- package/src/plugins/transpilation/as_js_classic/helpers/babel_plugin_transform_import_meta_url.js +47 -0
- package/src/plugins/transpilation/as_js_classic/helpers/systemjs_old.js +43 -0
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +199 -0
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_script_type_module_as_classic.js +270 -0
- package/src/plugins/transpilation/as_js_classic/jsenv_plugin_workers_type_module_as_classic.js +55 -0
- package/src/{omega/core_plugins → plugins/transpilation}/babel/global_this/babel_plugin_global_this_as_jsenv_import.js +0 -0
- package/src/{omega/core_plugins → plugins/transpilation}/babel/global_this/client/global_this.js +0 -0
- package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugin_babel_helpers_as_jsenv_imports.js +0 -0
- package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugin_structure.js +12 -19
- package/src/{omega/core_plugins → plugins/transpilation}/babel/helpers/babel_plugins_compatibility.js +0 -0
- package/src/{omega/core_plugins → plugins/transpilation}/babel/jsenv_plugin_babel.js +45 -27
- package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/babel_plugin_new_stylesheet_as_jsenv_import.js +30 -6
- package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/client/.eslintrc.cjs +0 -0
- package/src/{omega/core_plugins → plugins/transpilation}/babel/new_stylesheet/client/new_stylesheet.js +0 -0
- package/src/{omega/core_plugins → plugins/transpilation}/babel/regenerator_runtime/babel_plugin_regenerator_runtime_as_jsenv_import.js +0 -0
- package/src/{omega/core_plugins → plugins/transpilation}/babel/regenerator_runtime/client/regenerator_runtime.js +0 -0
- package/src/plugins/transpilation/css_parcel/jsenv_plugin_css_parcel.js +18 -0
- package/src/plugins/transpilation/fetch_original_url_info.js +30 -0
- package/src/plugins/transpilation/import_assertions/jsenv_plugin_import_assertions.js +181 -0
- package/src/plugins/transpilation/jsenv_plugin_top_level_await.js +80 -0
- package/src/plugins/transpilation/jsenv_plugin_transpilation.js +44 -0
- package/src/plugins/url_analysis/css/css_urls.js +49 -0
- package/src/plugins/url_analysis/html/html_urls.js +269 -0
- package/src/plugins/url_analysis/js/js_urls.js +67 -0
- package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +18 -0
- package/src/plugins/url_analysis/webmanifest/webmanifest_urls.js +17 -0
- package/src/{omega/core_plugins → plugins}/url_resolution/jsenv_plugin_url_resolution.js +12 -5
- package/src/plugins/url_version/jsenv_plugin_url_version.js +28 -0
- package/src/test/execute_plan.js +30 -18
- package/src/test/execute_test_plan.js +23 -8
- package/src/test/logs_file_execution.js +9 -8
- package/src/build/plugins/bundle_js_module/jsenv_plugin_bundle_js_module.js +0 -225
- package/src/build/plugins/minify_html/jsenv_plugin_minify_html.js +0 -30
- package/src/dev/plugins/autoreload/client/event_source_connection.js +0 -195
- package/src/dev/plugins/autoreload/jsenv_plugin_autoreload.js +0 -374
- package/src/dev/plugins/autoreload/sse_service.js +0 -149
- package/src/execute/runtimes/node/controlled_process.js +0 -316
- package/src/omega/core_plugins/file_urls/jsenv_plugin_file_urls.js +0 -67
- package/src/omega/core_plugins/html_supervisor/client/html_supervisor_installer.js +0 -168
- package/src/omega/core_plugins/html_supervisor/client/html_supervisor_setup.js +0 -77
- package/src/omega/core_plugins/import_assertions/helpers/babel_plugin_metadata_import_assertions.js +0 -98
- package/src/omega/core_plugins/import_assertions/helpers/json_module.js +0 -12
- package/src/omega/core_plugins/import_assertions/helpers/text_module.js +0 -6
- package/src/omega/core_plugins/import_assertions/jsenv_plugin_import_assertions.js +0 -211
- package/src/omega/core_plugins/inline/jsenv_plugin_inline.js +0 -13
- package/src/omega/core_plugins/inline/jsenv_plugin_new_inline_content.js +0 -210
- package/src/omega/core_plugins/leading_slash/jsenv_plugin_leading_slash.js +0 -12
- package/src/omega/core_plugins/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +0 -77
- package/src/omega/core_plugins/url_version/jsenv_plugin_url_version.js +0 -50
- package/src/omega/core_plugins.js +0 -39
- package/src/omega/runtime_support/runtime_support.js +0 -20
- package/src/omega/url_graph/url_graph_sort.js +0 -29
- package/src/omega/url_mentions/css_url_mentions.js +0 -63
- package/src/omega/url_mentions/html_url_mentions.js +0 -185
- package/src/omega/url_mentions/js_module_url_mentions.js +0 -91
- package/src/omega/url_mentions/parse_url_mentions.js +0 -37
- package/src/omega/url_mentions/worker_classic_url_mentions.js +0 -37
|
@@ -5,19 +5,19 @@ import {
|
|
|
5
5
|
getHtmlNodeTextNode,
|
|
6
6
|
htmlNodePosition,
|
|
7
7
|
parseScriptNode,
|
|
8
|
-
|
|
8
|
+
setHtmlNodeGeneratedText,
|
|
9
9
|
getHtmlNodeAttributeByName,
|
|
10
10
|
} from "@jsenv/utils/html_ast/html_ast.js"
|
|
11
|
-
import { injectQueryParams } from "@jsenv/utils/urls/url_utils.js"
|
|
12
11
|
import { generateInlineContentUrl } from "@jsenv/utils/urls/inline_content_url_generator.js"
|
|
12
|
+
import { CONTENT_TYPE } from "@jsenv/utils/content_type/content_type.js"
|
|
13
13
|
|
|
14
|
-
export const
|
|
14
|
+
export const jsenvPluginHtmlInlineContent = ({ analyzeConvertedScripts }) => {
|
|
15
15
|
return {
|
|
16
|
-
name: "jsenv:
|
|
16
|
+
name: "jsenv:html_inline_content",
|
|
17
17
|
appliesDuring: "*",
|
|
18
|
-
|
|
19
|
-
html: async (
|
|
20
|
-
const htmlAst = parseHtmlString(content)
|
|
18
|
+
transformUrlContent: {
|
|
19
|
+
html: async (urlInfo, context) => {
|
|
20
|
+
const htmlAst = parseHtmlString(urlInfo.content)
|
|
21
21
|
const actions = []
|
|
22
22
|
const handleInlineStyle = (node) => {
|
|
23
23
|
if (node.nodeName !== "style") {
|
|
@@ -33,7 +33,7 @@ export const jsenvPluginJsAndCssInsideHtml = () => {
|
|
|
33
33
|
preferOriginal: true,
|
|
34
34
|
})
|
|
35
35
|
const inlineStyleUrl = generateInlineContentUrl({
|
|
36
|
-
url,
|
|
36
|
+
url: urlInfo.url,
|
|
37
37
|
extension: ".css",
|
|
38
38
|
line,
|
|
39
39
|
column,
|
|
@@ -41,23 +41,27 @@ export const jsenvPluginJsAndCssInsideHtml = () => {
|
|
|
41
41
|
columnEnd,
|
|
42
42
|
})
|
|
43
43
|
const [inlineStyleReference, inlineStyleUrlInfo] =
|
|
44
|
-
referenceUtils.foundInline({
|
|
44
|
+
context.referenceUtils.foundInline({
|
|
45
45
|
type: "link_href",
|
|
46
|
+
expectedType: "css",
|
|
47
|
+
isOriginalPosition: isOriginal,
|
|
46
48
|
// we remove 1 to the line because imagine the following html:
|
|
47
49
|
// <style>body { color: red; }</style>
|
|
48
50
|
// -> content starts same line as <style>
|
|
49
|
-
|
|
50
|
-
column,
|
|
51
|
-
isOriginal,
|
|
51
|
+
specifierLine: line - 1,
|
|
52
|
+
specifierColumn: column,
|
|
52
53
|
specifier: inlineStyleUrl,
|
|
53
54
|
contentType: "text/css",
|
|
54
55
|
content: textNode.value,
|
|
55
56
|
})
|
|
56
|
-
await cook({
|
|
57
|
+
await context.cook({
|
|
57
58
|
reference: inlineStyleReference,
|
|
58
59
|
urlInfo: inlineStyleUrlInfo,
|
|
59
60
|
})
|
|
60
|
-
|
|
61
|
+
setHtmlNodeGeneratedText(node, {
|
|
62
|
+
generatedText: inlineStyleUrlInfo.content,
|
|
63
|
+
generatedBy: "jsenv:html_inline_content",
|
|
64
|
+
})
|
|
61
65
|
})
|
|
62
66
|
}
|
|
63
67
|
const handleInlineScript = (node) => {
|
|
@@ -68,14 +72,19 @@ export const jsenvPluginJsAndCssInsideHtml = () => {
|
|
|
68
72
|
if (!textNode) {
|
|
69
73
|
return
|
|
70
74
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
// If the inline script was already handled by an other plugin, ignore it
|
|
76
|
+
// - we want to preserve inline scripts generated by html supervisor during dev
|
|
77
|
+
// - we want to avoid cooking twice a script during build
|
|
78
|
+
const generatedBy = getHtmlNodeAttributeByName(node, "generated-by")
|
|
79
|
+
if (generatedBy) {
|
|
80
|
+
if (generatedBy.value === "jsenv:script_type_module_as_classic") {
|
|
81
|
+
if (!analyzeConvertedScripts) {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (generatedBy.value === "jsenv:html_supervisor") {
|
|
86
|
+
return
|
|
87
|
+
}
|
|
79
88
|
}
|
|
80
89
|
actions.push(async () => {
|
|
81
90
|
const scriptCategory = parseScriptNode(node)
|
|
@@ -83,41 +92,57 @@ export const jsenvPluginJsAndCssInsideHtml = () => {
|
|
|
83
92
|
htmlNodePosition.readNodePosition(node, {
|
|
84
93
|
preferOriginal: true,
|
|
85
94
|
})
|
|
95
|
+
// from MDN about [type] attribute:
|
|
96
|
+
// "Any other value: The embedded content is treated as a data block
|
|
97
|
+
// which won't be processed by the browser. Developers must use a valid MIME type
|
|
98
|
+
// that is not a JavaScript MIME type to denote data blocks.
|
|
99
|
+
// The src attribute will be ignored."
|
|
100
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type
|
|
101
|
+
const isJs =
|
|
102
|
+
scriptCategory === "classic" || scriptCategory === "module"
|
|
103
|
+
const isImportmap = scriptCategory === "importmap"
|
|
104
|
+
const contentType = isJs
|
|
105
|
+
? "text/javascript"
|
|
106
|
+
: isImportmap
|
|
107
|
+
? "application/importmap+json"
|
|
108
|
+
: scriptCategory
|
|
109
|
+
|
|
86
110
|
let inlineScriptUrl = generateInlineContentUrl({
|
|
87
|
-
url,
|
|
88
|
-
extension:
|
|
111
|
+
url: urlInfo.url,
|
|
112
|
+
extension: CONTENT_TYPE.asFileExtension(contentType),
|
|
89
113
|
line,
|
|
90
114
|
column,
|
|
91
115
|
lineEnd,
|
|
92
116
|
columnEnd,
|
|
93
117
|
})
|
|
94
|
-
if (scriptCategory === "classic") {
|
|
95
|
-
inlineScriptUrl = injectQueryParams(inlineScriptUrl, {
|
|
96
|
-
js_classic: "",
|
|
97
|
-
})
|
|
98
|
-
}
|
|
99
118
|
const [inlineScriptReference, inlineScriptUrlInfo] =
|
|
100
|
-
referenceUtils.foundInline({
|
|
119
|
+
context.referenceUtils.foundInline({
|
|
101
120
|
node,
|
|
102
121
|
type: "script_src",
|
|
122
|
+
expectedType: {
|
|
123
|
+
classic: "js_classic",
|
|
124
|
+
module: "js_module",
|
|
125
|
+
importmap: "importmap",
|
|
126
|
+
}[scriptCategory],
|
|
103
127
|
// we remove 1 to the line because imagine the following html:
|
|
104
128
|
// <script>console.log('ok')</script>
|
|
105
129
|
// -> content starts same line as <script>
|
|
106
|
-
|
|
107
|
-
column,
|
|
108
|
-
isOriginal,
|
|
130
|
+
specifierLine: line - 1,
|
|
131
|
+
specifierColumn: column,
|
|
132
|
+
isOriginalPosition: isOriginal,
|
|
109
133
|
specifier: inlineScriptUrl,
|
|
110
|
-
contentType
|
|
111
|
-
scriptCategory === "importmap"
|
|
112
|
-
? "application/importmap+json"
|
|
113
|
-
: "application/javascript",
|
|
134
|
+
contentType,
|
|
114
135
|
content: textNode.value,
|
|
115
136
|
})
|
|
116
|
-
|
|
137
|
+
|
|
138
|
+
await context.cook({
|
|
117
139
|
reference: inlineScriptReference,
|
|
118
140
|
urlInfo: inlineScriptUrlInfo,
|
|
119
141
|
})
|
|
120
|
-
|
|
142
|
+
setHtmlNodeGeneratedText(node, {
|
|
143
|
+
generatedText: inlineScriptUrlInfo.content,
|
|
144
|
+
generatedBy: "jsenv:html_inline_content",
|
|
145
|
+
})
|
|
121
146
|
})
|
|
122
147
|
}
|
|
123
148
|
visitHtmlAst(htmlAst, (node) => {
|
|
@@ -127,11 +152,7 @@ export const jsenvPluginJsAndCssInsideHtml = () => {
|
|
|
127
152
|
if (actions.length === 0) {
|
|
128
153
|
return null
|
|
129
154
|
}
|
|
130
|
-
await Promise.all(
|
|
131
|
-
actions.map(async (action) => {
|
|
132
|
-
await action()
|
|
133
|
-
}),
|
|
134
|
-
)
|
|
155
|
+
await Promise.all(actions.map((action) => action()))
|
|
135
156
|
const htmlModified = stringifyHtmlAst(htmlAst)
|
|
136
157
|
return {
|
|
137
158
|
content: htmlModified,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsenvPluginHtmlInlineContent } from "./jsenv_plugin_html_inline_content.js"
|
|
2
|
+
import { jsenvPluginJsInlineContent } from "./jsenv_plugin_js_inline_content.js"
|
|
3
|
+
import { jsenvPluginDataUrls } from "./jsenv_plugin_data_urls.js"
|
|
4
|
+
import { jsenvPluginInlineQueryParam } from "./jsenv_plugin_inline_query_param.js"
|
|
5
|
+
|
|
6
|
+
export const jsenvPluginInline = ({
|
|
7
|
+
fetchInlineUrls = true,
|
|
8
|
+
analyzeConvertedScripts = false,
|
|
9
|
+
allowEscapeForVersioning = false,
|
|
10
|
+
} = {}) => {
|
|
11
|
+
return [
|
|
12
|
+
...(fetchInlineUrls ? [jsenvPluginInlineUrls()] : []),
|
|
13
|
+
jsenvPluginHtmlInlineContent({ analyzeConvertedScripts }),
|
|
14
|
+
jsenvPluginJsInlineContent({ allowEscapeForVersioning }),
|
|
15
|
+
jsenvPluginDataUrls(),
|
|
16
|
+
jsenvPluginInlineQueryParam(),
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const jsenvPluginInlineUrls = () => {
|
|
21
|
+
return {
|
|
22
|
+
name: "jsenv:inline_urls",
|
|
23
|
+
appliesDuring: "*",
|
|
24
|
+
fetchUrlContent: (urlInfo) => {
|
|
25
|
+
if (!urlInfo.isInline) {
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
contentType: urlInfo.contentType,
|
|
30
|
+
// we want to fetch the original content otherwise we might re-cook
|
|
31
|
+
// content already cooked
|
|
32
|
+
content: urlInfo.originalContent,
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -4,7 +4,7 @@ export const jsenvPluginInlineQueryParam = () => {
|
|
|
4
4
|
return {
|
|
5
5
|
name: "jsenv:inline_query_param",
|
|
6
6
|
appliesDuring: "*",
|
|
7
|
-
|
|
7
|
+
formatUrl: {
|
|
8
8
|
// <link> and <script> can be inlined in the html
|
|
9
9
|
// this should be done during dev and postbuild but not build
|
|
10
10
|
// so that the bundled file gets inlined and not the entry point
|
|
@@ -15,17 +15,17 @@ export const jsenvPluginInlineQueryParam = () => {
|
|
|
15
15
|
// but maybe we should rather use ?object_url
|
|
16
16
|
// or people could do this:
|
|
17
17
|
// import workerText from './worker.js?text'
|
|
18
|
-
// const blob = new Blob(workerText, { type: '
|
|
18
|
+
// const blob = new Blob(workerText, { type: 'text/javascript' })
|
|
19
19
|
// window.URL.createObjectURL(blob)
|
|
20
20
|
// in any case the recommended way is to use an url
|
|
21
21
|
// to benefit from shared worker and reuse worker between tabs
|
|
22
|
-
"*": (reference,
|
|
23
|
-
if (!
|
|
22
|
+
"*": (reference, context) => {
|
|
23
|
+
if (!reference.searchParams.has("inline")) {
|
|
24
24
|
return null
|
|
25
25
|
}
|
|
26
26
|
return (async () => {
|
|
27
|
-
const urlInfo = urlGraph.getUrlInfo(reference.url)
|
|
28
|
-
await cook({
|
|
27
|
+
const urlInfo = context.urlGraph.getUrlInfo(reference.url)
|
|
28
|
+
await context.cook({
|
|
29
29
|
reference,
|
|
30
30
|
urlInfo,
|
|
31
31
|
})
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { CONTENT_TYPE } from "@jsenv/utils/content_type/content_type.js"
|
|
2
|
+
import { createMagicSource } from "@jsenv/utils/sourcemap/magic_source.js"
|
|
3
|
+
import { JS_QUOTES } from "@jsenv/utils/string/js_quotes.js"
|
|
4
|
+
import { applyBabelPlugins } from "@jsenv/utils/js_ast/apply_babel_plugins.js"
|
|
5
|
+
import { generateInlineContentUrl } from "@jsenv/utils/urls/inline_content_url_generator.js"
|
|
6
|
+
|
|
7
|
+
export const jsenvPluginJsInlineContent = ({ allowEscapeForVersioning }) => {
|
|
8
|
+
const parseAndTransformInlineContentCalls = async (urlInfo, context) => {
|
|
9
|
+
const inlineContentInfos = await parseJsInlineContentInfos({
|
|
10
|
+
js: urlInfo.content,
|
|
11
|
+
url: (urlInfo.data && urlInfo.data.rawUrl) || urlInfo.url,
|
|
12
|
+
isJsModule: urlInfo.type === "js_module",
|
|
13
|
+
})
|
|
14
|
+
if (inlineContentInfos.length === 0) {
|
|
15
|
+
return null
|
|
16
|
+
}
|
|
17
|
+
const magicSource = createMagicSource(urlInfo.content)
|
|
18
|
+
await inlineContentInfos.reduce(async (previous, inlineContentInfo) => {
|
|
19
|
+
await previous
|
|
20
|
+
const inlineUrl = generateInlineContentUrl({
|
|
21
|
+
url: urlInfo.url,
|
|
22
|
+
extension: CONTENT_TYPE.asFileExtension(inlineContentInfo.contentType),
|
|
23
|
+
line: inlineContentInfo.line,
|
|
24
|
+
column: inlineContentInfo.column,
|
|
25
|
+
lineEnd: inlineContentInfo.lineEnd,
|
|
26
|
+
columnEnd: inlineContentInfo.columnEnd,
|
|
27
|
+
})
|
|
28
|
+
let { quote } = inlineContentInfo
|
|
29
|
+
if (
|
|
30
|
+
quote === "`" &&
|
|
31
|
+
!context.isSupportedOnCurrentClients("template_literals")
|
|
32
|
+
) {
|
|
33
|
+
// if quote is "`" and template literals are not supported
|
|
34
|
+
// we'll use a regular string (single or double quote)
|
|
35
|
+
// when rendering the string
|
|
36
|
+
quote = JS_QUOTES.pickBest(inlineContentInfo.content)
|
|
37
|
+
}
|
|
38
|
+
const [inlineReference, inlineUrlInfo] =
|
|
39
|
+
context.referenceUtils.foundInline({
|
|
40
|
+
type: "js_inline_content",
|
|
41
|
+
subtype: inlineContentInfo.type, // "new_blob_first_arg", "new_inline_content_first_arg", "json_parse_first_arg"
|
|
42
|
+
isOriginalPosition: urlInfo.content === urlInfo.originalContent,
|
|
43
|
+
specifierLine: inlineContentInfo.line,
|
|
44
|
+
specifierColumn: inlineContentInfo.column,
|
|
45
|
+
specifier: inlineUrl,
|
|
46
|
+
contentType: inlineContentInfo.contentType,
|
|
47
|
+
content: inlineContentInfo.content,
|
|
48
|
+
})
|
|
49
|
+
inlineUrlInfo.jsQuote = quote
|
|
50
|
+
inlineReference.escape = (value) =>
|
|
51
|
+
JS_QUOTES.escapeSpecialChars(value.slice(1, -1), { quote })
|
|
52
|
+
await context.cook({
|
|
53
|
+
reference: inlineReference,
|
|
54
|
+
urlInfo: inlineUrlInfo,
|
|
55
|
+
})
|
|
56
|
+
magicSource.replace({
|
|
57
|
+
start: inlineContentInfo.start,
|
|
58
|
+
end: inlineContentInfo.end,
|
|
59
|
+
replacement: JS_QUOTES.escapeSpecialChars(inlineUrlInfo.content, {
|
|
60
|
+
quote,
|
|
61
|
+
allowEscapeForVersioning,
|
|
62
|
+
}),
|
|
63
|
+
})
|
|
64
|
+
}, Promise.resolve())
|
|
65
|
+
return magicSource.toContentAndSourcemap()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
name: "jsenv:js_inline_content",
|
|
70
|
+
appliesDuring: "*",
|
|
71
|
+
transformUrlContent: {
|
|
72
|
+
js_classic: parseAndTransformInlineContentCalls,
|
|
73
|
+
js_module: parseAndTransformInlineContentCalls,
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const parseJsInlineContentInfos = async ({ js, url, isJsModule }) => {
|
|
79
|
+
if (
|
|
80
|
+
!js.includes("InlineContent") &&
|
|
81
|
+
!js.includes("new Blob(") &&
|
|
82
|
+
!js.includes("JSON.parse(")
|
|
83
|
+
) {
|
|
84
|
+
return []
|
|
85
|
+
}
|
|
86
|
+
const { metadata } = await applyBabelPlugins({
|
|
87
|
+
babelPlugins: [babelPluginMetadataInlineContents],
|
|
88
|
+
urlInfo: {
|
|
89
|
+
url,
|
|
90
|
+
type: isJsModule ? "js_module" : "js_classic",
|
|
91
|
+
content: js,
|
|
92
|
+
},
|
|
93
|
+
})
|
|
94
|
+
return metadata.inlineContentInfos
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const babelPluginMetadataInlineContents = () => {
|
|
98
|
+
return {
|
|
99
|
+
name: "metadata-inline-contents",
|
|
100
|
+
visitor: {
|
|
101
|
+
Program: (programPath, state) => {
|
|
102
|
+
const inlineContentInfos = []
|
|
103
|
+
const onInlineContentInfo = (inlineContentInfo) => {
|
|
104
|
+
inlineContentInfos.push(inlineContentInfo)
|
|
105
|
+
}
|
|
106
|
+
programPath.traverse({
|
|
107
|
+
NewExpression: (path) => {
|
|
108
|
+
if (isNewInlineContentCall(path)) {
|
|
109
|
+
analyzeNewInlineContentCall(path.node, {
|
|
110
|
+
onInlineContentInfo,
|
|
111
|
+
})
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
if (isNewBlobCall(path.node)) {
|
|
115
|
+
analyzeNewBlobCall(path.node, {
|
|
116
|
+
onInlineContentInfo,
|
|
117
|
+
})
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
CallExpression: (path) => {
|
|
122
|
+
const node = path.node
|
|
123
|
+
if (isJSONParseCall(node)) {
|
|
124
|
+
analyzeJsonParseCall(node, {
|
|
125
|
+
onInlineContentInfo,
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
})
|
|
130
|
+
state.file.metadata.inlineContentInfos = inlineContentInfos
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const isNewInlineContentCall = (path) => {
|
|
137
|
+
const node = path.node
|
|
138
|
+
if (node.callee.type === "Identifier") {
|
|
139
|
+
// terser rename import to use a shorter name
|
|
140
|
+
const name = getOriginalName(path, node.callee.name)
|
|
141
|
+
return name === "InlineContent"
|
|
142
|
+
}
|
|
143
|
+
if (node.callee.id && node.callee.id.type === "Identifier") {
|
|
144
|
+
const name = getOriginalName(path, node.callee.id.name)
|
|
145
|
+
return name === "InlineContent"
|
|
146
|
+
}
|
|
147
|
+
return false
|
|
148
|
+
}
|
|
149
|
+
const analyzeNewInlineContentCall = (node, { onInlineContentInfo }) => {
|
|
150
|
+
analyzeArguments({
|
|
151
|
+
node,
|
|
152
|
+
onInlineContentInfo,
|
|
153
|
+
nodeHoldingContent: node.arguments[0],
|
|
154
|
+
type: "new_inline_content_first_arg",
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const isNewBlobCall = (node) => {
|
|
159
|
+
return node.callee.type === "Identifier" && node.callee.name === "Blob"
|
|
160
|
+
}
|
|
161
|
+
const analyzeNewBlobCall = (node, { onInlineContentInfo }) => {
|
|
162
|
+
const firstArg = node.arguments[0]
|
|
163
|
+
if (firstArg.type !== "ArrayExpression") {
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
if (firstArg.elements.length !== 1) {
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
analyzeArguments({
|
|
170
|
+
node,
|
|
171
|
+
onInlineContentInfo,
|
|
172
|
+
nodeHoldingContent: firstArg.elements[0],
|
|
173
|
+
type: "new_blob_first_arg",
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const analyzeArguments = ({
|
|
178
|
+
node,
|
|
179
|
+
onInlineContentInfo,
|
|
180
|
+
nodeHoldingContent,
|
|
181
|
+
type,
|
|
182
|
+
}) => {
|
|
183
|
+
if (node.arguments.length !== 2) {
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
const [, secondArg] = node.arguments
|
|
187
|
+
const typePropertyNode = getTypePropertyNode(secondArg)
|
|
188
|
+
if (!typePropertyNode) {
|
|
189
|
+
return
|
|
190
|
+
}
|
|
191
|
+
const typePropertyValueNode = typePropertyNode.value
|
|
192
|
+
if (typePropertyValueNode.type !== "StringLiteral") {
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
const contentType = typePropertyValueNode.value
|
|
196
|
+
const contentDetails = extractContentDetails(nodeHoldingContent)
|
|
197
|
+
if (contentDetails) {
|
|
198
|
+
onInlineContentInfo({
|
|
199
|
+
node: nodeHoldingContent,
|
|
200
|
+
...getNodePosition(nodeHoldingContent),
|
|
201
|
+
type,
|
|
202
|
+
contentType,
|
|
203
|
+
...contentDetails,
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const extractContentDetails = (node) => {
|
|
208
|
+
if (node.type === "StringLiteral") {
|
|
209
|
+
return {
|
|
210
|
+
nodeType: "StringLiteral",
|
|
211
|
+
quote: node.extra.raw[0],
|
|
212
|
+
content: node.value,
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (node.type === "TemplateLiteral") {
|
|
216
|
+
const quasis = node.quasis
|
|
217
|
+
if (quasis.length !== 1) {
|
|
218
|
+
return null
|
|
219
|
+
}
|
|
220
|
+
const templateElementNode = quasis[0]
|
|
221
|
+
return {
|
|
222
|
+
nodeType: "TemplateLiteral",
|
|
223
|
+
quote: "`",
|
|
224
|
+
content: templateElementNode.value.cooked,
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return null
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const isJSONParseCall = (node) => {
|
|
231
|
+
const callee = node.callee
|
|
232
|
+
return (
|
|
233
|
+
callee.type === "MemberExpression" &&
|
|
234
|
+
callee.object.type === "Identifier" &&
|
|
235
|
+
callee.object.name === "JSON" &&
|
|
236
|
+
callee.property.type === "Identifier" &&
|
|
237
|
+
callee.property.name === "parse"
|
|
238
|
+
)
|
|
239
|
+
}
|
|
240
|
+
const analyzeJsonParseCall = (node, { onInlineContentInfo }) => {
|
|
241
|
+
const firstArgNode = node.arguments[0]
|
|
242
|
+
const contentDetails = extractContentDetails(firstArgNode)
|
|
243
|
+
if (contentDetails) {
|
|
244
|
+
onInlineContentInfo({
|
|
245
|
+
node: firstArgNode,
|
|
246
|
+
...getNodePosition(firstArgNode),
|
|
247
|
+
type: "json_parse_first_arg",
|
|
248
|
+
contentType: "application/json",
|
|
249
|
+
...contentDetails,
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const getNodePosition = (node) => {
|
|
255
|
+
return {
|
|
256
|
+
start: node.start,
|
|
257
|
+
end: node.end,
|
|
258
|
+
line: node.loc.start.line,
|
|
259
|
+
column: node.loc.start.column,
|
|
260
|
+
lineEnd: node.loc.end.line,
|
|
261
|
+
columnEnd: node.loc.end.column,
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const getOriginalName = (path, name) => {
|
|
265
|
+
const binding = path.scope.getBinding(name)
|
|
266
|
+
if (!binding) {
|
|
267
|
+
return name
|
|
268
|
+
}
|
|
269
|
+
if (binding.path.type === "ImportSpecifier") {
|
|
270
|
+
const importedName = binding.path.node.imported.name
|
|
271
|
+
if (name === importedName) {
|
|
272
|
+
return name
|
|
273
|
+
}
|
|
274
|
+
return getOriginalName(path, importedName)
|
|
275
|
+
}
|
|
276
|
+
if (binding.path.type === "VariableDeclarator") {
|
|
277
|
+
const { init } = binding.path.node
|
|
278
|
+
if (init && init.type === "Identifier") {
|
|
279
|
+
const previousName = init.name
|
|
280
|
+
return getOriginalName(path, previousName)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return name
|
|
284
|
+
}
|
|
285
|
+
const getTypePropertyNode = (node) => {
|
|
286
|
+
if (node.type !== "ObjectExpression") {
|
|
287
|
+
return null
|
|
288
|
+
}
|
|
289
|
+
const { properties } = node
|
|
290
|
+
return properties.find((property) => {
|
|
291
|
+
return (
|
|
292
|
+
property.type === "ObjectProperty" &&
|
|
293
|
+
property.key.type === "Identifier" &&
|
|
294
|
+
property.key.name === "type"
|
|
295
|
+
)
|
|
296
|
+
})
|
|
297
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const jsenvPluginLeadingSlash = () => {
|
|
2
|
+
return {
|
|
3
|
+
name: "jsenv:leading_slash",
|
|
4
|
+
appliesDuring: "*",
|
|
5
|
+
resolveUrl: (reference, context) => {
|
|
6
|
+
if (reference.specifier[0] !== "/") {
|
|
7
|
+
return null
|
|
8
|
+
}
|
|
9
|
+
return new URL(reference.specifier.slice(1), context.rootDirectoryUrl)
|
|
10
|
+
.href
|
|
11
|
+
},
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createRequire } from "node:module"
|
|
2
|
+
|
|
3
|
+
const require = createRequire(import.meta.url)
|
|
4
|
+
|
|
5
|
+
// https://github.com/kangax/html-minifier#options-quick-reference
|
|
6
|
+
export const minifyHtml = ({ htmlUrlInfo, options } = {}) => {
|
|
7
|
+
const { collapseWhitespace = true, removeComments = true } = options
|
|
8
|
+
|
|
9
|
+
const { minify } = require("html-minifier")
|
|
10
|
+
const htmlMinified = minify(htmlUrlInfo.content, {
|
|
11
|
+
collapseWhitespace,
|
|
12
|
+
removeComments,
|
|
13
|
+
})
|
|
14
|
+
return htmlMinified
|
|
15
|
+
}
|
|
@@ -1,28 +1,11 @@
|
|
|
1
1
|
// https://github.com/terser-js/terser#minify-options
|
|
2
2
|
|
|
3
|
-
export const
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
sourcemap: urlInfo.sourcemap,
|
|
9
|
-
isJsModule: urlInfo.type === "js_module",
|
|
10
|
-
})
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return {
|
|
14
|
-
name: "jsenv:minify_js",
|
|
15
|
-
appliesDuring: {
|
|
16
|
-
build: true,
|
|
17
|
-
},
|
|
18
|
-
optimize: {
|
|
19
|
-
js_classic: applyTerser,
|
|
20
|
-
js_module: applyTerser,
|
|
21
|
-
},
|
|
22
|
-
}
|
|
23
|
-
}
|
|
3
|
+
export const minifyJs = async ({ jsUrlInfo, options }) => {
|
|
4
|
+
const url = jsUrlInfo.url
|
|
5
|
+
const content = jsUrlInfo.content
|
|
6
|
+
const sourcemap = jsUrlInfo.sourcemap
|
|
7
|
+
const isJsModule = jsUrlInfo.type === "js_module"
|
|
24
8
|
|
|
25
|
-
const minifyJs = async ({ url, content, sourcemap, isJsModule }) => {
|
|
26
9
|
const { minify } = await import("terser")
|
|
27
10
|
const terserResult = await minify(
|
|
28
11
|
{
|
|
@@ -38,6 +21,7 @@ const minifyJs = async ({ url, content, sourcemap, isJsModule }) => {
|
|
|
38
21
|
// We need to preserve "new InlineContent()" calls to be able to recognize them
|
|
39
22
|
// after minification in order to version urls inside inline content text
|
|
40
23
|
keep_fnames: /InlineContent/,
|
|
24
|
+
...options,
|
|
41
25
|
},
|
|
42
26
|
)
|
|
43
27
|
return {
|