@jsenv/core 27.0.0-alpha.90 → 27.0.0-alpha.93

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/main.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { workerData, Worker, parentPort } from "node:worker_threads";
1
2
  import http from "node:http";
2
3
  import cluster from "node:cluster";
3
4
  import process$1, { memoryUsage } from "node:process";
@@ -12,7 +13,6 @@ import { performance } from "node:perf_hooks";
12
13
  import { extname, dirname, basename } from "node:path";
13
14
  import { pathToFileURL, fileURLToPath } from "node:url";
14
15
  import crypto, { createHash } from "node:crypto";
15
- import { workerData, Worker } from "node:worker_threads";
16
16
  import { parseHtmlString, stringifyHtmlAst, visitHtmlNodes, getHtmlNodeAttribute, setHtmlNodeAttributes, parseSrcSet, getHtmlNodePosition, getHtmlNodeAttributePosition, applyPostCss, postCssPluginUrlVisitor, parseJsUrls, findHtmlNode, getHtmlNodeText, removeHtmlNode, setHtmlNodeText, analyzeScriptNode, applyBabelPlugins, injectScriptNodeAsEarlyAsPossible, createHtmlNode, removeHtmlNodeText, transpileWithParcel, injectJsImport, minifyWithParcel, analyzeLinkNode } from "@jsenv/ast";
17
17
  import { createMagicSource, composeTwoSourcemaps, sourcemapConverter, SOURCEMAP, generateSourcemapFileUrl, generateSourcemapDataUrl } from "@jsenv/sourcemap";
18
18
  import { createRequire } from "node:module";
@@ -562,8 +562,8 @@ const parseMs = ms => {
562
562
  };
563
563
  };
564
564
 
