@jsenv/core 40.12.7 → 40.12.8
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/browserslist_index/browserslist_index.js +1 -1
- package/dist/build/build.js +276 -73
- package/dist/build/jsenv_core_packages.js +23 -19
- 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 +2 -2
- 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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "40.12.
|
|
3
|
+
"version": "40.12.8",
|
|
4
4
|
"description": "Tool to develop, test and build js projects",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"@financial-times/polyfill-useragent-normaliser": "1.10.2",
|
|
78
78
|
"@jsenv/ast": "6.7.20",
|
|
79
79
|
"@jsenv/js-module-fallback": "1.4.28",
|
|
80
|
-
"@jsenv/plugin-bundling": "2.10.
|
|
80
|
+
"@jsenv/plugin-bundling": "2.10.8",
|
|
81
81
|
"@jsenv/plugin-minification": "1.7.3",
|
|
82
82
|
"@jsenv/plugin-supervisor": "1.7.14",
|
|
83
83
|
"@jsenv/plugin-transpilation": "1.5.69",
|
package/src/build/build.js
CHANGED
|
@@ -24,7 +24,6 @@ import {
|
|
|
24
24
|
compareFileUrls,
|
|
25
25
|
createLookupPackageDirectory,
|
|
26
26
|
ensureEmptyDirectory,
|
|
27
|
-
lookupPackageDirectory,
|
|
28
27
|
readPackageAtOrNull,
|
|
29
28
|
updateJsonFileSync,
|
|
30
29
|
writeFileSync,
|
|
@@ -62,6 +61,7 @@ import { memoryUsage as processMemoryUsage } from "node:process";
|
|
|
62
61
|
import { watchSourceFiles } from "../helpers/watch_source_files.js";
|
|
63
62
|
import { jsenvCoreDirectoryUrl } from "../jsenv_core_directory_url.js";
|
|
64
63
|
import { createKitchen } from "../kitchen/kitchen.js";
|
|
64
|
+
import { createPackageDirectory } from "../kitchen/package_directory.js";
|
|
65
65
|
import { GRAPH_VISITOR } from "../kitchen/url_graph/url_graph_visitor.js";
|
|
66
66
|
import { jsenvPluginDirectoryReferenceEffect } from "../plugins/directory_reference_effect/jsenv_plugin_directory_reference_effect.js";
|
|
67
67
|
import { jsenvPluginInlining } from "../plugins/inlining/jsenv_plugin_inlining.js";
|
|
@@ -562,20 +562,19 @@ export const build = async ({
|
|
|
562
562
|
return compareFileUrls(a.sourceUrl, b.sourceUrl);
|
|
563
563
|
});
|
|
564
564
|
|
|
565
|
-
const
|
|
565
|
+
const lookupPackageDirectory = createLookupPackageDirectory();
|
|
566
|
+
const packageDirectory = createPackageDirectory({
|
|
567
|
+
sourceDirectoryUrl,
|
|
568
|
+
lookupPackageDirectory,
|
|
569
|
+
});
|
|
566
570
|
const packageDirectoryCache = new Map();
|
|
567
|
-
|
|
571
|
+
packageDirectory.read = (url) => {
|
|
568
572
|
const fromCache = packageDirectoryCache.get(url);
|
|
569
573
|
if (fromCache !== undefined) {
|
|
570
574
|
return fromCache;
|
|
571
575
|
}
|
|
572
576
|
return readPackageAtOrNull(url);
|
|
573
577
|
};
|
|
574
|
-
const packageDirectory = {
|
|
575
|
-
url: lookupPackageDirectory(sourceDirectoryUrl),
|
|
576
|
-
find: lookupPackageDirectoryUrl,
|
|
577
|
-
read: readPackageDirectory,
|
|
578
|
-
};
|
|
579
578
|
|
|
580
579
|
if (outDirectoryUrl === undefined) {
|
|
581
580
|
if (
|
|
@@ -772,7 +771,7 @@ export const build = async ({
|
|
|
772
771
|
sideEffects: sideEffectRelativeUrlArray,
|
|
773
772
|
});
|
|
774
773
|
};
|
|
775
|
-
const sideEffects =
|
|
774
|
+
const sideEffects = packageDirectory.read(
|
|
776
775
|
packageDirectory.url,
|
|
777
776
|
)?.sideEffects;
|
|
778
777
|
if (sideEffects === false) {
|
|
@@ -2,7 +2,6 @@ import {
|
|
|
2
2
|
assertAndNormalizeDirectoryUrl,
|
|
3
3
|
bufferToEtag,
|
|
4
4
|
lookupPackageDirectory,
|
|
5
|
-
readPackageAtOrNull,
|
|
6
5
|
} from "@jsenv/filesystem";
|
|
7
6
|
import { createLogger, createTaskLog, formatError } from "@jsenv/humanize";
|
|
8
7
|
import {
|
|
@@ -23,6 +22,7 @@ import { watchSourceFiles } from "../helpers/watch_source_files.js";
|
|
|
23
22
|
import { WEB_URL_CONVERTER } from "../helpers/web_url_converter.js";
|
|
24
23
|
import { jsenvCoreDirectoryUrl } from "../jsenv_core_directory_url.js";
|
|
25
24
|
import { createKitchen } from "../kitchen/kitchen.js";
|
|
25
|
+
import { createPackageDirectory } from "../kitchen/package_directory.js";
|
|
26
26
|
import {
|
|
27
27
|
createPluginController,
|
|
28
28
|
createPluginStore,
|
|
@@ -97,9 +97,11 @@ export const startDevServer = async ({
|
|
|
97
97
|
transpilation,
|
|
98
98
|
cacheControl = true,
|
|
99
99
|
ribbon = true,
|
|
100
|
+
dropToOpen = true,
|
|
100
101
|
// toolbar = false,
|
|
101
102
|
onKitchenCreated = () => {},
|
|
102
103
|
spa,
|
|
104
|
+
packageBundle,
|
|
103
105
|
|
|
104
106
|
sourcemaps = "inline",
|
|
105
107
|
sourcemapsSourcesContent,
|
|
@@ -245,11 +247,9 @@ export const startDevServer = async ({
|
|
|
245
247
|
);
|
|
246
248
|
serverStopCallbackSet.add(stopWatchingSourceFiles);
|
|
247
249
|
|
|
248
|
-
const packageDirectory = {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
read: readPackageAtOrNull,
|
|
252
|
-
};
|
|
250
|
+
const packageDirectory = createPackageDirectory({
|
|
251
|
+
sourceDirectoryUrl,
|
|
252
|
+
});
|
|
253
253
|
|
|
254
254
|
const devServerPluginStore = await createPluginStore([
|
|
255
255
|
jsenvPluginServerEvents({ clientAutoreload }),
|
|
@@ -272,11 +272,13 @@ export const startDevServer = async ({
|
|
|
272
272
|
injections,
|
|
273
273
|
transpilation,
|
|
274
274
|
spa,
|
|
275
|
+
packageBundle,
|
|
275
276
|
|
|
276
277
|
clientAutoreload,
|
|
277
278
|
clientAutoreloadOnServerRestart,
|
|
278
279
|
cacheControl,
|
|
279
280
|
ribbon,
|
|
281
|
+
dropToOpen,
|
|
280
282
|
}),
|
|
281
283
|
]);
|
|
282
284
|
const getOrCreateKitchen = async (request) => {
|
|
@@ -331,66 +333,74 @@ export const startDevServer = async ({
|
|
|
331
333
|
urlInfoCreated.isWatched = watch;
|
|
332
334
|
// when an url depends on many others, we check all these (like package.json)
|
|
333
335
|
urlInfoCreated.isValid = () => {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
// urlInfo content is undefined when:
|
|
339
|
-
// - url info content never fetched
|
|
340
|
-
// - it is considered as modified because undelying file is watched and got saved
|
|
341
|
-
// - it is considered as modified because underlying file content
|
|
342
|
-
// was compared using etag and it has changed
|
|
343
|
-
return false;
|
|
344
|
-
}
|
|
345
|
-
if (!watch) {
|
|
346
|
-
// file is not watched, check the filesystem
|
|
347
|
-
let fileContentAsBuffer;
|
|
348
|
-
try {
|
|
349
|
-
fileContentAsBuffer = readFileSync(new URL(urlInfoCreated.url));
|
|
350
|
-
} catch (e) {
|
|
351
|
-
if (e.code === "ENOENT") {
|
|
352
|
-
urlInfoCreated.onModified();
|
|
353
|
-
return false;
|
|
354
|
-
}
|
|
355
|
-
return false;
|
|
336
|
+
const seenSet = new Set();
|
|
337
|
+
const checkValidity = (urlInfo) => {
|
|
338
|
+
if (seenSet.has(urlInfo)) {
|
|
339
|
+
return true;
|
|
356
340
|
}
|
|
357
|
-
|
|
358
|
-
if (
|
|
359
|
-
urlInfoCreated.onModified();
|
|
360
|
-
// restore content to be able to compare it again later
|
|
361
|
-
urlInfoCreated.kitchen.urlInfoTransformer.setContent(
|
|
362
|
-
urlInfoCreated,
|
|
363
|
-
String(fileContentAsBuffer),
|
|
364
|
-
{
|
|
365
|
-
contentEtag: fileContentEtag,
|
|
366
|
-
},
|
|
367
|
-
);
|
|
341
|
+
seenSet.add(urlInfo);
|
|
342
|
+
if (!urlInfo.url.startsWith("file:")) {
|
|
368
343
|
return false;
|
|
369
344
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
345
|
+
if (urlInfo.content === undefined) {
|
|
346
|
+
// urlInfo content is undefined when:
|
|
347
|
+
// - url info content never fetched
|
|
348
|
+
// - it is considered as modified because undelying file is watched and got saved
|
|
349
|
+
// - it is considered as modified because underlying file content
|
|
350
|
+
// was compared using etag and it has changed
|
|
351
|
+
return false;
|
|
376
352
|
}
|
|
377
|
-
if (
|
|
378
|
-
//
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
353
|
+
if (!urlInfo.isWatched) {
|
|
354
|
+
// file is not watched, check the filesystem
|
|
355
|
+
let fileContentAsBuffer;
|
|
356
|
+
try {
|
|
357
|
+
fileContentAsBuffer = readFileSync(new URL(urlInfo.url));
|
|
358
|
+
} catch (e) {
|
|
359
|
+
if (e.code === "ENOENT") {
|
|
360
|
+
urlInfo.onModified();
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
const fileContentEtag = bufferToEtag(fileContentAsBuffer);
|
|
366
|
+
if (fileContentEtag !== urlInfo.originalContentEtag) {
|
|
367
|
+
urlInfo.onModified();
|
|
368
|
+
// restore content to be able to compare it again later
|
|
369
|
+
urlInfo.kitchen.urlInfoTransformer.setContent(
|
|
370
|
+
urlInfo,
|
|
371
|
+
String(fileContentAsBuffer),
|
|
372
|
+
{
|
|
373
|
+
contentEtag: fileContentEtag,
|
|
374
|
+
},
|
|
375
|
+
);
|
|
385
376
|
return false;
|
|
386
377
|
}
|
|
387
|
-
continue;
|
|
388
378
|
}
|
|
389
|
-
|
|
390
|
-
|
|
379
|
+
for (const implicitUrl of urlInfo.implicitUrlSet) {
|
|
380
|
+
const implicitUrlInfo = urlInfo.graph.getUrlInfo(implicitUrl);
|
|
381
|
+
if (!implicitUrlInfo) {
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
if (implicitUrlInfo.content === undefined) {
|
|
385
|
+
// happens when we explicitely load an url with a search param
|
|
386
|
+
// - it creates an implicit url info to the url without params
|
|
387
|
+
// - we never explicitely request the url without search param so it has no content
|
|
388
|
+
// in that case the underlying urlInfo cannot be invalidate by the implicit
|
|
389
|
+
// we use modifiedTimestamp to detect if the url was loaded once
|
|
390
|
+
// or is just here to be used later
|
|
391
|
+
if (implicitUrlInfo.modifiedTimestamp) {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
if (!checkValidity(implicitUrlInfo)) {
|
|
397
|
+
return false;
|
|
398
|
+
}
|
|
391
399
|
}
|
|
392
|
-
|
|
393
|
-
|
|
400
|
+
return true;
|
|
401
|
+
};
|
|
402
|
+
const valid = checkValidity(urlInfoCreated);
|
|
403
|
+
return valid;
|
|
394
404
|
};
|
|
395
405
|
});
|
|
396
406
|
kitchen.graph.urlInfoDereferencedEventEmitter.on(
|
package/src/kitchen/errors.js
CHANGED
|
@@ -338,6 +338,14 @@ const detailsFromPluginController = (pluginController) => {
|
|
|
338
338
|
|
|
339
339
|
const detailsFromValueThrown = (valueThrownByPlugin) => {
|
|
340
340
|
if (valueThrownByPlugin && valueThrownByPlugin instanceof Error) {
|
|
341
|
+
// if (
|
|
342
|
+
// valueThrownByPlugin.message.includes("Maximum call stack size exceeded")
|
|
343
|
+
// ) {
|
|
344
|
+
// return {
|
|
345
|
+
// "error message": valueThrownByPlugin.message,
|
|
346
|
+
// "error stack": valueThrownByPlugin.stack,
|
|
347
|
+
// };
|
|
348
|
+
// }
|
|
341
349
|
if (
|
|
342
350
|
valueThrownByPlugin.code === "PARSE_ERROR" ||
|
|
343
351
|
valueThrownByPlugin.code === "MODULE_NOT_FOUND" ||
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
lookupPackageDirectory as lookupPackageDirectoryDefault,
|
|
3
|
+
readPackageAtOrNull,
|
|
4
|
+
} from "@jsenv/filesystem";
|
|
5
|
+
|
|
6
|
+
export const createPackageDirectory = ({
|
|
7
|
+
sourceDirectoryUrl,
|
|
8
|
+
lookupPackageDirectory = lookupPackageDirectoryDefault,
|
|
9
|
+
}) => {
|
|
10
|
+
const packageDirectory = {
|
|
11
|
+
url: lookupPackageDirectory(sourceDirectoryUrl),
|
|
12
|
+
find: (url) => {
|
|
13
|
+
const urlString = typeof url === "string" ? url : url?.href;
|
|
14
|
+
if (!urlString.startsWith("file:")) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return lookupPackageDirectory(url);
|
|
18
|
+
},
|
|
19
|
+
read: readPackageAtOrNull,
|
|
20
|
+
};
|
|
21
|
+
return packageDirectory;
|
|
22
|
+
};
|
|
@@ -324,26 +324,13 @@ const createUrlInfo = (url, context) => {
|
|
|
324
324
|
}
|
|
325
325
|
return false;
|
|
326
326
|
};
|
|
327
|
-
|
|
328
|
-
// The search param can be
|
|
329
|
-
// 1. injected by a plugin during "redirectReference"
|
|
330
|
-
// - import assertions
|
|
331
|
-
// - js module fallback to systemjs
|
|
332
|
-
// 2. already inside source files
|
|
333
|
-
// - turn js module into js classic for convenience ?as_js_classic
|
|
334
|
-
// - turn js classic to js module for to make it importable
|
|
335
|
-
if (!urlInfo.searchParams.has(searchParam)) {
|
|
336
|
-
return null;
|
|
337
|
-
}
|
|
327
|
+
const getNextUrlInfo = (newProps) => {
|
|
338
328
|
const reference = urlInfo.firstReference;
|
|
339
|
-
const
|
|
340
|
-
[searchParam]: undefined,
|
|
341
|
-
});
|
|
342
|
-
const referenceWithoutSearchParam = reference.addImplicit({
|
|
329
|
+
const nextReference = reference.addImplicit({
|
|
343
330
|
type: reference.type,
|
|
344
331
|
subtype: reference.subtype,
|
|
345
332
|
expectedContentType: reference.expectedContentType,
|
|
346
|
-
expectedType:
|
|
333
|
+
expectedType: reference.expectedType,
|
|
347
334
|
expectedSubtype: reference.expectedSubtype,
|
|
348
335
|
integrity: reference.integrity,
|
|
349
336
|
crossorigin: reference.crossorigin,
|
|
@@ -367,7 +354,6 @@ const createUrlInfo = (url, context) => {
|
|
|
367
354
|
astInfo: reference.astInfo,
|
|
368
355
|
mutation: reference.mutation,
|
|
369
356
|
data: { ...reference.data },
|
|
370
|
-
specifier: newSpecifier,
|
|
371
357
|
isWeak: true,
|
|
372
358
|
isInline: reference.isInline,
|
|
373
359
|
original: reference.original || reference,
|
|
@@ -377,9 +363,37 @@ const createUrlInfo = (url, context) => {
|
|
|
377
363
|
// generatedUrl: null,
|
|
378
364
|
// generatedSpecifier: null,
|
|
379
365
|
// filename: null,
|
|
366
|
+
...newProps,
|
|
367
|
+
});
|
|
368
|
+
reference.next = nextReference;
|
|
369
|
+
return nextReference.urlInfo;
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
urlInfo.redirect = (props) => {
|
|
373
|
+
return getNextUrlInfo(props);
|
|
374
|
+
};
|
|
375
|
+
urlInfo.getWithoutSearchParam = (searchParam, props) => {
|
|
376
|
+
// The search param can be
|
|
377
|
+
// 1. injected by a plugin during "redirectReference"
|
|
378
|
+
// - import assertions
|
|
379
|
+
// - js module fallback to systemjs
|
|
380
|
+
// 2. already inside source files
|
|
381
|
+
// - turn js module into js classic for convenience ?as_js_classic
|
|
382
|
+
// - turn js classic to js module for to make it importable
|
|
383
|
+
if (!urlInfo.searchParams.has(searchParam)) {
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
const reference = urlInfo.firstReference;
|
|
387
|
+
const specifierWithoutSearchParam = injectQueryParamsIntoSpecifier(
|
|
388
|
+
reference.specifier,
|
|
389
|
+
{
|
|
390
|
+
[searchParam]: undefined,
|
|
391
|
+
},
|
|
392
|
+
);
|
|
393
|
+
return urlInfo.redirect({
|
|
394
|
+
specifier: specifierWithoutSearchParam,
|
|
395
|
+
...props,
|
|
380
396
|
});
|
|
381
|
-
reference.next = referenceWithoutSearchParam;
|
|
382
|
-
return referenceWithoutSearchParam.urlInfo;
|
|
383
397
|
};
|
|
384
398
|
urlInfo.onRemoved = () => {
|
|
385
399
|
urlInfo.kitchen.urlInfoTransformer.resetContent(urlInfo);
|
package/src/plugins/plugins.js
CHANGED
|
@@ -28,6 +28,7 @@ import { jsenvPluginCleanHTML } from "./clean_html/jsenv_plugin_clean_html.js";
|
|
|
28
28
|
import { jsenvPluginChromeDevtoolsJson } from "./chrome_devtools_json/jsenv_plugin_chrome_devtools_json.js";
|
|
29
29
|
import { jsenvPluginAutoreloadOnServerRestart } from "./autoreload_on_server_restart/jsenv_plugin_autoreload_on_server_restart.js";
|
|
30
30
|
import { jsenvPluginPackageSideEffects } from "./package_side_effects/jsenv_plugin_package_side_effects.js";
|
|
31
|
+
import { jsenvPluginWorkspaceBundle } from "./workspace_bundle/jsenv_plugin_workspace_bundle.js";
|
|
31
32
|
|
|
32
33
|
export const getCorePlugins = ({
|
|
33
34
|
rootDirectoryUrl,
|
|
@@ -50,12 +51,14 @@ export const getCorePlugins = ({
|
|
|
50
51
|
inlining = true,
|
|
51
52
|
http = false,
|
|
52
53
|
spa,
|
|
54
|
+
packageBundle,
|
|
53
55
|
|
|
54
56
|
clientAutoreload,
|
|
55
57
|
clientAutoreloadOnServerRestart,
|
|
56
58
|
cacheControl,
|
|
57
59
|
scenarioPlaceholders = true,
|
|
58
60
|
ribbon = true,
|
|
61
|
+
dropToOpen = true,
|
|
59
62
|
packageSideEffects = false,
|
|
60
63
|
} = {}) => {
|
|
61
64
|
if (cacheControl === true) {
|
|
@@ -78,6 +81,9 @@ export const getCorePlugins = ({
|
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
return [
|
|
84
|
+
...(packageBundle
|
|
85
|
+
? [jsenvPluginWorkspaceBundle({ packageDirectory })]
|
|
86
|
+
: []),
|
|
81
87
|
jsenvPluginReferenceAnalysis(referenceAnalysis),
|
|
82
88
|
jsenvPluginInjections(injections),
|
|
83
89
|
jsenvPluginTranspilation(transpilation),
|
|
@@ -116,11 +122,12 @@ export const getCorePlugins = ({
|
|
|
116
122
|
},
|
|
117
123
|
...(nodeEsmResolution
|
|
118
124
|
? [
|
|
119
|
-
jsenvPluginNodeEsmResolution(
|
|
120
|
-
|
|
125
|
+
jsenvPluginNodeEsmResolution({
|
|
126
|
+
packageDirectory,
|
|
127
|
+
resolutionConfig: nodeEsmResolution,
|
|
121
128
|
packageConditions,
|
|
122
129
|
packageConditionsConfig,
|
|
123
|
-
),
|
|
130
|
+
}),
|
|
124
131
|
]
|
|
125
132
|
: []),
|
|
126
133
|
jsenvPluginWebResolution(),
|
|
@@ -147,7 +154,7 @@ export const getCorePlugins = ({
|
|
|
147
154
|
: []),
|
|
148
155
|
...(cacheControl ? [jsenvPluginCacheControl(cacheControl)] : []),
|
|
149
156
|
...(ribbon ? [jsenvPluginRibbon({ rootDirectoryUrl, ...ribbon })] : []),
|
|
150
|
-
jsenvPluginDropToOpen(),
|
|
157
|
+
...(dropToOpen ? [jsenvPluginDropToOpen()] : []),
|
|
151
158
|
jsenvPluginCleanHTML(),
|
|
152
159
|
jsenvPluginChromeDevtoolsJson(),
|
|
153
160
|
...(packageSideEffects
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { createNodeEsmResolver } from "./node_esm_resolver.js";
|
|
2
2
|
|
|
3
|
-
export const jsenvPluginNodeEsmResolution = (
|
|
3
|
+
export const jsenvPluginNodeEsmResolution = ({
|
|
4
|
+
packageDirectory,
|
|
4
5
|
resolutionConfig = {},
|
|
5
6
|
packageConditions,
|
|
6
7
|
packageConditionsConfig = {},
|
|
7
|
-
) => {
|
|
8
|
+
}) => {
|
|
8
9
|
let nodeEsmResolverDefault;
|
|
9
10
|
const resolverMap = new Map();
|
|
10
11
|
let anyTypeResolver;
|
|
@@ -22,6 +23,7 @@ export const jsenvPluginNodeEsmResolution = (
|
|
|
22
23
|
);
|
|
23
24
|
}
|
|
24
25
|
return createNodeEsmResolver({
|
|
26
|
+
packageDirectory,
|
|
25
27
|
runtimeCompat: kitchenContext.runtimeCompat,
|
|
26
28
|
rootDirectoryUrl: kitchenContext.rootDirectoryUrl,
|
|
27
29
|
packageConditions,
|
|
@@ -38,9 +40,10 @@ export const jsenvPluginNodeEsmResolution = (
|
|
|
38
40
|
appliesDuring: "*",
|
|
39
41
|
init: (kitchenContext) => {
|
|
40
42
|
nodeEsmResolverDefault = createNodeEsmResolver({
|
|
43
|
+
packageDirectory,
|
|
41
44
|
runtimeCompat: kitchenContext.runtimeCompat,
|
|
42
45
|
rootDirectoryUrl: kitchenContext.rootDirectoryUrl,
|
|
43
|
-
preservesSymlink: true,
|
|
46
|
+
// preservesSymlink: true,
|
|
44
47
|
packageConditions,
|
|
45
48
|
packageConditionsConfig: {
|
|
46
49
|
...kitchenContext.packageConditionsConfig,
|
|
@@ -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 {
|