@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.
@@ -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, defaultLookupPackageScope, defaultReadPackageJson, readCustomConditionsFromProcessArgs, readEntryStatSync, ensurePathnameTrailingSlash, compareFileUrls, urlToFilename, applyFileSystemMagicResolution, getExtensionsToTry, setUrlExtension, isSpecifierForNodeBuiltin, memoizeByFirstArgument, assertAndNormalizeDirectoryUrl, createTaskLog, formatError, readPackageAtOrNull } from "./jsenv_core_packages.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, 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
- urlInfo.getWithoutSearchParam = (searchParam, { expectedType } = {}) => {
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 newSpecifier = injectQueryParamsIntoSpecifier(reference.specifier, {
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: expectedType || reference.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
- applyNodeEsmResolution,
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
- applyNodeEsmResolution,
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
- : applyNodeEsmResolution,
5702
+ : applyNodeEsmResolutionMemo,
5653
5703
  });
5654
5704
  const resolver = webResolutionFallback
5655
5705
  ? resolveNodeEsmFallbackNullToDelegateToWebPlugin
5656
- : applyNodeEsmResolution;
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
- const dependsOnPackageJson =
5688
- type !== "relative_specifier" &&
5689
- type !== "absolute_specifier" &&
5690
- type !== "node_builtin_specifier";
5691
- if (dependsOnPackageJson) {
5692
- // this reference depends on package.json and node_modules
5693
- // to be resolved. Each file using this specifier
5694
- // must be invalidated when corresponding package.json changes
5695
- addRelationshipWithPackageJson({
5696
- reference,
5697
- packageJsonUrl: `${packageDirectoryUrl}package.json`,
5698
- field: type.startsWith("field:")
5699
- ? `#${type.slice("field:".length)}`
5700
- : "",
5701
- });
5702
- }
5703
- // without this check a file inside a project without package.json
5704
- // could be considered as a node module if there is a ancestor package.json
5705
- // but we want to version only node modules
5706
- if (url.includes("/node_modules/")) {
5707
- const packageDirectoryUrl = defaultLookupPackageScope(url);
5708
- if (
5709
- packageDirectoryUrl &&
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: "version",
5720
- hasVersioningEffect: true,
5763
+ field: type.startsWith("field:")
5764
+ ? `#${type.slice("field:".length)}`
5765
+ : "",
5721
5766
  });
5722
5767
  }
5723
- reference.version = packageVersion;
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
- { packageConditionsConfig, rootDirectoryUrl, runtimeCompat },
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
- nodeEsmResolution,
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
- url: lookupPackageDirectory(sourceDirectoryUrl),
9660
- find: lookupPackageDirectory,
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
- if (!urlInfoCreated.url.startsWith("file:")) {
9745
- return false;
9746
- }
9747
- if (urlInfoCreated.content === undefined) {
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
- const fileContentEtag = bufferToEtag(fileContentAsBuffer);
9768
- if (fileContentEtag !== urlInfoCreated.originalContentEtag) {
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
- for (const implicitUrl of urlInfoCreated.implicitUrlSet) {
9782
- const implicitUrlInfo =
9783
- urlInfoCreated.graph.getUrlInfo(implicitUrl);
9784
- if (!implicitUrlInfo) {
9785
- continue;
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 (implicitUrlInfo.content === undefined) {
9788
- // happens when we explicitely load an url with a search param
9789
- // - it creates an implicit url info to the url without params
9790
- // - we never explicitely request the url without search param so it has no content
9791
- // in that case the underlying urlInfo cannot be invalidate by the implicit
9792
- // we use modifiedTimestamp to detect if the url was loaded once
9793
- // or is just here to be used later
9794
- if (implicitUrlInfo.modifiedTimestamp) {
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
- if (!implicitUrlInfo.isValid()) {
9800
- return false;
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
- return true;
10015
+ return true;
10016
+ };
10017
+ const valid = checkValidity(urlInfoCreated);
10018
+ return valid;
9804
10019
  };
9805
10020
  });
9806
10021
  kitchen.graph.urlInfoDereferencedEventEmitter.on(