@jsenv/core 40.12.7 → 40.12.9
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/README.md +1 -1
- package/dist/build/browserslist_index/browserslist_index.js +109 -3
- package/dist/build/build.js +276 -73
- package/dist/build/jsenv_core_node_modules.js +114 -361
- package/dist/build/jsenv_core_packages.js +23 -19
- package/dist/start_build_server/jsenv_core_node_modules.js +109 -361
- package/dist/start_dev_server/jsenv_core_node_modules.js +109 -361
- package/dist/start_dev_server/jsenv_core_packages.js +24 -20
- package/dist/start_dev_server/start_dev_server.js +336 -121
- package/package.json +14 -12
- package/src/build/build.js +8 -9
- package/src/dev/start_dev_server.js +68 -58
- package/src/kitchen/errors.js +8 -0
- package/src/kitchen/package_directory.js +22 -0
- package/src/kitchen/url_graph/url_graph.js +33 -19
- package/src/plugins/plugins.js +11 -4
- package/src/plugins/resolution_node_esm/jsenv_plugin_node_esm_resolution.js +6 -3
- package/src/plugins/resolution_node_esm/node_esm_resolver.js +75 -39
- package/src/plugins/workspace_bundle/jsenv_plugin_workspace_bundle.js +119 -0
|
@@ -9,8 +9,6 @@
|
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
applyNodeEsmResolution,
|
|
12
|
-
defaultLookupPackageScope,
|
|
13
|
-
defaultReadPackageJson,
|
|
14
12
|
readCustomConditionsFromProcessArgs,
|
|
15
13
|
} from "@jsenv/node-esm-resolution";
|
|
16
14
|
import { URL_META } from "@jsenv/url-meta";
|
|
@@ -18,18 +16,27 @@ import { urlToBasename, urlToExtension } from "@jsenv/urls";
|
|
|
18
16
|
import { readFileSync } from "node:fs";
|
|
19
17
|
|
|
20
18
|
export const createNodeEsmResolver = ({
|
|
19
|
+
packageDirectory,
|
|
21
20
|
runtimeCompat,
|
|
22
21
|
rootDirectoryUrl,
|
|
23
22
|
packageConditions = {},
|
|
24
23
|
packageConditionsConfig,
|
|
25
24
|
preservesSymlink,
|
|
26
25
|
}) => {
|
|
26
|
+
const applyNodeEsmResolutionMemo = (params) =>
|
|
27
|
+
applyNodeEsmResolution({
|
|
28
|
+
lookupPackageScope: packageDirectory.find,
|
|
29
|
+
readPackageJson: packageDirectory.read,
|
|
30
|
+
preservesSymlink,
|
|
31
|
+
...params,
|
|
32
|
+
});
|
|
27
33
|
const buildPackageConditions = createBuildPackageConditions(
|
|
28
34
|
packageConditions,
|
|
29
35
|
{
|
|
30
36
|
packageConditionsConfig,
|
|
31
37
|
rootDirectoryUrl,
|
|
32
38
|
runtimeCompat,
|
|
39
|
+
preservesSymlink,
|
|
33
40
|
},
|
|
34
41
|
);
|
|
35
42
|
|
|
@@ -61,7 +68,7 @@ export const createNodeEsmResolver = ({
|
|
|
61
68
|
reference.type === "sourcemap_comment";
|
|
62
69
|
|
|
63
70
|
const resolveNodeEsmFallbackOnWeb = createResolverWithFallbackOnError(
|
|
64
|
-
|
|
71
|
+
applyNodeEsmResolutionMemo,
|
|
65
72
|
({ specifier, parentUrl }) => {
|
|
66
73
|
const url = new URL(specifier, parentUrl).href;
|
|
67
74
|
return { url };
|
|
@@ -70,7 +77,7 @@ export const createNodeEsmResolver = ({
|
|
|
70
77
|
const DELEGATE_TO_WEB_RESOLUTION_PLUGIN = {};
|
|
71
78
|
const resolveNodeEsmFallbackNullToDelegateToWebPlugin =
|
|
72
79
|
createResolverWithFallbackOnError(
|
|
73
|
-
|
|
80
|
+
applyNodeEsmResolutionMemo,
|
|
74
81
|
() => DELEGATE_TO_WEB_RESOLUTION_PLUGIN,
|
|
75
82
|
);
|
|
76
83
|
|
|
@@ -78,11 +85,11 @@ export const createNodeEsmResolver = ({
|
|
|
78
85
|
webResolutionFallback,
|
|
79
86
|
resolver: webResolutionFallback
|
|
80
87
|
? resolveNodeEsmFallbackOnWeb
|
|
81
|
-
:
|
|
88
|
+
: applyNodeEsmResolutionMemo,
|
|
82
89
|
});
|
|
83
90
|
const resolver = webResolutionFallback
|
|
84
91
|
? resolveNodeEsmFallbackNullToDelegateToWebPlugin
|
|
85
|
-
:
|
|
92
|
+
: applyNodeEsmResolutionMemo;
|
|
86
93
|
|
|
87
94
|
const result = resolver({
|
|
88
95
|
conditions,
|
|
@@ -113,52 +120,79 @@ export const createNodeEsmResolver = ({
|
|
|
113
120
|
if (ownerUrlInfo.context.build) {
|
|
114
121
|
return url;
|
|
115
122
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
//
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
packageDirectoryUrl !== ownerUrlInfo.context.rootDirectoryUrl
|
|
140
|
-
) {
|
|
141
|
-
const packageVersion =
|
|
142
|
-
defaultReadPackageJson(packageDirectoryUrl).version;
|
|
143
|
-
// package version can be null, see https://github.com/babel/babel/blob/2ce56e832c2dd7a7ed92c89028ba929f874c2f5c/packages/babel-runtime/helpers/esm/package.json#L2
|
|
144
|
-
if (packageVersion) {
|
|
123
|
+
|
|
124
|
+
package_relationships: {
|
|
125
|
+
if (!url.startsWith("file:")) {
|
|
126
|
+
// data:, javascript:void(0), etc...
|
|
127
|
+
break package_relationships;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// packageDirectoryUrl can be already known thanks to node resolution
|
|
131
|
+
// otherwise we look for it
|
|
132
|
+
const closestPackageDirectoryUrl =
|
|
133
|
+
packageDirectoryUrl || packageDirectory.find(url);
|
|
134
|
+
if (!closestPackageDirectoryUrl) {
|
|
135
|
+
// happens for projects without package.json or some files outside of package scope
|
|
136
|
+
// (generated files like sourcemaps or cache files for example)
|
|
137
|
+
break package_relationships;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
resolution_relationship: {
|
|
141
|
+
const dependsOnPackageJson = Boolean(packageDirectoryUrl);
|
|
142
|
+
if (dependsOnPackageJson) {
|
|
143
|
+
// this reference depends on package.json and node_modules
|
|
144
|
+
// to be resolved. Each file using this specifier
|
|
145
|
+
// must be invalidated when corresponding package.json changes
|
|
145
146
|
addRelationshipWithPackageJson({
|
|
146
147
|
reference,
|
|
147
148
|
packageJsonUrl: `${packageDirectoryUrl}package.json`,
|
|
148
|
-
field: "
|
|
149
|
-
|
|
149
|
+
field: type.startsWith("field:")
|
|
150
|
+
? `#${type.slice("field:".length)}`
|
|
151
|
+
: "",
|
|
150
152
|
});
|
|
151
153
|
}
|
|
152
|
-
|
|
154
|
+
}
|
|
155
|
+
version_relationship: {
|
|
156
|
+
const packageVersion = packageDirectory.read(
|
|
157
|
+
closestPackageDirectoryUrl,
|
|
158
|
+
).version;
|
|
159
|
+
if (!packageVersion) {
|
|
160
|
+
// package version can be null, see https://github.com/babel/babel/blob/2ce56e832c2dd7a7ed92c89028ba929f874c2f5c/packages/babel-runtime/helpers/esm/package.json#L2
|
|
161
|
+
break version_relationship;
|
|
162
|
+
}
|
|
163
|
+
// We want the versioning effect
|
|
164
|
+
// which would put the file in browser cache for 1 year based on that version
|
|
165
|
+
// only for files we don't control and touch ourselves (node modules)
|
|
166
|
+
// which would never change until their version change
|
|
167
|
+
// (minus the case you update them yourselves in your node modules without updating the package version)
|
|
168
|
+
// (in that case you would have to clear browser cache to use the modified version of the node module files)
|
|
169
|
+
const hasVersioningEffect =
|
|
170
|
+
closestPackageDirectoryUrl !== packageDirectory.url &&
|
|
171
|
+
url.includes("/node_modules/");
|
|
172
|
+
addRelationshipWithPackageJson({
|
|
173
|
+
reference,
|
|
174
|
+
packageJsonUrl: `${closestPackageDirectoryUrl}package.json`,
|
|
175
|
+
field: "version",
|
|
176
|
+
hasVersioningEffect,
|
|
177
|
+
});
|
|
178
|
+
if (hasVersioningEffect) {
|
|
179
|
+
reference.version = packageVersion;
|
|
180
|
+
}
|
|
153
181
|
}
|
|
154
182
|
}
|
|
183
|
+
|
|
155
184
|
return url;
|
|
156
185
|
};
|
|
157
186
|
};
|
|
158
187
|
|
|
159
188
|
const createBuildPackageConditions = (
|
|
160
189
|
packageConditions,
|
|
161
|
-
{
|
|
190
|
+
{
|
|
191
|
+
packageConditionsConfig,
|
|
192
|
+
rootDirectoryUrl,
|
|
193
|
+
runtimeCompat,
|
|
194
|
+
preservesSymlink,
|
|
195
|
+
},
|
|
162
196
|
) => {
|
|
163
197
|
let resolveConditionsFromSpecifier = () => null;
|
|
164
198
|
let resolveConditionsFromContext = () => [];
|
|
@@ -185,6 +219,7 @@ const createBuildPackageConditions = (
|
|
|
185
219
|
const { packageDirectoryUrl } = applyNodeEsmResolution({
|
|
186
220
|
specifier: key.slice(0, -1), // avoid package path not exported
|
|
187
221
|
parentUrl: rootDirectoryUrl,
|
|
222
|
+
preservesSymlink,
|
|
188
223
|
});
|
|
189
224
|
const url = packageDirectoryUrl;
|
|
190
225
|
associationsRaw[url] = associatedValue;
|
|
@@ -193,6 +228,7 @@ const createBuildPackageConditions = (
|
|
|
193
228
|
const { url } = applyNodeEsmResolution({
|
|
194
229
|
specifier: key,
|
|
195
230
|
parentUrl: rootDirectoryUrl,
|
|
231
|
+
preservesSymlink,
|
|
196
232
|
});
|
|
197
233
|
associationsRaw[url] = associatedValue;
|
|
198
234
|
} catch {
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { bundleJsModules } from "@jsenv/plugin-bundling";
|
|
2
|
+
import { injectQueryParams, injectQueryParamsIntoSpecifier } from "@jsenv/urls";
|
|
3
|
+
|
|
4
|
+
const PACKAGE_BUNDLE_QUERY_PARAM = "package_bundle";
|
|
5
|
+
const PACKAGE_NO_BUNDLE_QUERY_PARAM = "package_no_bundle";
|
|
6
|
+
const DYNAMIC_IMPORT_QUERY_PARAM = "dynamic_import";
|
|
7
|
+
|
|
8
|
+
export const jsenvPluginWorkspaceBundle = ({ packageDirectory }) => {
|
|
9
|
+
return {
|
|
10
|
+
name: "jsenv:workspace_bundle",
|
|
11
|
+
appliesDuring: "dev",
|
|
12
|
+
redirectReference: (reference) => {
|
|
13
|
+
if (!reference.url.startsWith("file:")) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
if (reference.searchParams.has(PACKAGE_BUNDLE_QUERY_PARAM)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
if (reference.searchParams.has(PACKAGE_NO_BUNDLE_QUERY_PARAM)) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
if (
|
|
23
|
+
reference.ownerUrlInfo.searchParams.has(PACKAGE_NO_BUNDLE_QUERY_PARAM)
|
|
24
|
+
) {
|
|
25
|
+
// we're cooking the bundle, without this check we would have infinite recursion to try to bundle
|
|
26
|
+
// we want to propagate the ?package_no_bundle
|
|
27
|
+
const noBundleUrl = injectQueryParams(reference.url, {
|
|
28
|
+
v: undefined,
|
|
29
|
+
[PACKAGE_NO_BUNDLE_QUERY_PARAM]: "",
|
|
30
|
+
});
|
|
31
|
+
// console.log(
|
|
32
|
+
// `redirecting ${reference.url} to ${noBundleUrl} to cook the bundle`,
|
|
33
|
+
// );
|
|
34
|
+
return noBundleUrl;
|
|
35
|
+
}
|
|
36
|
+
const packageDirectoryUrl = packageDirectory.find(reference.url);
|
|
37
|
+
if (!packageDirectoryUrl) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
if (packageDirectoryUrl === packageDirectory.url) {
|
|
41
|
+
// root package, we don't want to bundle
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
// we make sure we target the bundle version of the package
|
|
45
|
+
// otherwise we might execute some parts of the package code multiple times.
|
|
46
|
+
// so we need to redirect the potential reference to non entry point to the package main entry point
|
|
47
|
+
const packageJSON = packageDirectory.read(packageDirectoryUrl);
|
|
48
|
+
const rootReference = reference.ownerUrlInfo.dependencies.inject({
|
|
49
|
+
type: "js_import",
|
|
50
|
+
specifier: `${packageJSON.name}?${PACKAGE_BUNDLE_QUERY_PARAM}`,
|
|
51
|
+
});
|
|
52
|
+
// console.log(
|
|
53
|
+
// `redirecting ${reference.url} to ${rootReference.url} to target the package bundle version of the package`,
|
|
54
|
+
// );
|
|
55
|
+
const packageMainUrl = rootReference.url;
|
|
56
|
+
return packageMainUrl;
|
|
57
|
+
},
|
|
58
|
+
fetchUrlContent: async (urlInfo) => {
|
|
59
|
+
if (!urlInfo.searchParams.has(PACKAGE_BUNDLE_QUERY_PARAM)) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
const noBundleSpecifier = injectQueryParamsIntoSpecifier(
|
|
63
|
+
urlInfo.firstReference.specifier,
|
|
64
|
+
{
|
|
65
|
+
[PACKAGE_BUNDLE_QUERY_PARAM]: undefined,
|
|
66
|
+
[PACKAGE_NO_BUNDLE_QUERY_PARAM]: "",
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
const noBundleUrlInfo = urlInfo.redirect({
|
|
70
|
+
specifier: noBundleSpecifier,
|
|
71
|
+
});
|
|
72
|
+
if (!noBundleUrlInfo) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
await noBundleUrlInfo.cook();
|
|
76
|
+
await noBundleUrlInfo.cookDependencies({
|
|
77
|
+
// we ignore dynamic import to cook lazyly (as browser request the server)
|
|
78
|
+
// these dynamic imports must inherit "?package_bundle"
|
|
79
|
+
// This is done inside rollup for convenience
|
|
80
|
+
ignoreDynamicImport: true,
|
|
81
|
+
});
|
|
82
|
+
const bundleUrlInfos = await bundleJsModules([noBundleUrlInfo], {
|
|
83
|
+
chunks: false,
|
|
84
|
+
buildDirectoryUrl: new URL("./", import.meta.url),
|
|
85
|
+
preserveDynamicImports: true,
|
|
86
|
+
augmentDynamicImportUrlSearchParams: () => {
|
|
87
|
+
return {
|
|
88
|
+
[DYNAMIC_IMPORT_QUERY_PARAM]: "",
|
|
89
|
+
[PACKAGE_BUNDLE_QUERY_PARAM]: "",
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
const bundledUrlInfo = bundleUrlInfos[noBundleUrlInfo.url];
|
|
94
|
+
if (urlInfo.context.dev) {
|
|
95
|
+
for (const sourceUrl of bundledUrlInfo.sourceUrls) {
|
|
96
|
+
urlInfo.dependencies.inject({
|
|
97
|
+
isImplicit: true,
|
|
98
|
+
type: "js_url",
|
|
99
|
+
specifier: sourceUrl,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
content: bundledUrlInfo.content,
|
|
105
|
+
contentType: "text/javascript",
|
|
106
|
+
type: "js_module",
|
|
107
|
+
originalUrl: urlInfo.originalUrl,
|
|
108
|
+
originalContent: bundledUrlInfo.originalContent,
|
|
109
|
+
sourcemap: bundledUrlInfo.sourcemap,
|
|
110
|
+
data: bundledUrlInfo.data,
|
|
111
|
+
};
|
|
112
|
+
},
|
|
113
|
+
// transformReferenceSearchParams: () => {
|
|
114
|
+
// return {
|
|
115
|
+
// [PACKAGE_BUNDLE_QUERY_PARAM]: undefined,
|
|
116
|
+
// };
|
|
117
|
+
// },
|
|
118
|
+
};
|
|
119
|
+
};
|