565
- const byteAsFileSize = metricValue => {
566
- return formatBytes(metricValue);
565
+ const byteAsFileSize = numberOfBytes => {
566
+ return formatBytes(numberOfBytes);
567
567
  };
568
568
  const byteAsMemoryUsage = metricValue => {
569
569
  return formatBytes(metricValue, {
@@ -581,13 +581,14 @@ const formatBytes = (number, {
581
581
  const exponent = Math.min(Math.floor(Math.log10(number) / 3), BYTE_UNITS.length - 1);
582
582
  const unitNumber = number / Math.pow(1000, exponent);
583
583
  const unitName = BYTE_UNITS[exponent];
584
- const decimals = unitName === "B" ? 0 : 1;
584
+ const maxDecimals = unitNumber < 100 ? 1 : 0;
585
585
  const unitNumberRounded = setRoundedPrecision(unitNumber, {
586
- decimals
586
+ decimals: maxDecimals,
587
+ decimalsWhenSmall: 1
587
588
  });
588
589
 
589
590
  if (fixedDecimals) {
590
- return `${unitNumberRounded.toFixed(decimals)} ${unitName}`;
591
+ return `${unitNumberRounded.toFixed(maxDecimals)} ${unitName}`;
591
592
  }
592
593
 
593
594
  return `${unitNumberRounded} ${unitName}`;
@@ -7825,6 +7826,24 @@ const readFileSync = (value, {
7825
7826
  };
7826
7827
 
7827
7828
  const guardTooFastSecondCall = (callback, cooldownBetweenFileEvents = 40) => {
7829
+ let previousCallMs;
7830
+ return (...args) => {
7831
+ const nowMs = Date.now();
7832
+
7833
+ if (previousCallMs) {
7834
+ const msEllapsed = nowMs - previousCallMs;
7835
+
7836
+ if (msEllapsed < cooldownBetweenFileEvents) {
7837
+ previousCallMs = null;
7838
+ return;
7839
+ }
7840
+ }
7841
+
7842
+ previousCallMs = nowMs;
7843
+ callback(...args);
7844
+ };
7845
+ };
7846
+ const guardTooFastSecondCallPerFile = (callback, cooldownBetweenFileEvents = 40) => {
7828
7847
  const previousCallMsMap = new Map();
7829
7848
  return fileEvent => {
7830
7849
  const {
@@ -7936,15 +7955,15 @@ const registerDirectoryLifecycle = (source, {
7936
7955
 
7937
7956
  if (cooldownBetweenFileEvents) {
7938
7957
  if (added) {
7939
- added = guardTooFastSecondCall(added, cooldownBetweenFileEvents);
7958
+ added = guardTooFastSecondCallPerFile(added, cooldownBetweenFileEvents);
7940
7959
  }
7941
7960
 
7942
7961
  if (updated) {
7943
- updated = guardTooFastSecondCall(updated, cooldownBetweenFileEvents);
7962
+ updated = guardTooFastSecondCallPerFile(updated, cooldownBetweenFileEvents);
7944
7963
  }
7945
7964
 
7946
7965
  if (removed) {
7947
- removed = guardTooFastSecondCall(removed, cooldownBetweenFileEvents);
7966
+ removed = guardTooFastSecondCallPerFile(removed, cooldownBetweenFileEvents);
7948
7967
  }
7949
7968
  }
7950
7969
 
@@ -8541,12 +8560,12 @@ const createReloadableWorker = (workerFileUrl, options = {}) => {
8541
8560
  worker.once("error", error => {
8542
8561
  console.error(error);
8543
8562
  });
8544
- await new Promise(resolve => {
8545
- worker.once("online", resolve);
8546
- });
8547
8563
  worker.once("exit", () => {
8548
8564
  worker = null;
8549
8565
  });
8566
+ await new Promise(resolve => {
8567
+ worker.once("online", resolve);
8568
+ });
8550
8569
  return worker;
8551
8570
  };
8552
8571
 
@@ -8557,6 +8576,7 @@ const createReloadableWorker = (workerFileUrl, options = {}) => {
8557
8576
 
8558
8577
  return {
8559
8578
  isPrimary,
8579
+ isWorker: !isPrimary,
8560
8580
  load,
8561
8581
  reload,
8562
8582
  terminate
@@ -13262,7 +13282,7 @@ const jsenvPluginAsJsClassicHtml = ({
13262
13282
  appliesDuring: "*",
13263
13283
  transformUrlContent: {
13264
13284
  html: async (urlInfo, context) => {
13265
- const shouldTransformScriptTypeModule = !context.isSupportedOnCurrentClients("script_type_module") || !context.isSupportedOnCurrentClients("import_dynamic");
13285
+ const shouldTransformScriptTypeModule = !context.isSupportedOnCurrentClients("script_type_module") || !context.isSupportedOnCurrentClients("import_dynamic") || !context.isSupportedOnCurrentClients("import_meta");
13266
13286
  const htmlAst = parseHtmlString(urlInfo.content);
13267
13287
  const preloadAsScriptNodes = [];
13268
13288
  const modulePreloadNodes = [];
@@ -13869,14 +13889,16 @@ const featureCompats = {
13869
13889
  android: "4.4",
13870
13890
  samsung: "4"
13871
13891
  },
13892
+ // https://caniuse.com/?search=import.meta
13872
13893
  import_meta: {
13894
+ android: "9",
13873
13895
  chrome: "64",
13874
13896
  edge: "79",
13875
13897
  firefox: "62",
13876
- safari: "11.1",
13877
- opera: "51",
13878
13898
  ios: "12",
13879
- android: "9"
13899
+ opera: "51",
13900
+ safari: "11.1",
13901
+ samsung: "9.2"
13880
13902
  },
13881
13903
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#browser_compatibility
13882
13904
  import_dynamic: {
@@ -19251,14 +19273,10 @@ const startDevServer = async ({
19251
19273
  "./jsenv.config.mjs": true
19252
19274
  },
19253
19275
  devServerMainFile = getCallerPosition().url,
19254
- // force disable server autoreload when this code is executed:
19255
- // - inside a forked child process
19256
- // - debugged by vscode
19257
- // otherwise we get net:ERR_CONNECTION_REFUSED
19258
- devServerAutoreload = typeof process.send !== "function" && !process.env.VSCODE_INSPECTOR_OPTIONS,
19276
+ devServerAutoreload = true,
19259
19277
  clientFiles = {
19260
19278
  "./src/": true,
19261
- "./test/": true
19279
+ "./tests/": true
19262
19280
  },
19263
19281
  cooldownBetweenFileEvents,
19264
19282
  clientAutoreload = true,
@@ -19285,7 +19303,7 @@ const startDevServer = async ({
19285
19303
  "./src/**/*.html": true
19286
19304
  },
19287
19305
  test: {
19288
- "./test/**/*.test.html": true
19306
+ "./tests/**/*.test.html": true
19289
19307
  }
19290
19308
  },
19291
19309
  // toolbar = false,
@@ -19362,10 +19380,12 @@ const startDevServer = async ({
19362
19380
  reloadableWorker.terminate();
19363
19381
  });
19364
19382
  const worker = await reloadableWorker.load();
19365
-
19366
- if (!keepProcessAlive) {
19367
- worker.unref();
19368
- }
19383
+ const messagePromise = new Promise(resolve => {
19384
+ worker.once("message", resolve);
19385
+ });
19386
+ await messagePromise; // if (!keepProcessAlive) {
19387
+ // worker.unref()
19388
+ // }
19369
19389
 
19370
19390
  return {
19371
19391
  origin: `${protocol}://127.0.0.1:${port}`,
@@ -19481,6 +19501,11 @@ const startDevServer = async ({
19481
19501
  kitchen.pluginController.callHooks("destroy", {});
19482
19502
  };
19483
19503
  });
19504
+
19505
+ if (reloadableWorker.isWorker) {
19506
+ parentPort.postMessage(server.origin);
19507
+ }
19508
+
19484
19509
  return {
19485
19510
  origin: server.origin,
19486
19511
  stop: () => {
@@ -20189,7 +20214,9 @@ const run = async ({
20189
20214
  const runOperation = Abort.startOperation();
20190
20215
  runOperation.addAbortSignal(signal);
20191
20216
 
20192
- if (typeof allocatedMs === "number" && allocatedMs !== Infinity) {
20217
+ if ( // ideally we would rather log than the timeout is ignored
20218
+ // when keepRunning is true
20219
+ !keepRunning && typeof allocatedMs === "number" && allocatedMs !== Infinity) {
20193
20220
  const timeoutAbortSource = runOperation.timeout(allocatedMs);
20194
20221
  resultTransformer = composeTransformer$1(resultTransformer, result => {
20195
20222
  if (result.status === "errored" && Abort.isAbortError(result.error) && timeoutAbortSource.signal.aborted) {
@@ -21206,15 +21233,6 @@ const executeInParallel = async ({
21206
21233
  return executionResults;
21207
21234
  };
21208
21235
 
21209
- const defaultCoverageConfig = {
21210
- "./index.js": true,
21211
- "./main.js": true,
21212
- "./src/**/*.js": true,
21213
- "./**/*.test.*": false,
21214
- // contains .test. -> nope
21215
- "./**/test/": false // inside a test folder -> nope,
21216
-
21217
- };
21218
21236
  /**
21219
21237
  * Execute a list of files and log how it goes
21220
21238
  * @param {Object} testPlanParameters
@@ -21258,7 +21276,15 @@ const executeTestPlan = async ({
21258
21276
  gcBetweenExecutions = logMemoryHeapUsage,
21259
21277
  coverage = process.argv.includes("--cover") || process.argv.includes("--coverage"),
21260
21278
  coverageTempDirectoryRelativeUrl = "./.coverage/tmp/",
21261
- coverageConfig = defaultCoverageConfig,
21279
+ coverageConfig = {
21280
+ "./src/**/*.js": true,
21281
+ "./**/*.test.*": false,
21282
+ // contains .test. -> no
21283
+ "./**/test/": false,
21284
+ // inside a test directory -> no
21285
+ "./**/tests/": false // inside a tests directory -> no
21286
+
21287
+ },
21262
21288
  coverageIncludeMissing = true,
21263
21289
  coverageAndExecutionAllowed = false,
21264
21290
  coverageForceIstanbul = false,
@@ -21499,7 +21525,7 @@ const createRuntimeFromPlaywright = ({
21499
21525
  keepRunning,
21500
21526
  onConsole,
21501
21527
  executablePath,
21502
- headful = false,
21528
+ headful = keepRunning,
21503
21529
  ignoreHTTPSErrors = true
21504
21530
  }) => {
21505
21531
  const cleanupCallbackList = createCallbackListNotifiedOnce();
@@ -23513,17 +23539,18 @@ const build = async ({
23513
23539
  buildDirectoryUrl,
23514
23540
  entryPoints = {},
23515
23541
  baseUrl = "/",
23516
- // default runtimeCompat corresponds to dynamic import
23517
- // (meaning we can keep <script type="module">)
23542
+ // default runtimeCompat corresponds to
23543
+ // "we can keep <script type="module"> intact":
23544
+ // so script_type_module + dynamic_import + import_meta
23518
23545
  runtimeCompat = {
23519
23546
  // android: "8",
23520
- chrome: "63",
23547
+ chrome: "64",
23521
23548
  edge: "79",
23522
23549
  firefox: "67",
23523
- ios: "11.3",
23524
- opera: "50",
23550
+ ios: "12",
23551
+ opera: "51",
23525
23552
  safari: "11.3",
23526
- samsung: "8.2"
23553
+ samsung: "9.2"
23527
23554
  },
23528
23555
  plugins = [],
23529
23556
  sourcemaps = false,
@@ -24738,17 +24765,13 @@ const startBuildServer = async ({
24738
24765
  keepProcessAlive = true,
24739
24766
  rootDirectoryUrl,
24740
24767
  buildDirectoryUrl,
24741
- mainBuildFileUrl = "/index.html",
24768
+ buildIndexPath = "/index.html",
24742
24769
  buildServerFiles = {
24743
24770
  "./package.json": true,
24744
24771
  "./jsenv.config.mjs": true
24745
24772
  },
24746
24773
  buildServerMainFile = getCallerPosition().url,
24747
- // force disable server autoreload when this code is executed:
24748
- // - inside a forked child process
24749
- // - debugged by vscode
24750
- // otherwise we get net:ERR_CONNECTION_REFUSED
24751
- buildServerAutoreload = typeof process.send !== "function" && !process.env.VSCODE_INSPECTOR_OPTIONS,
24774
+ buildServerAutoreload = true,
24752
24775
  cooldownBetweenFileEvents
24753
24776
  }) => {
24754
24777
  const logger = createLogger({
@@ -24756,6 +24779,23 @@ const startBuildServer = async ({
24756
24779
  });
24757
24780
  rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl);
24758
24781
  buildDirectoryUrl = assertAndNormalizeDirectoryUrl(buildDirectoryUrl);
24782
+
24783
+ if (buildIndexPath) {
24784
+ if (typeof buildIndexPath !== "string") {
24785
+ throw new TypeError(`buildIndexPath must be a string, got ${buildIndexPath}`);
24786
+ }
24787
+
24788
+ if (buildIndexPath[0] !== "/") {
24789
+ const buildIndexUrl = new URL(buildIndexPath, buildDirectoryUrl).href;
24790
+
24791
+ if (!buildIndexUrl.startsWith(buildDirectoryUrl)) {
24792
+ throw new Error(`buildIndexPath must be relative, got ${buildIndexPath}`);
24793
+ }
24794
+
24795
+ buildIndexPath = buildIndexUrl.slice(buildDirectoryUrl.length);
24796
+ }
24797
+ }
24798
+
24759
24799
  const operation = Abort.startOperation();
24760
24800
  operation.addAbortSignal(signal);
24761
24801
 
@@ -24826,10 +24866,12 @@ const startBuildServer = async ({
24826
24866
  reloadableWorker.terminate();
24827
24867
  });
24828
24868
  const worker = await reloadableWorker.load();
24829
-
24830
- if (!keepProcessAlive) {
24831
- worker.unref();
24832
- }
24869
+ const messagePromise = new Promise(resolve => {
24870
+ worker.once("message", resolve);
24871
+ });
24872
+ await messagePromise; // if (!keepProcessAlive) {
24873
+ // worker.unref()
24874
+ // }
24833
24875
 
24834
24876
  return {
24835
24877
  origin: `${protocol}://127.0.0.1:${port}`,
@@ -24848,7 +24890,8 @@ const startBuildServer = async ({
24848
24890
  stopOnExit: false,
24849
24891
  stopOnSIGINT: false,
24850
24892
  stopOnInternalError: false,
24851
- keepProcessAlive: true,
24893
+ // the worker should be kept alive by the parent otherwise
24894
+ keepProcessAlive,
24852
24895
  logLevel: serverLogLevel,
24853
24896
  startLog: false,
24854
24897
  protocol,
@@ -24874,7 +24917,7 @@ const startBuildServer = async ({
24874
24917
  requestToResponse: composeServices({ ...services,
24875
24918
  build_files_service: createBuildFilesService({
24876
24919
  buildDirectoryUrl,
24877
- mainBuildFileUrl
24920
+ buildIndexPath
24878
24921
  })
24879
24922
  })
24880
24923
  });
@@ -24884,6 +24927,11 @@ const startBuildServer = async ({
24884
24927
  logger.info(`- ${server.origins[key]}`);
24885
24928
  });
24886
24929
  logger.info(``);
24930
+
24931
+ if (reloadableWorker.isWorker) {
24932
+ parentPort.postMessage(server.origin);
24933
+ }
24934
+
24887
24935
  return {
24888
24936
  origin: server.origin,
24889
24937
  stop: () => {
@@ -24894,14 +24942,14 @@ const startBuildServer = async ({
24894
24942
 
24895
24943
  const createBuildFilesService = ({
24896
24944
  buildDirectoryUrl,
24897
- mainBuildFileUrl
24945
+ buildIndexPath
24898
24946
  }) => {
24899
24947
  return request => {
24900
24948
  const urlIsVersioned = new URL(request.ressource, request.origin).searchParams.has("v");
24901
24949
 
24902
- if (mainBuildFileUrl && request.ressource === "/") {
24950
+ if (buildIndexPath && request.ressource === "/") {
24903
24951
  request = { ...request,
24904
- ressource: mainBuildFileUrl
24952
+ ressource: `/${buildIndexPath}`
24905
24953
  };
24906
24954
  }
24907
24955
 
@@ -25142,4 +25190,4 @@ const jsenvPluginInjectGlobals = urlAssociations => {
25142
25190
  };
25143
25191
  };
25144
25192
 
25145
- export { build, chromium, chromiumIsolatedTab, defaultCoverageConfig, execute, executeTestPlan, firefox, firefoxIsolatedTab, jsenvPluginInjectGlobals, nodeProcess, startBuildServer, startDevServer, webkit, webkitIsolatedTab };
25193
+ export { build, chromium, chromiumIsolatedTab, execute, executeTestPlan, firefox, firefoxIsolatedTab, jsenvPluginInjectGlobals, nodeProcess, startBuildServer, startDevServer, webkit, webkitIsolatedTab };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "27.0.0-alpha.90",
3
+ "version": "27.0.0-alpha.93",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -67,17 +67,17 @@
67
67
  "@financial-times/polyfill-useragent-normaliser": "2.0.1",
68
68
  "@jsenv/ast": "1.1.1",
69
69
  "@jsenv/abort": "4.2.3",
70
- "@jsenv/filesystem": "4.0.10",
70
+ "@jsenv/filesystem": "4.1.0",
71
71
  "@jsenv/importmap": "1.2.1",
72
72
  "@jsenv/integrity": "0.0.1",
73
73
  "@jsenv/node-esm-resolution": "0.1.0",
74
- "@jsenv/server": "12.7.2",
74
+ "@jsenv/server": "12.7.3",
75
75
  "@jsenv/uneval": "1.6.0",
76
76
  "@jsenv/url-meta": "7.0.0",
77
77
  "@jsenv/urls": "1.2.6",
78
78
  "@jsenv/utils": "2.0.1",
79
79
  "@jsenv/babel-plugins": "1.0.5",
80
- "@jsenv/log": "2.0.1",
80
+ "@jsenv/log": "2.1.0",
81
81
  "@jsenv/sourcemap": "1.0.1",
82
82
  "acorn-import-assertions": "1.8.0",
83
83
  "cuid": "2.1.8",
@@ -87,27 +87,27 @@
87
87
  "istanbul-lib-report": "3.0.0",
88
88
  "istanbul-reports": "3.1.4",
89
89
  "pidtree": "0.6.0",
90
- "rollup": "2.75.6",
90
+ "rollup": "2.75.7",
91
91
  "string-width": "5.1.2",
92
92
  "strip-ansi": "7.0.1",
93
93
  "terser": "5.14.1",
94
- "v8-to-istanbul": "9.0.0",
94
+ "v8-to-istanbul": "9.0.1",
95
95
  "wrap-ansi": "8.0.1"
96
96
  },
97
97
  "devDependencies": {
98
98
  "@babel/eslint-parser": "7.18.2",
99
99
  "@babel/plugin-syntax-import-assertions": "7.17.12",
100
- "@jsenv/assert": "2.5.4",
100
+ "@jsenv/assert": "2.6.0",
101
101
  "@jsenv/eslint-config": "16.0.9",
102
- "@jsenv/file-size-impact": "12.1.13",
103
- "@jsenv/https-local": "1.1.0",
104
- "@jsenv/package-workspace": "0.2.1",
105
- "@jsenv/performance-impact": "2.2.11",
106
- "eslint": "8.17.0",
102
+ "@jsenv/file-size-impact": "13.0.0",
103
+ "@jsenv/https-local": "2.1.0",
104
+ "@jsenv/package-workspace": "0.3.0",
105
+ "@jsenv/performance-impact": "3.0.0",
106
+ "eslint": "8.18.0",
107
107
  "eslint-plugin-html": "6.2.0",
108
108
  "eslint-plugin-import": "2.26.0",
109
- "eslint-plugin-react": "7.30.0",
109
+ "eslint-plugin-react": "7.30.1",
110
110
  "playwright": "1.22.2",
111
111
  "prettier": "2.7.1"
112
112
  }
113
- }
113
+ }
@@ -85,17 +85,18 @@ export const build = async ({
85
85
  entryPoints = {},
86
86
  baseUrl = "/",
87
87
 
88
- // default runtimeCompat corresponds to dynamic import
89
- // (meaning we can keep <script type="module">)
88
+ // default runtimeCompat corresponds to
89
+ // "we can keep <script type="module"> intact":
90
+ // so script_type_module + dynamic_import + import_meta
90
91
  runtimeCompat = {
91
92
  // android: "8",
92
- chrome: "63",
93
+ chrome: "64",
93
94
  edge: "79",
94
95
  firefox: "67",
95
- ios: "11.3",
96
- opera: "50",
96
+ ios: "12",
97
+ opera: "51",
97
98
  safari: "11.3",
98
- samsung: "8.2",
99
+ samsung: "9.2",
99
100
  },
100
101
  plugins = [],
101
102
  sourcemaps = false,
@@ -13,6 +13,7 @@
13
13
  * we want to be in the user shoes and we should not alter build files.
14
14
  */
15
15
 
16
+ import { parentPort } from "node:worker_threads"
16
17
  import {
17
18
  jsenvAccessControlAllowedHeaders,
18
19
  startServer,
@@ -50,23 +51,34 @@ export const startBuildServer = async ({
50
51
 
51
52
  rootDirectoryUrl,
52
53
  buildDirectoryUrl,
53
- mainBuildFileUrl = "/index.html",
54
+ buildIndexPath = "/index.html",
54
55
  buildServerFiles = {
55
56
  "./package.json": true,
56
57
  "./jsenv.config.mjs": true,
57
58
  },
58
59
  buildServerMainFile = getCallerPosition().url,
59
- // force disable server autoreload when this code is executed:
60
- // - inside a forked child process
61
- // - debugged by vscode
62
- // otherwise we get net:ERR_CONNECTION_REFUSED
63
- buildServerAutoreload = typeof process.send !== "function" &&
64
- !process.env.VSCODE_INSPECTOR_OPTIONS,
60
+ buildServerAutoreload = true,
65
61
  cooldownBetweenFileEvents,
66
62
  }) => {
67
63
  const logger = createLogger({ logLevel })
68
64
  rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl)
69
65
  buildDirectoryUrl = assertAndNormalizeDirectoryUrl(buildDirectoryUrl)
66
+ if (buildIndexPath) {
67
+ if (typeof buildIndexPath !== "string") {
68
+ throw new TypeError(
69
+ `buildIndexPath must be a string, got ${buildIndexPath}`,
70
+ )
71
+ }
72
+ if (buildIndexPath[0] !== "/") {
73
+ const buildIndexUrl = new URL(buildIndexPath, buildDirectoryUrl).href
74
+ if (!buildIndexUrl.startsWith(buildDirectoryUrl)) {
75
+ throw new Error(
76
+ `buildIndexPath must be relative, got ${buildIndexPath}`,
77
+ )
78
+ }
79
+ buildIndexPath = buildIndexUrl.slice(buildDirectoryUrl.length)
80
+ }
81
+ }
70
82
 
71
83
  const operation = Abort.startOperation()
72
84
  operation.addAbortSignal(signal)
@@ -119,9 +131,13 @@ export const startBuildServer = async ({
119
131
  reloadableWorker.terminate()
120
132
  })
121
133
  const worker = await reloadableWorker.load()
122
- if (!keepProcessAlive) {
123
- worker.unref()
124
- }
134
+ const messagePromise = new Promise((resolve) => {
135
+ worker.once("message", resolve)
136
+ })
137
+ await messagePromise
138
+ // if (!keepProcessAlive) {
139
+ // worker.unref()
140
+ // }
125
141
  return {
126
142
  origin: `${protocol}://127.0.0.1:${port}`,
127
143
  stop: () => {
@@ -139,7 +155,8 @@ export const startBuildServer = async ({
139
155
  stopOnExit: false,
140
156
  stopOnSIGINT: false,
141
157
  stopOnInternalError: false,
142
- keepProcessAlive: true,
158
+ // the worker should be kept alive by the parent otherwise
159
+ keepProcessAlive,
143
160
  logLevel: serverLogLevel,
144
161
  startLog: false,
145
162
 
@@ -168,7 +185,7 @@ export const startBuildServer = async ({
168
185
  ...services,
169
186
  build_files_service: createBuildFilesService({
170
187
  buildDirectoryUrl,
171
- mainBuildFileUrl,
188
+ buildIndexPath,
172
189
  }),
173
190
  }),
174
191
  })
@@ -178,6 +195,9 @@ export const startBuildServer = async ({
178
195
  logger.info(`- ${server.origins[key]}`)
179
196
  })
180
197
  logger.info(``)
198
+ if (reloadableWorker.isWorker) {
199
+ parentPort.postMessage(server.origin)
200
+ }
181
201
  return {
182
202
  origin: server.origin,
183
203
  stop: () => {
@@ -186,16 +206,16 @@ export const startBuildServer = async ({
186
206
  }
187
207
  }
188
208
 
189
- const createBuildFilesService = ({ buildDirectoryUrl, mainBuildFileUrl }) => {
209
+ const createBuildFilesService = ({ buildDirectoryUrl, buildIndexPath }) => {
190
210
  return (request) => {
191
211
  const urlIsVersioned = new URL(
192
212
  request.ressource,
193
213
  request.origin,
194
214
  ).searchParams.has("v")
195
- if (mainBuildFileUrl && request.ressource === "/") {
215
+ if (buildIndexPath && request.ressource === "/") {
196
216
  request = {
197
217
  ...request,
198
- ressource: mainBuildFileUrl,
218
+ ressource: `/${buildIndexPath}`,
199
219
  }
200
220
  }
201
221
  return fetchFileSystem(
@@ -1,3 +1,4 @@
1
+ import { parentPort } from "node:worker_threads"
1
2
  import { findFreePort } from "@jsenv/server"
2
3
  import {
3
4
  assertAndNormalizeDirectoryUrl,
@@ -36,15 +37,10 @@ export const startDevServer = async ({
36
37
  "./jsenv.config.mjs": true,
37
38
  },
38
39
  devServerMainFile = getCallerPosition().url,
39
- // force disable server autoreload when this code is executed:
40
- // - inside a forked child process
41
- // - debugged by vscode
42
- // otherwise we get net:ERR_CONNECTION_REFUSED
43
- devServerAutoreload = typeof process.send !== "function" &&
44
- !process.env.VSCODE_INSPECTOR_OPTIONS,
40
+ devServerAutoreload = true,
45
41
  clientFiles = {
46
42
  "./src/": true,
47
- "./test/": true,
43
+ "./tests/": true,
48
44
  },
49
45
  cooldownBetweenFileEvents,
50
46
  clientAutoreload = true,
@@ -72,7 +68,7 @@ export const startDevServer = async ({
72
68
  "./src/**/*.html": true,
73
69
  },
74
70
  test: {
75
- "./test/**/*.test.html": true,
71
+ "./tests/**/*.test.html": true,
76
72
  },
77
73
  },
78
74
  // toolbar = false,
@@ -130,9 +126,13 @@ export const startDevServer = async ({
130
126
  })
131
127
 
132
128
  const worker = await reloadableWorker.load()
133
- if (!keepProcessAlive) {
134
- worker.unref()
135
- }
129
+ const messagePromise = new Promise((resolve) => {
130
+ worker.once("message", resolve)
131
+ })
132
+ await messagePromise
133
+ // if (!keepProcessAlive) {
134
+ // worker.unref()
135
+ // }
136
136
  return {
137
137
  origin: `${protocol}://127.0.0.1:${port}`,
138
138
  stop: () => {
@@ -230,6 +230,9 @@ export const startDevServer = async ({
230
230
  kitchen.pluginController.callHooks("destroy", {})
231
231
  }
232
232
  })
233
+ if (reloadableWorker.isWorker) {
234
+ parentPort.postMessage(server.origin)
235
+ }
233
236
  return {
234
237
  origin: server.origin,
235
238
  stop: () => {
@@ -25,7 +25,13 @@ export const run = async ({
25
25
 
26
26
  const runOperation = Abort.startOperation()
27
27
  runOperation.addAbortSignal(signal)
28
- if (typeof allocatedMs === "number" && allocatedMs !== Infinity) {
28
+ if (
29
+ // ideally we would rather log than the timeout is ignored
30
+ // when keepRunning is true
31
+ !keepRunning &&
32
+ typeof allocatedMs === "number" &&
33
+ allocatedMs !== Infinity
34
+ ) {
29
35
  const timeoutAbortSource = runOperation.timeout(allocatedMs)
30
36
  resultTransformer = composeTransformer(resultTransformer, (result) => {
31
37
  if (
@@ -47,7 +47,7 @@ export const createRuntimeFromPlaywright = ({
47
47
  onConsole,
48
48
 
49
49
  executablePath,
50
- headful = false,
50
+ headful = keepRunning,
51
51
  ignoreHTTPSErrors = true,
52
52
  }) => {
53
53
  const cleanupCallbackList = createCallbackListNotifiedOnce()
@@ -30,16 +30,15 @@ export const createReloadableWorker = (workerFileUrl, options = {}) => {
30
30
  workerFilePath,
31
31
  },
32
32
  })
33
-
34
33
  worker.once("error", (error) => {
35
34
  console.error(error)
36
35
  })
37
- await new Promise((resolve) => {
38
- worker.once("online", resolve)
39
- })
40
36
  worker.once("exit", () => {
41
37
  worker = null
42
38
  })
39
+ await new Promise((resolve) => {
40
+ worker.once("online", resolve)
41
+ })
43
42
  return worker
44
43
  }
45
44
 
@@ -50,6 +49,7 @@ export const createReloadableWorker = (workerFileUrl, options = {}) => {
50
49
 
51
50
  return {
52
51
  isPrimary,
52
+ isWorker: !isPrimary,
53
53
  load,
54
54
  reload,
55
55
  terminate,
package/src/main.js CHANGED
@@ -1,10 +1,7 @@
1
1
  // dev
2
2
  export { startDevServer } from "./dev/start_dev_server.js"
3
3
  // test
4
- export {
5
- executeTestPlan,
6
- defaultCoverageConfig,
7
- } from "./test/execute_test_plan.js"
4
+ export { executeTestPlan } from "./test/execute_test_plan.js"
8
5
  export {
9
6
  chromium,
10
7
  chromiumIsolatedTab,
@@ -18,14 +18,16 @@ export const featureCompats = {
18
18
  android: "4.4",
19
19
  samsung: "4",
20
20
  },
21
+ // https://caniuse.com/?search=import.meta
21
22
  import_meta: {
23
+ android: "9",
22
24
  chrome: "64",
23
25
  edge: "79",
24
26
  firefox: "62",
25
- safari: "11.1",
26
- opera: "51",
27
27
  ios: "12",
28
- android: "9",
28
+ opera: "51",
29
+ safari: "11.1",
30
+ samsung: "9.2",
29
31
  },
30
32
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#browser_compatibility
31
33
  import_dynamic: {
@@ -27,7 +27,8 @@ export const jsenvPluginAsJsClassicHtml = ({
27
27
  html: async (urlInfo, context) => {
28
28
  const shouldTransformScriptTypeModule =
29
29
  !context.isSupportedOnCurrentClients("script_type_module") ||
30
- !context.isSupportedOnCurrentClients("import_dynamic")
30
+ !context.isSupportedOnCurrentClients("import_dynamic") ||
31
+ !context.isSupportedOnCurrentClients("import_meta")
31
32
  const htmlAst = parseHtmlString(urlInfo.content)
32
33
  const preloadAsScriptNodes = []
33
34
  const modulePreloadNodes = []
@@ -11,14 +11,6 @@ import { generateCoverageHtmlDirectory } from "./coverage/coverage_reporter_html
11
11
  import { generateCoverageTextLog } from "./coverage/coverage_reporter_text_log.js"
12
12
  import { executePlan } from "./execute_plan.js"
13
13
 
14
- export const defaultCoverageConfig = {
15
- "./index.js": true,
16
- "./main.js": true,
17
- "./src/**/*.js": true,
18
- "./**/*.test.*": false, // contains .test. -> nope
19
- "./**/test/": false, // inside a test folder -> nope,
20
- }
21
-
22
14
  /**
23
15
  * Execute a list of files and log how it goes
24
16
  * @param {Object} testPlanParameters
@@ -64,7 +56,12 @@ export const executeTestPlan = async ({
64
56
  coverage = process.argv.includes("--cover") ||
65
57
  process.argv.includes("--coverage"),
66
58
  coverageTempDirectoryRelativeUrl = "./.coverage/tmp/",
67
- coverageConfig = defaultCoverageConfig,
59
+ coverageConfig = {
60
+ "./src/**/*.js": true,
61
+ "./**/*.test.*": false, // contains .test. -> no
62
+ "./**/test/": false, // inside a test directory -> no
63
+ "./**/tests/": false, // inside a tests directory -> no
64
+ },
68
65
  coverageIncludeMissing = true,
69
66
  coverageAndExecutionAllowed = false,
70
67
  coverageForceIstanbul = false,