@jsenv/core 40.12.6 → 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 +7 -7
- 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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WebSocketResponse, pickContentType, ServerEvents, jsenvServiceCORS, jsenvAccessControlAllowedHeaders, composeTwoResponses, serveDirectory, jsenvServiceErrorHandler, startServer } from "@jsenv/server";
|
|
2
2
|
import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/internal/convertFileSystemErrorToResponseProperties.js";
|
|
3
|
-
import { lookupPackageDirectory, registerDirectoryLifecycle, urlToRelativeUrl, moveUrl, urlIsOrIsInsideOf, ensureWindowsDriveLetter, createDetailedMessage, stringifyUrlSite, generateContentFrame, validateResponseIntegrity, setUrlFilename, getCallerPosition, urlToBasename, urlToExtension, asSpecifierWithoutSearch, asUrlWithoutSearch, injectQueryParamsIntoSpecifier, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, urlToFileSystemPath, writeFileSync, createLogger, URL_META, applyNodeEsmResolution, normalizeUrl, ANSI, RUNTIME_COMPAT, CONTENT_TYPE, errorToHTML, DATA_URL, normalizeImportMap, composeTwoImportMaps, resolveImport, JS_QUOTES,
|
|
3
|
+
import { lookupPackageDirectory, registerDirectoryLifecycle, urlToRelativeUrl, moveUrl, urlIsOrIsInsideOf, ensureWindowsDriveLetter, createDetailedMessage, stringifyUrlSite, generateContentFrame, validateResponseIntegrity, setUrlFilename, getCallerPosition, urlToBasename, urlToExtension, asSpecifierWithoutSearch, asUrlWithoutSearch, injectQueryParamsIntoSpecifier, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, urlToFileSystemPath, writeFileSync, createLogger, URL_META, applyNodeEsmResolution, normalizeUrl, ANSI, RUNTIME_COMPAT, CONTENT_TYPE, readPackageAtOrNull, errorToHTML, DATA_URL, normalizeImportMap, composeTwoImportMaps, resolveImport, JS_QUOTES, readCustomConditionsFromProcessArgs, readEntryStatSync, ensurePathnameTrailingSlash, compareFileUrls, urlToFilename, applyFileSystemMagicResolution, getExtensionsToTry, setUrlExtension, isSpecifierForNodeBuiltin, injectQueryParams, memoizeByFirstArgument, assertAndNormalizeDirectoryUrl, createTaskLog, formatError } from "./jsenv_core_packages.js";
|
|
4
4
|
import { readFileSync, existsSync, readdirSync, lstatSync, realpathSync } from "node:fs";
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
6
|
import { generateSourcemapFileUrl, createMagicSource, composeTwoSourcemaps, generateSourcemapDataUrl, SOURCEMAP } from "@jsenv/sourcemap";
|
|
@@ -9,6 +9,7 @@ import { performance } from "node:perf_hooks";
|
|
|
9
9
|
import { jsenvPluginSupervisor } from "@jsenv/plugin-supervisor";
|
|
10
10
|
import { jsenvPluginTranspilation } from "@jsenv/plugin-transpilation";
|
|
11
11
|
import { randomUUID } from "node:crypto";
|
|
12
|
+
import { bundleJsModules } from "@jsenv/plugin-bundling";
|
|
12
13
|
import { createRequire } from "node:module";
|
|
13
14
|
import "./jsenv_core_node_modules.js";
|
|
14
15
|
import "node:process";
|
|
@@ -527,6 +528,14 @@ const detailsFromPluginController = (pluginController) => {
|
|
|
527
528
|
|
|
528
529
|
const detailsFromValueThrown = (valueThrownByPlugin) => {
|
|
529
530
|
if (valueThrownByPlugin && valueThrownByPlugin instanceof Error) {
|
|
531
|
+
// if (
|
|
532
|
+
// valueThrownByPlugin.message.includes("Maximum call stack size exceeded")
|
|
533
|
+
// ) {
|
|
534
|
+
// return {
|
|
535
|
+
// "error message": valueThrownByPlugin.message,
|
|
536
|
+
// "error stack": valueThrownByPlugin.stack,
|
|
537
|
+
// };
|
|
538
|
+
// }
|
|
530
539
|
if (
|
|
531
540
|
valueThrownByPlugin.code === "PARSE_ERROR" ||
|
|
532
541
|
valueThrownByPlugin.code === "MODULE_NOT_FOUND" ||
|
|
@@ -2047,26 +2056,13 @@ const createUrlInfo = (url, context) => {
|
|
|
2047
2056
|
}
|
|
2048
2057
|
return false;
|
|
2049
2058
|
};
|
|
2050
|
-
|
|
2051
|
-
// The search param can be
|
|
2052
|
-
// 1. injected by a plugin during "redirectReference"
|
|
2053
|
-
// - import assertions
|
|
2054
|
-
// - js module fallback to systemjs
|
|
2055
|
-
// 2. already inside source files
|
|
2056
|
-
// - turn js module into js classic for convenience ?as_js_classic
|
|
2057
|
-
// - turn js classic to js module for to make it importable
|
|
2058
|
-
if (!urlInfo.searchParams.has(searchParam)) {
|
|
2059
|
-
return null;
|
|
2060
|
-
}
|
|
2059
|
+
const getNextUrlInfo = (newProps) => {
|
|
2061
2060
|
const reference = urlInfo.firstReference;
|
|
2062
|
-
const
|
|
2063
|
-
[searchParam]: undefined,
|
|
2064
|
-
});
|
|
2065
|
-
const referenceWithoutSearchParam = reference.addImplicit({
|
|
2061
|
+
const nextReference = reference.addImplicit({
|
|
2066
2062
|
type: reference.type,
|
|
2067
2063
|
subtype: reference.subtype,
|
|
2068
2064
|
expectedContentType: reference.expectedContentType,
|
|
2069
|
-
expectedType:
|
|
2065
|
+
expectedType: reference.expectedType,
|
|
2070
2066
|
expectedSubtype: reference.expectedSubtype,
|
|
2071
2067
|
integrity: reference.integrity,
|
|
2072
2068
|
crossorigin: reference.crossorigin,
|
|
@@ -2090,7 +2086,6 @@ const createUrlInfo = (url, context) => {
|
|
|
2090
2086
|
astInfo: reference.astInfo,
|
|
2091
2087
|
mutation: reference.mutation,
|
|
2092
2088
|
data: { ...reference.data },
|
|
2093
|
-
specifier: newSpecifier,
|
|
2094
2089
|
isWeak: true,
|
|
2095
2090
|
isInline: reference.isInline,
|
|
2096
2091
|
original: reference.original || reference,
|
|
@@ -2100,9 +2095,37 @@ const createUrlInfo = (url, context) => {
|
|
|
2100
2095
|
// generatedUrl: null,
|
|
2101
2096
|
// generatedSpecifier: null,
|
|
2102
2097
|
// filename: null,
|
|
2098
|
+
...newProps,
|
|
2099
|
+
});
|
|
2100
|
+
reference.next = nextReference;
|
|
2101
|
+
return nextReference.urlInfo;
|
|
2102
|
+
};
|
|
2103
|
+
|
|
2104
|
+
urlInfo.redirect = (props) => {
|
|
2105
|
+
return getNextUrlInfo(props);
|
|
2106
|
+
};
|
|
2107
|
+
urlInfo.getWithoutSearchParam = (searchParam, props) => {
|
|
2108
|
+
// The search param can be
|
|
2109
|
+
// 1. injected by a plugin during "redirectReference"
|
|
2110
|
+
// - import assertions
|
|
2111
|
+
// - js module fallback to systemjs
|
|
2112
|
+
// 2. already inside source files
|
|
2113
|
+
// - turn js module into js classic for convenience ?as_js_classic
|
|
2114
|
+
// - turn js classic to js module for to make it importable
|
|
2115
|
+
if (!urlInfo.searchParams.has(searchParam)) {
|
|
2116
|
+
return null;
|
|
2117
|
+
}
|
|
2118
|
+
const reference = urlInfo.firstReference;
|
|
2119
|
+
const specifierWithoutSearchParam = injectQueryParamsIntoSpecifier(
|
|
2120
|
+
reference.specifier,
|
|
2121
|
+
{
|
|
2122
|
+
[searchParam]: undefined,
|
|
2123
|
+
},
|
|
2124
|
+
);
|
|
2125
|
+
return urlInfo.redirect({
|
|
2126
|
+
specifier: specifierWithoutSearchParam,
|
|
2127
|
+
...props,
|
|
2103
2128
|
});
|
|
2104
|
-
reference.next = referenceWithoutSearchParam;
|
|
2105
|
-
return referenceWithoutSearchParam.urlInfo;
|
|
2106
2129
|
};
|
|
2107
2130
|
urlInfo.onRemoved = () => {
|
|
2108
2131
|
urlInfo.kitchen.urlInfoTransformer.resetContent(urlInfo);
|
|
@@ -3804,6 +3827,24 @@ const inferUrlInfoType = (urlInfo) => {
|
|
|
3804
3827
|
return expectedType || "other";
|
|
3805
3828
|
};
|
|
3806
3829
|
|
|
3830
|
+
const createPackageDirectory = ({
|
|
3831
|
+
sourceDirectoryUrl,
|
|
3832
|
+
lookupPackageDirectory: lookupPackageDirectory$1 = lookupPackageDirectory,
|
|
3833
|
+
}) => {
|
|
3834
|
+
const packageDirectory = {
|
|
3835
|
+
url: lookupPackageDirectory$1(sourceDirectoryUrl),
|
|
3836
|
+
find: (url) => {
|
|
3837
|
+
const urlString = typeof url === "string" ? url : url?.href;
|
|
3838
|
+
if (!urlString.startsWith("file:")) {
|
|
3839
|
+
return null;
|
|
3840
|
+
}
|
|
3841
|
+
return lookupPackageDirectory$1(url);
|
|
3842
|
+
},
|
|
3843
|
+
read: readPackageAtOrNull,
|
|
3844
|
+
};
|
|
3845
|
+
return packageDirectory;
|
|
3846
|
+
};
|
|
3847
|
+
|
|
3807
3848
|
const jsenvPluginHtmlSyntaxErrorFallback = () => {
|
|
3808
3849
|
const htmlSyntaxErrorFileUrl = import.meta
|
|
3809
3850
|
.resolve("../client/html_syntax_error/html_syntax_error.html");
|
|
@@ -5589,18 +5630,27 @@ const jsenvPluginInlineContentFetcher = () => {
|
|
|
5589
5630
|
|
|
5590
5631
|
|
|
5591
5632
|
const createNodeEsmResolver = ({
|
|
5633
|
+
packageDirectory,
|
|
5592
5634
|
runtimeCompat,
|
|
5593
5635
|
rootDirectoryUrl,
|
|
5594
5636
|
packageConditions = {},
|
|
5595
5637
|
packageConditionsConfig,
|
|
5596
5638
|
preservesSymlink,
|
|
5597
5639
|
}) => {
|
|
5640
|
+
const applyNodeEsmResolutionMemo = (params) =>
|
|
5641
|
+
applyNodeEsmResolution({
|
|
5642
|
+
lookupPackageScope: packageDirectory.find,
|
|
5643
|
+
readPackageJson: packageDirectory.read,
|
|
5644
|
+
preservesSymlink,
|
|
5645
|
+
...params,
|
|
5646
|
+
});
|
|
5598
5647
|
const buildPackageConditions = createBuildPackageConditions(
|
|
5599
5648
|
packageConditions,
|
|
5600
5649
|
{
|
|
5601
5650
|
packageConditionsConfig,
|
|
5602
5651
|
rootDirectoryUrl,
|
|
5603
5652
|
runtimeCompat,
|
|
5653
|
+
preservesSymlink,
|
|
5604
5654
|
},
|
|
5605
5655
|
);
|
|
5606
5656
|
|
|
@@ -5632,7 +5682,7 @@ const createNodeEsmResolver = ({
|
|
|
5632
5682
|
reference.type === "sourcemap_comment";
|
|
5633
5683
|
|
|
5634
5684
|
const resolveNodeEsmFallbackOnWeb = createResolverWithFallbackOnError(
|
|
5635
|
-
|
|
5685
|
+
applyNodeEsmResolutionMemo,
|
|
5636
5686
|
({ specifier, parentUrl }) => {
|
|
5637
5687
|
const url = new URL(specifier, parentUrl).href;
|
|
5638
5688
|
return { url };
|
|
@@ -5641,7 +5691,7 @@ const createNodeEsmResolver = ({
|
|
|
5641
5691
|
const DELEGATE_TO_WEB_RESOLUTION_PLUGIN = {};
|
|
5642
5692
|
const resolveNodeEsmFallbackNullToDelegateToWebPlugin =
|
|
5643
5693
|
createResolverWithFallbackOnError(
|
|
5644
|
-
|
|
5694
|
+
applyNodeEsmResolutionMemo,
|
|
5645
5695
|
() => DELEGATE_TO_WEB_RESOLUTION_PLUGIN,
|
|
5646
5696
|
);
|
|
5647
5697
|
|
|
@@ -5649,11 +5699,11 @@ const createNodeEsmResolver = ({
|
|
|
5649
5699
|
webResolutionFallback,
|
|
5650
5700
|
resolver: webResolutionFallback
|
|
5651
5701
|
? resolveNodeEsmFallbackOnWeb
|
|
5652
|
-
:
|
|
5702
|
+
: applyNodeEsmResolutionMemo,
|
|
5653
5703
|
});
|
|
5654
5704
|
const resolver = webResolutionFallback
|
|
5655
5705
|
? resolveNodeEsmFallbackNullToDelegateToWebPlugin
|
|
5656
|
-
:
|
|
5706
|
+
: applyNodeEsmResolutionMemo;
|
|
5657
5707
|
|
|
5658
5708
|
const result = resolver({
|
|
5659
5709
|
conditions,
|
|
@@ -5684,52 +5734,79 @@ const createNodeEsmResolver = ({
|
|
|
5684
5734
|
if (ownerUrlInfo.context.build) {
|
|
5685
5735
|
return url;
|
|
5686
5736
|
}
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
//
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
packageDirectoryUrl !== ownerUrlInfo.context.rootDirectoryUrl
|
|
5711
|
-
) {
|
|
5712
|
-
const packageVersion =
|
|
5713
|
-
defaultReadPackageJson(packageDirectoryUrl).version;
|
|
5714
|
-
// package version can be null, see https://github.com/babel/babel/blob/2ce56e832c2dd7a7ed92c89028ba929f874c2f5c/packages/babel-runtime/helpers/esm/package.json#L2
|
|
5715
|
-
if (packageVersion) {
|
|
5737
|
+
|
|
5738
|
+
package_relationships: {
|
|
5739
|
+
if (!url.startsWith("file:")) {
|
|
5740
|
+
// data:, javascript:void(0), etc...
|
|
5741
|
+
break package_relationships;
|
|
5742
|
+
}
|
|
5743
|
+
|
|
5744
|
+
// packageDirectoryUrl can be already known thanks to node resolution
|
|
5745
|
+
// otherwise we look for it
|
|
5746
|
+
const closestPackageDirectoryUrl =
|
|
5747
|
+
packageDirectoryUrl || packageDirectory.find(url);
|
|
5748
|
+
if (!closestPackageDirectoryUrl) {
|
|
5749
|
+
// happens for projects without package.json or some files outside of package scope
|
|
5750
|
+
// (generated files like sourcemaps or cache files for example)
|
|
5751
|
+
break package_relationships;
|
|
5752
|
+
}
|
|
5753
|
+
|
|
5754
|
+
{
|
|
5755
|
+
const dependsOnPackageJson = Boolean(packageDirectoryUrl);
|
|
5756
|
+
if (dependsOnPackageJson) {
|
|
5757
|
+
// this reference depends on package.json and node_modules
|
|
5758
|
+
// to be resolved. Each file using this specifier
|
|
5759
|
+
// must be invalidated when corresponding package.json changes
|
|
5716
5760
|
addRelationshipWithPackageJson({
|
|
5717
5761
|
reference,
|
|
5718
5762
|
packageJsonUrl: `${packageDirectoryUrl}package.json`,
|
|
5719
|
-
field: "
|
|
5720
|
-
|
|
5763
|
+
field: type.startsWith("field:")
|
|
5764
|
+
? `#${type.slice("field:".length)}`
|
|
5765
|
+
: "",
|
|
5721
5766
|
});
|
|
5722
5767
|
}
|
|
5723
|
-
|
|
5768
|
+
}
|
|
5769
|
+
version_relationship: {
|
|
5770
|
+
const packageVersion = packageDirectory.read(
|
|
5771
|
+
closestPackageDirectoryUrl,
|
|
5772
|
+
).version;
|
|
5773
|
+
if (!packageVersion) {
|
|
5774
|
+
// package version can be null, see https://github.com/babel/babel/blob/2ce56e832c2dd7a7ed92c89028ba929f874c2f5c/packages/babel-runtime/helpers/esm/package.json#L2
|
|
5775
|
+
break version_relationship;
|
|
5776
|
+
}
|
|
5777
|
+
// We want the versioning effect
|
|
5778
|
+
// which would put the file in browser cache for 1 year based on that version
|
|
5779
|
+
// only for files we don't control and touch ourselves (node modules)
|
|
5780
|
+
// which would never change until their version change
|
|
5781
|
+
// (minus the case you update them yourselves in your node modules without updating the package version)
|
|
5782
|
+
// (in that case you would have to clear browser cache to use the modified version of the node module files)
|
|
5783
|
+
const hasVersioningEffect =
|
|
5784
|
+
closestPackageDirectoryUrl !== packageDirectory.url &&
|
|
5785
|
+
url.includes("/node_modules/");
|
|
5786
|
+
addRelationshipWithPackageJson({
|
|
5787
|
+
reference,
|
|
5788
|
+
packageJsonUrl: `${closestPackageDirectoryUrl}package.json`,
|
|
5789
|
+
field: "version",
|
|
5790
|
+
hasVersioningEffect,
|
|
5791
|
+
});
|
|
5792
|
+
if (hasVersioningEffect) {
|
|
5793
|
+
reference.version = packageVersion;
|
|
5794
|
+
}
|
|
5724
5795
|
}
|
|
5725
5796
|
}
|
|
5797
|
+
|
|
5726
5798
|
return url;
|
|
5727
5799
|
};
|
|
5728
5800
|
};
|
|
5729
5801
|
|
|
5730
5802
|
const createBuildPackageConditions = (
|
|
5731
5803
|
packageConditions,
|
|
5732
|
-
{
|
|
5804
|
+
{
|
|
5805
|
+
packageConditionsConfig,
|
|
5806
|
+
rootDirectoryUrl,
|
|
5807
|
+
runtimeCompat,
|
|
5808
|
+
preservesSymlink,
|
|
5809
|
+
},
|
|
5733
5810
|
) => {
|
|
5734
5811
|
let resolveConditionsFromSpecifier = () => null;
|
|
5735
5812
|
let resolveConditionsFromContext = () => [];
|
|
@@ -5756,6 +5833,7 @@ const createBuildPackageConditions = (
|
|
|
5756
5833
|
const { packageDirectoryUrl } = applyNodeEsmResolution({
|
|
5757
5834
|
specifier: key.slice(0, -1), // avoid package path not exported
|
|
5758
5835
|
parentUrl: rootDirectoryUrl,
|
|
5836
|
+
preservesSymlink,
|
|
5759
5837
|
});
|
|
5760
5838
|
const url = packageDirectoryUrl;
|
|
5761
5839
|
associationsRaw[url] = associatedValue;
|
|
@@ -5764,6 +5842,7 @@ const createBuildPackageConditions = (
|
|
|
5764
5842
|
const { url } = applyNodeEsmResolution({
|
|
5765
5843
|
specifier: key,
|
|
5766
5844
|
parentUrl: rootDirectoryUrl,
|
|
5845
|
+
preservesSymlink,
|
|
5767
5846
|
});
|
|
5768
5847
|
associationsRaw[url] = associatedValue;
|
|
5769
5848
|
} catch {
|
|
@@ -6035,11 +6114,12 @@ const isBareSpecifier = (specifier) => {
|
|
|
6035
6114
|
}
|
|
6036
6115
|
};
|
|
6037
6116
|
|
|
6038
|
-
const jsenvPluginNodeEsmResolution = (
|
|
6117
|
+
const jsenvPluginNodeEsmResolution = ({
|
|
6118
|
+
packageDirectory,
|
|
6039
6119
|
resolutionConfig = {},
|
|
6040
6120
|
packageConditions,
|
|
6041
6121
|
packageConditionsConfig = {},
|
|
6042
|
-
) => {
|
|
6122
|
+
}) => {
|
|
6043
6123
|
let nodeEsmResolverDefault;
|
|
6044
6124
|
const resolverMap = new Map();
|
|
6045
6125
|
let anyTypeResolver;
|
|
@@ -6057,6 +6137,7 @@ const jsenvPluginNodeEsmResolution = (
|
|
|
6057
6137
|
);
|
|
6058
6138
|
}
|
|
6059
6139
|
return createNodeEsmResolver({
|
|
6140
|
+
packageDirectory,
|
|
6060
6141
|
runtimeCompat: kitchenContext.runtimeCompat,
|
|
6061
6142
|
rootDirectoryUrl: kitchenContext.rootDirectoryUrl,
|
|
6062
6143
|
packageConditions,
|
|
@@ -6073,9 +6154,10 @@ const jsenvPluginNodeEsmResolution = (
|
|
|
6073
6154
|
appliesDuring: "*",
|
|
6074
6155
|
init: (kitchenContext) => {
|
|
6075
6156
|
nodeEsmResolverDefault = createNodeEsmResolver({
|
|
6157
|
+
packageDirectory,
|
|
6076
6158
|
runtimeCompat: kitchenContext.runtimeCompat,
|
|
6077
6159
|
rootDirectoryUrl: kitchenContext.rootDirectoryUrl,
|
|
6078
|
-
preservesSymlink: true,
|
|
6160
|
+
// preservesSymlink: true,
|
|
6079
6161
|
packageConditions,
|
|
6080
6162
|
packageConditionsConfig: {
|
|
6081
6163
|
...kitchenContext.packageConditionsConfig,
|
|
@@ -9190,6 +9272,123 @@ const jsenvPluginPackageSideEffects = ({ packageDirectory }) => {
|
|
|
9190
9272
|
};
|
|
9191
9273
|
};
|
|
9192
9274
|
|
|
9275
|
+
const PACKAGE_BUNDLE_QUERY_PARAM = "package_bundle";
|
|
9276
|
+
const PACKAGE_NO_BUNDLE_QUERY_PARAM = "package_no_bundle";
|
|
9277
|
+
const DYNAMIC_IMPORT_QUERY_PARAM = "dynamic_import";
|
|
9278
|
+
|
|
9279
|
+
const jsenvPluginWorkspaceBundle = ({ packageDirectory }) => {
|
|
9280
|
+
return {
|
|
9281
|
+
name: "jsenv:workspace_bundle",
|
|
9282
|
+
appliesDuring: "dev",
|
|
9283
|
+
redirectReference: (reference) => {
|
|
9284
|
+
if (!reference.url.startsWith("file:")) {
|
|
9285
|
+
return null;
|
|
9286
|
+
}
|
|
9287
|
+
if (reference.searchParams.has(PACKAGE_BUNDLE_QUERY_PARAM)) {
|
|
9288
|
+
return null;
|
|
9289
|
+
}
|
|
9290
|
+
if (reference.searchParams.has(PACKAGE_NO_BUNDLE_QUERY_PARAM)) {
|
|
9291
|
+
return null;
|
|
9292
|
+
}
|
|
9293
|
+
if (
|
|
9294
|
+
reference.ownerUrlInfo.searchParams.has(PACKAGE_NO_BUNDLE_QUERY_PARAM)
|
|
9295
|
+
) {
|
|
9296
|
+
// we're cooking the bundle, without this check we would have infinite recursion to try to bundle
|
|
9297
|
+
// we want to propagate the ?package_no_bundle
|
|
9298
|
+
const noBundleUrl = injectQueryParams(reference.url, {
|
|
9299
|
+
v: undefined,
|
|
9300
|
+
[PACKAGE_NO_BUNDLE_QUERY_PARAM]: "",
|
|
9301
|
+
});
|
|
9302
|
+
// console.log(
|
|
9303
|
+
// `redirecting ${reference.url} to ${noBundleUrl} to cook the bundle`,
|
|
9304
|
+
// );
|
|
9305
|
+
return noBundleUrl;
|
|
9306
|
+
}
|
|
9307
|
+
const packageDirectoryUrl = packageDirectory.find(reference.url);
|
|
9308
|
+
if (!packageDirectoryUrl) {
|
|
9309
|
+
return null;
|
|
9310
|
+
}
|
|
9311
|
+
if (packageDirectoryUrl === packageDirectory.url) {
|
|
9312
|
+
// root package, we don't want to bundle
|
|
9313
|
+
return null;
|
|
9314
|
+
}
|
|
9315
|
+
// we make sure we target the bundle version of the package
|
|
9316
|
+
// otherwise we might execute some parts of the package code multiple times.
|
|
9317
|
+
// so we need to redirect the potential reference to non entry point to the package main entry point
|
|
9318
|
+
const packageJSON = packageDirectory.read(packageDirectoryUrl);
|
|
9319
|
+
const rootReference = reference.ownerUrlInfo.dependencies.inject({
|
|
9320
|
+
type: "js_import",
|
|
9321
|
+
specifier: `${packageJSON.name}?${PACKAGE_BUNDLE_QUERY_PARAM}`,
|
|
9322
|
+
});
|
|
9323
|
+
// console.log(
|
|
9324
|
+
// `redirecting ${reference.url} to ${rootReference.url} to target the package bundle version of the package`,
|
|
9325
|
+
// );
|
|
9326
|
+
const packageMainUrl = rootReference.url;
|
|
9327
|
+
return packageMainUrl;
|
|
9328
|
+
},
|
|
9329
|
+
fetchUrlContent: async (urlInfo) => {
|
|
9330
|
+
if (!urlInfo.searchParams.has(PACKAGE_BUNDLE_QUERY_PARAM)) {
|
|
9331
|
+
return null;
|
|
9332
|
+
}
|
|
9333
|
+
const noBundleSpecifier = injectQueryParamsIntoSpecifier(
|
|
9334
|
+
urlInfo.firstReference.specifier,
|
|
9335
|
+
{
|
|
9336
|
+
[PACKAGE_BUNDLE_QUERY_PARAM]: undefined,
|
|
9337
|
+
[PACKAGE_NO_BUNDLE_QUERY_PARAM]: "",
|
|
9338
|
+
},
|
|
9339
|
+
);
|
|
9340
|
+
const noBundleUrlInfo = urlInfo.redirect({
|
|
9341
|
+
specifier: noBundleSpecifier,
|
|
9342
|
+
});
|
|
9343
|
+
if (!noBundleUrlInfo) {
|
|
9344
|
+
return null;
|
|
9345
|
+
}
|
|
9346
|
+
await noBundleUrlInfo.cook();
|
|
9347
|
+
await noBundleUrlInfo.cookDependencies({
|
|
9348
|
+
// we ignore dynamic import to cook lazyly (as browser request the server)
|
|
9349
|
+
// these dynamic imports must inherit "?package_bundle"
|
|
9350
|
+
// This is done inside rollup for convenience
|
|
9351
|
+
ignoreDynamicImport: true,
|
|
9352
|
+
});
|
|
9353
|
+
const bundleUrlInfos = await bundleJsModules([noBundleUrlInfo], {
|
|
9354
|
+
chunks: false,
|
|
9355
|
+
buildDirectoryUrl: new URL("../src/plugins/workspace_bundle/", import.meta.url),
|
|
9356
|
+
preserveDynamicImports: true,
|
|
9357
|
+
augmentDynamicImportUrlSearchParams: () => {
|
|
9358
|
+
return {
|
|
9359
|
+
[DYNAMIC_IMPORT_QUERY_PARAM]: "",
|
|
9360
|
+
[PACKAGE_BUNDLE_QUERY_PARAM]: "",
|
|
9361
|
+
};
|
|
9362
|
+
},
|
|
9363
|
+
});
|
|
9364
|
+
const bundledUrlInfo = bundleUrlInfos[noBundleUrlInfo.url];
|
|
9365
|
+
if (urlInfo.context.dev) {
|
|
9366
|
+
for (const sourceUrl of bundledUrlInfo.sourceUrls) {
|
|
9367
|
+
urlInfo.dependencies.inject({
|
|
9368
|
+
isImplicit: true,
|
|
9369
|
+
type: "js_url",
|
|
9370
|
+
specifier: sourceUrl,
|
|
9371
|
+
});
|
|
9372
|
+
}
|
|
9373
|
+
}
|
|
9374
|
+
return {
|
|
9375
|
+
content: bundledUrlInfo.content,
|
|
9376
|
+
contentType: "text/javascript",
|
|
9377
|
+
type: "js_module",
|
|
9378
|
+
originalUrl: urlInfo.originalUrl,
|
|
9379
|
+
originalContent: bundledUrlInfo.originalContent,
|
|
9380
|
+
sourcemap: bundledUrlInfo.sourcemap,
|
|
9381
|
+
data: bundledUrlInfo.data,
|
|
9382
|
+
};
|
|
9383
|
+
},
|
|
9384
|
+
// transformReferenceSearchParams: () => {
|
|
9385
|
+
// return {
|
|
9386
|
+
// [PACKAGE_BUNDLE_QUERY_PARAM]: undefined,
|
|
9387
|
+
// };
|
|
9388
|
+
// },
|
|
9389
|
+
};
|
|
9390
|
+
};
|
|
9391
|
+
|
|
9193
9392
|
// tslint:disable:ordered-imports
|
|
9194
9393
|
|
|
9195
9394
|
|
|
@@ -9214,12 +9413,14 @@ const getCorePlugins = ({
|
|
|
9214
9413
|
inlining = true,
|
|
9215
9414
|
http = false,
|
|
9216
9415
|
spa,
|
|
9416
|
+
packageBundle,
|
|
9217
9417
|
|
|
9218
9418
|
clientAutoreload,
|
|
9219
9419
|
clientAutoreloadOnServerRestart,
|
|
9220
9420
|
cacheControl,
|
|
9221
9421
|
scenarioPlaceholders = true,
|
|
9222
9422
|
ribbon = true,
|
|
9423
|
+
dropToOpen = true,
|
|
9223
9424
|
packageSideEffects = false,
|
|
9224
9425
|
} = {}) => {
|
|
9225
9426
|
if (cacheControl === true) {
|
|
@@ -9242,6 +9443,9 @@ const getCorePlugins = ({
|
|
|
9242
9443
|
}
|
|
9243
9444
|
|
|
9244
9445
|
return [
|
|
9446
|
+
...(packageBundle
|
|
9447
|
+
? [jsenvPluginWorkspaceBundle({ packageDirectory })]
|
|
9448
|
+
: []),
|
|
9245
9449
|
jsenvPluginReferenceAnalysis(referenceAnalysis),
|
|
9246
9450
|
jsenvPluginInjections(injections),
|
|
9247
9451
|
jsenvPluginTranspilation(transpilation),
|
|
@@ -9280,11 +9484,12 @@ const getCorePlugins = ({
|
|
|
9280
9484
|
},
|
|
9281
9485
|
...(nodeEsmResolution
|
|
9282
9486
|
? [
|
|
9283
|
-
jsenvPluginNodeEsmResolution(
|
|
9284
|
-
|
|
9487
|
+
jsenvPluginNodeEsmResolution({
|
|
9488
|
+
packageDirectory,
|
|
9489
|
+
resolutionConfig: nodeEsmResolution,
|
|
9285
9490
|
packageConditions,
|
|
9286
9491
|
packageConditionsConfig,
|
|
9287
|
-
),
|
|
9492
|
+
}),
|
|
9288
9493
|
]
|
|
9289
9494
|
: []),
|
|
9290
9495
|
jsenvPluginWebResolution(),
|
|
@@ -9311,7 +9516,7 @@ const getCorePlugins = ({
|
|
|
9311
9516
|
: []),
|
|
9312
9517
|
...(cacheControl ? [jsenvPluginCacheControl(cacheControl)] : []),
|
|
9313
9518
|
...(ribbon ? [jsenvPluginRibbon({ rootDirectoryUrl, ...ribbon })] : []),
|
|
9314
|
-
jsenvPluginDropToOpen(),
|
|
9519
|
+
...(dropToOpen ? [jsenvPluginDropToOpen()] : []),
|
|
9315
9520
|
jsenvPluginCleanHTML(),
|
|
9316
9521
|
jsenvPluginChromeDevtoolsJson(),
|
|
9317
9522
|
...(packageSideEffects
|
|
@@ -9508,9 +9713,11 @@ const startDevServer = async ({
|
|
|
9508
9713
|
transpilation,
|
|
9509
9714
|
cacheControl = true,
|
|
9510
9715
|
ribbon = true,
|
|
9716
|
+
dropToOpen = true,
|
|
9511
9717
|
// toolbar = false,
|
|
9512
9718
|
onKitchenCreated = () => {},
|
|
9513
9719
|
spa,
|
|
9720
|
+
packageBundle,
|
|
9514
9721
|
|
|
9515
9722
|
sourcemaps = "inline",
|
|
9516
9723
|
sourcemapsSourcesContent,
|
|
@@ -9655,11 +9862,9 @@ const startDevServer = async ({
|
|
|
9655
9862
|
);
|
|
9656
9863
|
serverStopCallbackSet.add(stopWatchingSourceFiles);
|
|
9657
9864
|
|
|
9658
|
-
const packageDirectory = {
|
|
9659
|
-
|
|
9660
|
-
|
|
9661
|
-
read: readPackageAtOrNull,
|
|
9662
|
-
};
|
|
9865
|
+
const packageDirectory = createPackageDirectory({
|
|
9866
|
+
sourceDirectoryUrl,
|
|
9867
|
+
});
|
|
9663
9868
|
|
|
9664
9869
|
const devServerPluginStore = await createPluginStore([
|
|
9665
9870
|
jsenvPluginServerEvents({ clientAutoreload }),
|
|
@@ -9682,11 +9887,13 @@ const startDevServer = async ({
|
|
|
9682
9887
|
injections,
|
|
9683
9888
|
transpilation,
|
|
9684
9889
|
spa,
|
|
9890
|
+
packageBundle,
|
|
9685
9891
|
|
|
9686
9892
|
clientAutoreload,
|
|
9687
9893
|
clientAutoreloadOnServerRestart,
|
|
9688
9894
|
cacheControl,
|
|
9689
9895
|
ribbon,
|
|
9896
|
+
dropToOpen,
|
|
9690
9897
|
}),
|
|
9691
9898
|
]);
|
|
9692
9899
|
const getOrCreateKitchen = async (request) => {
|
|
@@ -9741,66 +9948,74 @@ const startDevServer = async ({
|
|
|
9741
9948
|
urlInfoCreated.isWatched = watch;
|
|
9742
9949
|
// when an url depends on many others, we check all these (like package.json)
|
|
9743
9950
|
urlInfoCreated.isValid = () => {
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
// urlInfo content is undefined when:
|
|
9749
|
-
// - url info content never fetched
|
|
9750
|
-
// - it is considered as modified because undelying file is watched and got saved
|
|
9751
|
-
// - it is considered as modified because underlying file content
|
|
9752
|
-
// was compared using etag and it has changed
|
|
9753
|
-
return false;
|
|
9754
|
-
}
|
|
9755
|
-
if (!watch) {
|
|
9756
|
-
// file is not watched, check the filesystem
|
|
9757
|
-
let fileContentAsBuffer;
|
|
9758
|
-
try {
|
|
9759
|
-
fileContentAsBuffer = readFileSync(new URL(urlInfoCreated.url));
|
|
9760
|
-
} catch (e) {
|
|
9761
|
-
if (e.code === "ENOENT") {
|
|
9762
|
-
urlInfoCreated.onModified();
|
|
9763
|
-
return false;
|
|
9764
|
-
}
|
|
9765
|
-
return false;
|
|
9951
|
+
const seenSet = new Set();
|
|
9952
|
+
const checkValidity = (urlInfo) => {
|
|
9953
|
+
if (seenSet.has(urlInfo)) {
|
|
9954
|
+
return true;
|
|
9766
9955
|
}
|
|
9767
|
-
|
|
9768
|
-
if (
|
|
9769
|
-
urlInfoCreated.onModified();
|
|
9770
|
-
// restore content to be able to compare it again later
|
|
9771
|
-
urlInfoCreated.kitchen.urlInfoTransformer.setContent(
|
|
9772
|
-
urlInfoCreated,
|
|
9773
|
-
String(fileContentAsBuffer),
|
|
9774
|
-
{
|
|
9775
|
-
contentEtag: fileContentEtag,
|
|
9776
|
-
},
|
|
9777
|
-
);
|
|
9956
|
+
seenSet.add(urlInfo);
|
|
9957
|
+
if (!urlInfo.url.startsWith("file:")) {
|
|
9778
9958
|
return false;
|
|
9779
9959
|
}
|
|
9780
|
-
|
|
9781
|
-
|
|
9782
|
-
|
|
9783
|
-
|
|
9784
|
-
|
|
9785
|
-
|
|
9960
|
+
if (urlInfo.content === undefined) {
|
|
9961
|
+
// urlInfo content is undefined when:
|
|
9962
|
+
// - url info content never fetched
|
|
9963
|
+
// - it is considered as modified because undelying file is watched and got saved
|
|
9964
|
+
// - it is considered as modified because underlying file content
|
|
9965
|
+
// was compared using etag and it has changed
|
|
9966
|
+
return false;
|
|
9786
9967
|
}
|
|
9787
|
-
if (
|
|
9788
|
-
//
|
|
9789
|
-
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
|
|
9793
|
-
|
|
9794
|
-
|
|
9968
|
+
if (!urlInfo.isWatched) {
|
|
9969
|
+
// file is not watched, check the filesystem
|
|
9970
|
+
let fileContentAsBuffer;
|
|
9971
|
+
try {
|
|
9972
|
+
fileContentAsBuffer = readFileSync(new URL(urlInfo.url));
|
|
9973
|
+
} catch (e) {
|
|
9974
|
+
if (e.code === "ENOENT") {
|
|
9975
|
+
urlInfo.onModified();
|
|
9976
|
+
return false;
|
|
9977
|
+
}
|
|
9978
|
+
return false;
|
|
9979
|
+
}
|
|
9980
|
+
const fileContentEtag = bufferToEtag(fileContentAsBuffer);
|
|
9981
|
+
if (fileContentEtag !== urlInfo.originalContentEtag) {
|
|
9982
|
+
urlInfo.onModified();
|
|
9983
|
+
// restore content to be able to compare it again later
|
|
9984
|
+
urlInfo.kitchen.urlInfoTransformer.setContent(
|
|
9985
|
+
urlInfo,
|
|
9986
|
+
String(fileContentAsBuffer),
|
|
9987
|
+
{
|
|
9988
|
+
contentEtag: fileContentEtag,
|
|
9989
|
+
},
|
|
9990
|
+
);
|
|
9795
9991
|
return false;
|
|
9796
9992
|
}
|
|
9797
|
-
continue;
|
|
9798
9993
|
}
|
|
9799
|
-
|
|
9800
|
-
|
|
9994
|
+
for (const implicitUrl of urlInfo.implicitUrlSet) {
|
|
9995
|
+
const implicitUrlInfo = urlInfo.graph.getUrlInfo(implicitUrl);
|
|
9996
|
+
if (!implicitUrlInfo) {
|
|
9997
|
+
continue;
|
|
9998
|
+
}
|
|
9999
|
+
if (implicitUrlInfo.content === undefined) {
|
|
10000
|
+
// happens when we explicitely load an url with a search param
|
|
10001
|
+
// - it creates an implicit url info to the url without params
|
|
10002
|
+
// - we never explicitely request the url without search param so it has no content
|
|
10003
|
+
// in that case the underlying urlInfo cannot be invalidate by the implicit
|
|
10004
|
+
// we use modifiedTimestamp to detect if the url was loaded once
|
|
10005
|
+
// or is just here to be used later
|
|
10006
|
+
if (implicitUrlInfo.modifiedTimestamp) {
|
|
10007
|
+
return false;
|
|
10008
|
+
}
|
|
10009
|
+
continue;
|
|
10010
|
+
}
|
|
10011
|
+
if (!checkValidity(implicitUrlInfo)) {
|
|
10012
|
+
return false;
|
|
10013
|
+
}
|
|
9801
10014
|
}
|
|
9802
|
-
|
|
9803
|
-
|
|
10015
|
+
return true;
|
|
10016
|
+
};
|
|
10017
|
+
const valid = checkValidity(urlInfoCreated);
|
|
10018
|
+
return valid;
|
|
9804
10019
|
};
|
|
9805
10020
|
});
|
|
9806
10021
|
kitchen.graph.urlInfoDereferencedEventEmitter.on(
|