@jsenv/core 39.13.2 → 39.14.0

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 CHANGED
@@ -4,32 +4,31 @@
4
4
 
5
5
  Jsenv is a suite of tools that can be used in projects involving JavaScript.
6
6
 
7
- `@jsenv/core` goal is too provide the following tools:
7
+ The goal of `@jsenv/core` is to provide the following tools:
8
8
 
9
- 1. **dev server**; a server for source files
10
- 2. **build**; generate an optimized version of source files into a directory
11
- 3. **build server**; a server for build files
12
- 4. **test runner**; execute all test files at once
9
+ 1. **dev server**; A server that serves source files, facilitating development with live reloading.
10
+ 2. **build**; Optimizes source files into a specified directory for production.
11
+ 3. **build server**; Serves the built files, allowing for testing and verifying the production build.
12
+ 4. **test runner**; Runs test files concurrently, ensuring code reliability.
13
13
 
14
- It favors standards and simplicity.
15
- As a result it can be enjoyed by people without much experience in tooling or seeking for simple tools without hidden complexities.
14
+ Jsenv prioritizes standards and simplicity, making it ideal for both beginners and those who need straightforward tools without unnecessary complexities.
16
15
 
17
- If you want to try jsenv on your machine, use [@jsenv/cli](./packages/related/cli/#jsenvcli).
16
+ To try jsenv on your machine, use [@jsenv/cli](./packages/related/cli/#jsenvcli).
18
17
 
19
- Link to [documentation](./docs/users/users.md)
18
+ For additional details, consult the [documentation](./docs/users/users.md)
20
19
 
21
20
  # The best parts
22
21
 
23
- - Test files are [executed like standard files](./docs/users/d_test/d_test.md#14-executing-a-single-test)
24
- - [Isolated environment](./docs/users/d_test/d_test.md#33-isolated-environment) for each test file
25
- - Execute [tests in multiple browsers](./docs/users/d_test/d_test.md#32-execute-on-more-browsers>): Chrome, Safari, Firefox
26
- - [Large browser support during dev](./docs/users/b_dev/b_dev.md#21-browser-support>). Because some people might be happy to use an other browser than the latest chrome during dev. Moreover it is useful to reproduce bug specific to certain browsers.
27
- - [Large browser support after build](./docs/users/c_build/c_build.md#211-maximal-browser-support). Because some product still needs to support old versions of Firefox, Chrome and Safari.
28
- - [Single set of files after build](./docs/users/c_build/c_build.md#212-same-build-for-all-browsers). Because a single one is simpler to properly support in every aspects.
29
- - Versioning during build is robust and <a href="https://bundlers.tooling.report/hashing/avoid-cascade/" target="_blank">avoids cascading hash changes</a><sup>↗</sup>
30
- - Advanced support of top level await, allowing to use it everywhere
31
- - Advanced support of web workers including worker type module
32
- - Unlock [js module features on a classic `<script>`](./docs/users/g_plugins/g_plugins.md#22-asjsclassic>).
22
+ - **Test files are executed like standard files**.
23
+ - **Isolated environment for each test file**: Ensures tests run independently, preventing side effects.
24
+ - Execute tests in multiple browsers: Supports Chrome, Safari, and Firefox.
25
+ - Extensive browser support during dev: Allows the use of various browsers beyond the latest Chrome, which is useful for reproducing browser-specific bugs.
26
+ - **Large browser support after build**: Ensures compatibility with older versions of Firefox, Chrome, and Safari.
27
+ - Single set of files after build: Simplifies support and deployement with a single set of files.
28
+ - **Robust versioning during build**: Avoids <a href="https://bundlers.tooling.report/hashing/avoid-cascade/" target="_blank">cascading hash changes</a><sup>↗</sup>.
29
+ - **Advanced support of top level await**.
30
+ - **Advanced support of web workers**.
31
+ - **Load js module with classic script**: See the [asJsClassic plugin](./docs/users/g_plugins/g_plugins.md#22-asjsclassic>).
33
32
 
34
33
  <!--
35
34
  The following commands can be used to skip the prompt
@@ -3226,6 +3226,27 @@ const readDirectory = async (url, { emfileMaxWait = 1000 } = {}) => {
3226
3226
  return attempt();
3227
3227
  };
3228
3228
 
3229
+ const generateWindowsEPERMErrorMessage = (
3230
+ error,
3231
+ { operation, path },
3232
+ ) => {
3233
+ const pathLengthIsExceedingUsualLimit = String(path).length >= 256;
3234
+ let message = "";
3235
+
3236
+ if (operation) {
3237
+ message += `error while trying to fix windows EPERM after ${operation} on ${path}`;
3238
+ }
3239
+
3240
+ if (pathLengthIsExceedingUsualLimit) {
3241
+ message += "\n";
3242
+ message += `Maybe because path length is exceeding the usual limit of 256 characters of windows OS?`;
3243
+ message += "\n";
3244
+ }
3245
+ message += "\n";
3246
+ message += error.stack;
3247
+ return message;
3248
+ };
3249
+
3229
3250
  const writeEntryPermissions = async (source, permissions) => {
3230
3251
  const sourceUrl = assertAndNormalizeFileUrl(source);
3231
3252
 
@@ -3296,7 +3317,10 @@ const readEntryStat = async (
3296
3317
  return stats;
3297
3318
  } catch (e) {
3298
3319
  console.error(
3299
- `error while trying to fix windows EPERM after stats on ${sourcePath}: ${e.stack}`,
3320
+ generateWindowsEPERMErrorMessage(e, {
3321
+ operation: "stats",
3322
+ path: sourcePath,
3323
+ }),
3300
3324
  );
3301
3325
  throw error;
3302
3326
  }
@@ -3398,7 +3422,10 @@ const readEntryStatSync = (
3398
3422
  return stats;
3399
3423
  } catch (e) {
3400
3424
  console.error(
3401
- `error while trying to fix windows EPERM after stats on ${sourcePath}: ${e.stack}`,
3425
+ generateWindowsEPERMErrorMessage(e, {
3426
+ operation: "stats",
3427
+ path: sourcePath,
3428
+ }),
3402
3429
  );
3403
3430
  throw error;
3404
3431
  }
@@ -3816,7 +3843,10 @@ const removeDirectorySync$1 = (
3816
3843
  return;
3817
3844
  }
3818
3845
  console.error(
3819
- `error while trying to fix windows EPERM after readir on ${directoryPath}: ${openOrCloseError.stack}`,
3846
+ generateWindowsEPERMErrorMessage(openOrCloseError, {
3847
+ path: directoryPath,
3848
+ operation: "readir",
3849
+ }),
3820
3850
  );
3821
3851
  throw error;
3822
3852
  }
@@ -4152,7 +4182,6 @@ const removeDirectory = async (
4152
4182
  console.error(
4153
4183
  `trying to fix windows EPERM after readir on ${directoryPath}`,
4154
4184
  );
4155
-
4156
4185
  let openOrCloseError;
4157
4186
  try {
4158
4187
  const fd = openSync(directoryPath);
@@ -4166,7 +4195,10 @@ const removeDirectory = async (
4166
4195
  return;
4167
4196
  }
4168
4197
  console.error(
4169
- `error while trying to fix windows EPERM after readir on ${directoryPath}: ${openOrCloseError.stack}`,
4198
+ generateWindowsEPERMErrorMessage(openOrCloseError, {
4199
+ operation: "readdir",
4200
+ path: directoryPath,
4201
+ }),
4170
4202
  );
4171
4203
  throw error;
4172
4204
  }
@@ -4305,7 +4337,10 @@ const createWatcher = (sourcePath, options) => {
4305
4337
  return;
4306
4338
  }
4307
4339
  console.error(
4308
- `error while trying to get rid of windows EPERM: ${e.stack}`,
4340
+ generateWindowsEPERMErrorMessage(error, {
4341
+ operation: "watch",
4342
+ path: sourcePath,
4343
+ }),
4309
4344
  );
4310
4345
  throw error;
4311
4346
  }
@@ -11325,7 +11360,7 @@ const JS_QUOTE_REPLACEMENTS = {
11325
11360
 
11326
11361
  const jsenvPluginImportAttributes = ({
11327
11362
  json = "auto",
11328
- css = "auto",
11363
+ css = true,
11329
11364
  text = "auto",
11330
11365
  }) => {
11331
11366
  const transpilations = { json, css, text };
@@ -11335,7 +11370,11 @@ const jsenvPluginImportAttributes = ({
11335
11370
  reference.filenameHint = `${urlToFilename$1(reference.url)}.js`;
11336
11371
  }
11337
11372
  };
11338
- const turnIntoJsModuleProxy = (reference, type) => {
11373
+ const turnIntoJsModuleProxy = (
11374
+ reference,
11375
+ type,
11376
+ { injectSearchParamForSideEffectImports },
11377
+ ) => {
11339
11378
  reference.mutation = (magicSource) => {
11340
11379
  if (reference.subtype === "import_dynamic") {
11341
11380
  const { importTypeAttributeNode } = reference.astInfo;
@@ -11362,12 +11401,19 @@ const jsenvPluginImportAttributes = ({
11362
11401
  };
11363
11402
  const newUrl = injectQueryParams(reference.url, {
11364
11403
  [`as_${type}_module`]: "",
11404
+ ...(injectSearchParamForSideEffectImports && reference.isSideEffectImport
11405
+ ? { side_effect: "" }
11406
+ : {}),
11365
11407
  });
11366
11408
  markAsJsModuleProxy(reference);
11367
11409
  return newUrl;
11368
11410
  };
11369
11411
 
11370
- const createImportTypePlugin = ({ type, createUrlContent }) => {
11412
+ const createImportTypePlugin = ({
11413
+ type,
11414
+ createUrlContent,
11415
+ injectSearchParamForSideEffectImports,
11416
+ }) => {
11371
11417
  return {
11372
11418
  name: `jsenv:import_type_${type}`,
11373
11419
  appliesDuring: "*",
@@ -11405,7 +11451,9 @@ const jsenvPluginImportAttributes = ({
11405
11451
  return null;
11406
11452
  }
11407
11453
  if (reference.importAttributes.type === type) {
11408
- return turnIntoJsModuleProxy(reference, type);
11454
+ return turnIntoJsModuleProxy(reference, type, {
11455
+ injectSearchParamForSideEffectImports,
11456
+ });
11409
11457
  }
11410
11458
  return null;
11411
11459
  },
@@ -11454,6 +11502,7 @@ const jsenvPluginImportAttributes = ({
11454
11502
 
11455
11503
  const asCssModule = createImportTypePlugin({
11456
11504
  type: "css",
11505
+ injectSearchParamForSideEffectImports: true,
11457
11506
  createUrlContent: (cssUrlInfo) => {
11458
11507
  const cssText = JS_QUOTES.escapeSpecialChars(cssUrlInfo.content, {
11459
11508
  // If template string is choosen and runtime do not support template literals
@@ -11471,15 +11520,38 @@ const jsenvPluginImportAttributes = ({
11471
11520
  } else {
11472
11521
  inlineContentCall = `new __InlineContent__(${cssText}, { type: "text/css" })`;
11473
11522
  }
11474
- return {
11475
- content: `
11476
- import ${JSON.stringify(cssUrlInfo.context.inlineContentClientFileUrl)};
11523
+
11524
+ let autoInject = cssUrlInfo.searchParams.has("side_effect");
11525
+ let cssModuleAutoInjectCode = ``;
11526
+ if (autoInject) {
11527
+ if (cssUrlInfo.context.dev) {
11528
+ cssModuleAutoInjectCode = `
11529
+ document.adoptedStyleSheets = [...document.adoptedStyleSheets, stylesheet];
11530
+
11531
+ if (import.meta.hot) {
11532
+ import.meta.hot.dispose(() => {
11533
+ document.adoptedStyleSheets = document.adoptedStyleSheets.filter(
11534
+ (s) => s !== stylesheet,
11535
+ );
11536
+ });
11537
+ };
11538
+ `;
11539
+ } else {
11540
+ cssModuleAutoInjectCode = `
11541
+ document.adoptedStyleSheets = [...document.adoptedStyleSheets, stylesheet];
11542
+ `;
11543
+ }
11544
+ }
11545
+ let cssModuleContent = `import ${JSON.stringify(cssUrlInfo.context.inlineContentClientFileUrl)};
11477
11546
 
11478
11547
  const inlineContent = ${inlineContentCall};
11479
11548
  const stylesheet = new CSSStyleSheet();
11480
11549
  stylesheet.replaceSync(inlineContent.text);
11550
+ ${cssModuleAutoInjectCode}
11551
+ export default stylesheet;`;
11481
11552
 
11482
- export default stylesheet;`,
11553
+ return {
11554
+ content: cssModuleContent,
11483
11555
  contentType: "text/javascript",
11484
11556
  type: "js_module",
11485
11557
  originalUrl: cssUrlInfo.originalUrl,
@@ -13194,6 +13266,7 @@ const createReference = ({
13194
13266
  urlInfo = null,
13195
13267
  escape = null,
13196
13268
  importAttributes,
13269
+ isSideEffectImport = false,
13197
13270
  astInfo = {},
13198
13271
  mutation,
13199
13272
  }) => {
@@ -13257,6 +13330,7 @@ const createReference = ({
13257
13330
  // used mostly by worker and import assertions
13258
13331
  astInfo,
13259
13332
  importAttributes,
13333
+ isSideEffectImport,
13260
13334
  mutation,
13261
13335
  };
13262
13336
 
@@ -17675,6 +17749,7 @@ const parseAndTransformJsReferences = async (
17675
17749
  "document.currentScript.src": urlInfo.url,
17676
17750
  }[externalReferenceInfo.baseUrlType],
17677
17751
  importAttributes: externalReferenceInfo.importAttributes,
17752
+ isSideEffectImport: externalReferenceInfo.isSideEffectImport,
17678
17753
  astInfo: externalReferenceInfo.astInfo,
17679
17754
  });
17680
17755
  parallelActions.push(async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "39.13.2",
3
+ "version": "39.14.0",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -69,17 +69,17 @@
69
69
  "dependencies": {
70
70
  "@financial-times/polyfill-useragent-normaliser": "1.10.2",
71
71
  "@jsenv/abort": "4.3.0",
72
- "@jsenv/ast": "6.5.0",
73
- "@jsenv/filesystem": "4.13.3",
72
+ "@jsenv/ast": "6.5.1",
73
+ "@jsenv/filesystem": "4.13.4",
74
74
  "@jsenv/humanize": "1.2.8",
75
75
  "@jsenv/importmap": "1.2.1",
76
76
  "@jsenv/integrity": "0.0.2",
77
- "@jsenv/js-module-fallback": "1.3.57",
77
+ "@jsenv/js-module-fallback": "1.3.58",
78
78
  "@jsenv/node-esm-resolution": "1.0.6",
79
79
  "@jsenv/plugin-bundling": "2.7.25",
80
80
  "@jsenv/plugin-minification": "1.5.13",
81
- "@jsenv/plugin-supervisor": "1.6.4",
82
- "@jsenv/plugin-transpilation": "1.4.93",
81
+ "@jsenv/plugin-supervisor": "1.6.5",
82
+ "@jsenv/plugin-transpilation": "1.4.94",
83
83
  "@jsenv/runtime-compat": "1.3.1",
84
84
  "@jsenv/server": "15.5.1",
85
85
  "@jsenv/sourcemap": "1.2.30",
@@ -304,6 +304,7 @@ const createReference = ({
304
304
  urlInfo = null,
305
305
  escape = null,
306
306
  importAttributes,
307
+ isSideEffectImport = false,
307
308
  astInfo = {},
308
309
  mutation,
309
310
  }) => {
@@ -367,6 +368,7 @@ const createReference = ({
367
368
  // used mostly by worker and import assertions
368
369
  astInfo,
369
370
  importAttributes,
371
+ isSideEffectImport,
370
372
  mutation,
371
373
  };
372
374
 
@@ -117,6 +117,7 @@ const parseAndTransformJsReferences = async (
117
117
  "document.currentScript.src": urlInfo.url,
118
118
  }[externalReferenceInfo.baseUrlType],
119
119
  importAttributes: externalReferenceInfo.importAttributes,
120
+ isSideEffectImport: externalReferenceInfo.isSideEffectImport,
120
121
  astInfo: externalReferenceInfo.astInfo,
121
122
  });
122
123
  parallelActions.push(async () => {