@jsenv/core 38.2.3 → 38.2.4

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
@@ -1,9 +1,43 @@
1
1
  # @jsenv/core [![npm package](https://img.shields.io/npm/v/@jsenv/core.svg?logo=npm&label=package)](https://www.npmjs.com/package/@jsenv/core)
2
2
 
3
- Jsenv is a tool to develop test and build projects using JavaScript.
4
- Jsenv is simple, easy to understand and well documented.
3
+ Jsenv is a tool to develop test and build projects using JavaScript. Jsenv is simple, easy to understand and well [documented](<https://github.com/jsenv/core/wiki/A)-directory-structure>).
5
4
 
6
- [Documentation](<https://github.com/jsenv/core/wiki/A)-Introduction>)
5
+ Jsenv cares a lot about the developper experience, especially when it comes to tests.
6
+
7
+ The pillars of jsenv are:
8
+
9
+ 1. A dev server serving source files with autoreload
10
+ 2. A build generating an optimized version of source files into a directory
11
+ 3. A build server serving build files
12
+ 4. A test runner executing test files in web browser(s)
13
+
14
+ # The best parts
15
+
16
+ ## Reduce cognitive load inside test files
17
+
18
+ When coding, we spend most of our time working on source files. At some point we switch from source files to test files. Suddenly things are different:
19
+
20
+ - code does not execute as it would in source files
21
+ - some tools are used differently in test files, some cannot be used at all
22
+ - you are forced to code in a certain way that is completely different from the one in source files
23
+
24
+ This huge gap between source files and test files creates a context switching costing a lot of cognitive energy.
25
+ Jsenv makes a special effort to [provide a solution](<https://github.com/jsenv/core/wiki/D)-Test>) where switching from source files to test files is easy.
26
+
27
+ ## Others
28
+
29
+ - A [large browser support during dev](<https://github.com/jsenv/core/wiki/B)-Dev#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.
30
+ - A [large browser support after build](<https://github.com/jsenv/core/wiki/C)-Build#211-maximal-browser-support>). Because some product still needs to support old versions of Firefox, Chrome and Safari.
31
+ - A [single set of files during build](<https://github.com/jsenv/core/wiki/C)-Build#212-same-build-for-all-browsers>). Because a single one is simpler to properly support in every aspects.
32
+ - Versioning during build is robust and <a href="https://bundlers.tooling.report/hashing/avoid-cascade/" target="_blank">avoids cascading hash changes</a><sup>↗</sup>
33
+ - Ability to [execute tests in multiple browsers](<https://github.com/jsenv/core/wiki/D)-Test#32-executing-on-more-browsers>): Chrome, Safari, Firefox
34
+ - An advanced support of top level await, allowing to use it everywhere
35
+ - An advanced support of web workers including worker type module
36
+ - Unlock js module features on a regular `<script>` when needed. If you need the behaviour of `<script>` which is to block other `<script>` tag in the page, you'll be happy to still have the power of js modules, like imports, at your disposal.
37
+
38
+ # Demos
39
+
40
+ [H) Demos](<https://github.com/jsenv/core/wiki/H)-Demos>).
7
41
 
8
42
  <!-- # Installation
9
43
 
@@ -11,5 +45,5 @@ Jsenv is simple, easy to understand and well documented.
11
45
  npm install --save-dev @jsenv/core
12
46
  ```
13
47
 
14
- _@jsenv/core_ is tested on Mac, Windows, Linux with Node.js 18.
48
+ _@jsenv/core_ is tested on Mac, Windows, Linux with Node.js 20.
15
49
  Other operating systems and Node.js versions are not tested. -->
@@ -2509,7 +2509,9 @@ const createWatcher = (sourcePath, options) => {
2509
2509
  if (e.code === "ENOENT") {
2510
2510
  return;
2511
2511
  }
2512
- console.error(`error while fixing windows eperm: ${e.stack}`);
2512
+ console.error(
2513
+ `error while trying to get rid of windows EPERM: ${e.stack}`,
2514
+ );
2513
2515
  throw error;
2514
2516
  }
2515
2517
  } else {
@@ -2543,7 +2545,7 @@ callback: ${callback}`);
2543
2545
  return { registerCleanupCallback, cleanup };
2544
2546
  };
2545
2547
 
2546
- const fsWatchSupportsRecursive = true;
2548
+ const fsWatchSupportsRecursive = process.platform !== "linux";
2547
2549
 
2548
2550
  const registerDirectoryLifecycle = (
2549
2551
  source,
@@ -2626,8 +2628,8 @@ const registerDirectoryLifecycle = (
2626
2628
  try {
2627
2629
  const relativeUrl = urlToRelativeUrl(url, source);
2628
2630
  const previousInfo = infoMap.get(relativeUrl);
2629
- const stats = statSync(new URL(url));
2630
- const type = statsToType(stats);
2631
+ const stat = statSync(new URL(url));
2632
+ const type = statsToType(stat);
2631
2633
  const patternValue = previousInfo
2632
2634
  ? previousInfo.patternValue
2633
2635
  : getWatchPatternValue({ url, type });
@@ -2636,13 +2638,15 @@ const registerDirectoryLifecycle = (
2636
2638
  url,
2637
2639
  relativeUrl,
2638
2640
  type,
2639
- atimeMs: stats.atimeMs,
2640
- mtimeMs: stats.mtimeMs,
2641
+ stat,
2641
2642
  patternValue,
2642
2643
  };
2643
2644
  } catch (e) {
2644
2645
  if (e.code === "ENOENT") {
2645
- return null;
2646
+ return {
2647
+ type: null,
2648
+ stat: null,
2649
+ };
2646
2650
  }
2647
2651
  throw e;
2648
2652
  }
@@ -2715,7 +2719,7 @@ const registerDirectoryLifecycle = (
2715
2719
  const handleChange = (relativeUrl) => {
2716
2720
  const entryUrl = new URL(relativeUrl, sourceUrl).href;
2717
2721
  const entryInfo = readEntryInfo(entryUrl);
2718
- if (!entryInfo) {
2722
+ if (entryInfo.type === null) {
2719
2723
  const previousEntryInfo = infoMap.get(relativeUrl);
2720
2724
  if (!previousEntryInfo) {
2721
2725
  // on MacOS it's possible to receive a "rename" event for
@@ -2775,17 +2779,36 @@ const registerDirectoryLifecycle = (
2775
2779
  readdirSync(new URL(directoryUrl)).forEach((entryName) => {
2776
2780
  const childEntryUrl = new URL(entryName, directoryUrl).href;
2777
2781
  const childEntryInfo = readEntryInfo(childEntryUrl);
2778
- if (childEntryInfo && childEntryInfo.patternValue) {
2782
+ if (childEntryInfo.type !== null && childEntryInfo.patternValue) {
2779
2783
  handleEntryFound(childEntryInfo, { notify });
2780
2784
  }
2781
2785
  });
2786
+ // we must watch manually every directory we find
2787
+ if (!fsWatchSupportsRecursive) {
2788
+ const watcher = createWatcher(urlToFileSystemPath(entryInfo.url), {
2789
+ persistent: keepProcessAlive,
2790
+ });
2791
+ tracker.registerCleanupCallback(() => {
2792
+ watcher.close();
2793
+ });
2794
+ watcher.on("change", (eventType, filename) => {
2795
+ handleDirectoryEvent({
2796
+ directoryRelativeUrl: entryInfo.relativeUrl,
2797
+ filename: filename
2798
+ ? // replace back slashes with slashes
2799
+ filename.replace(/\\/g, "/")
2800
+ : "",
2801
+ eventType,
2802
+ });
2803
+ });
2804
+ }
2782
2805
  }
2783
2806
  if (added && entryInfo.patternValue && notify) {
2784
2807
  added({
2785
2808
  relativeUrl: entryInfo.relativeUrl,
2786
2809
  type: entryInfo.type,
2787
2810
  patternValue: entryInfo.patternValue,
2788
- mtime: entryInfo.mtimeMs,
2811
+ mtime: entryInfo.stat.mtimeMs,
2789
2812
  });
2790
2813
  }
2791
2814
  };
@@ -2796,19 +2819,19 @@ const registerDirectoryLifecycle = (
2796
2819
  relativeUrl: entryInfo.relativeUrl,
2797
2820
  type: entryInfo.type,
2798
2821
  patternValue: entryInfo.patternValue,
2799
- mtime: entryInfo.mtimeMs,
2822
+ mtime: entryInfo.stat.mtimeMs,
2800
2823
  });
2801
2824
  }
2802
2825
  };
2803
2826
  const handleEntryUpdated = (entryInfo) => {
2804
2827
  infoMap.set(entryInfo.relativeUrl, entryInfo);
2805
- if (updated && entryInfo.patternValue) {
2828
+ if (updated && entryInfo.patternValue && shouldCallUpdated(entryInfo)) {
2806
2829
  updated({
2807
2830
  relativeUrl: entryInfo.relativeUrl,
2808
2831
  type: entryInfo.type,
2809
2832
  patternValue: entryInfo.patternValue,
2810
- mtime: entryInfo.mtimeMs,
2811
- previousMtime: entryInfo.previousInfo.mtimeMs,
2833
+ mtime: entryInfo.stat.mtimeMs,
2834
+ previousMtime: entryInfo.previousInfo.stat.mtimeMs,
2812
2835
  });
2813
2836
  }
2814
2837
  };
@@ -2816,7 +2839,7 @@ const registerDirectoryLifecycle = (
2816
2839
  readdirSync(new URL(sourceUrl)).forEach((entry) => {
2817
2840
  const entryUrl = new URL(entry, sourceUrl).href;
2818
2841
  const entryInfo = readEntryInfo(entryUrl);
2819
- if (entryInfo && entryInfo.patternValue) {
2842
+ if (entryInfo.type !== null && entryInfo.patternValue) {
2820
2843
  handleEntryFound(entryInfo, {
2821
2844
  notify: notifyExistent,
2822
2845
  });
@@ -2850,6 +2873,20 @@ ${relativeUrls.join("\n")}`,
2850
2873
  return tracker.cleanup;
2851
2874
  };
2852
2875
 
2876
+ const shouldCallUpdated = (entryInfo) => {
2877
+ const { stat, previousInfo } = entryInfo;
2878
+ if (!stat.atimeMs) {
2879
+ return true;
2880
+ }
2881
+ if (stat.atimeMs < stat.mtimeMs) {
2882
+ return true;
2883
+ }
2884
+ if (stat.mtimeMs > previousInfo.stat.mtimeMs) {
2885
+ return true;
2886
+ }
2887
+ return false;
2888
+ };
2889
+
2853
2890
  const undefinedOrFunction = (value) => {
2854
2891
  return typeof value === "undefined" || typeof value === "function";
2855
2892
  };
@@ -13214,6 +13251,7 @@ const createUrlInfoTransformer = ({
13214
13251
  generatedUrlObject.searchParams.delete("as_json_module");
13215
13252
  generatedUrlObject.searchParams.delete("as_text_module");
13216
13253
  generatedUrlObject.searchParams.delete("dynamic_import");
13254
+ generatedUrlObject.searchParams.delete("cjs_as_js_module");
13217
13255
  const urlForSourcemap = generatedUrlObject.href;
13218
13256
  urlInfo.sourcemapGeneratedUrl = generateSourcemapFileUrl(urlForSourcemap);
13219
13257
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "38.2.3",
3
+ "version": "38.2.4",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -62,7 +62,7 @@
62
62
  "@financial-times/polyfill-useragent-normaliser": "1.10.2",
63
63
  "@jsenv/abort": "4.2.4",
64
64
  "@jsenv/ast": "5.1.4",
65
- "@jsenv/filesystem": "4.3.0",
65
+ "@jsenv/filesystem": "4.3.1",
66
66
  "@jsenv/importmap": "1.2.1",
67
67
  "@jsenv/integrity": "0.0.1",
68
68
  "@jsenv/log": "3.4.0",
@@ -149,6 +149,7 @@ export const createUrlInfoTransformer = ({
149
149
  generatedUrlObject.searchParams.delete("as_json_module");
150
150
  generatedUrlObject.searchParams.delete("as_text_module");
151
151
  generatedUrlObject.searchParams.delete("dynamic_import");
152
+ generatedUrlObject.searchParams.delete("cjs_as_js_module");
152
153
  const urlForSourcemap = generatedUrlObject.href;
153
154
  urlInfo.sourcemapGeneratedUrl = generateSourcemapFileUrl(urlForSourcemap);
154
155