@jsenv/core 27.0.0-alpha.91 → 27.0.0-alpha.94

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}`,
@@ -19396,7 +19416,9 @@ const startDevServer = async ({
19396
19416
  };
19397
19417
 
19398
19418
  const stopWatchingClientFiles = registerDirectoryLifecycle(rootDirectoryUrl, {
19399
- watchPatterns: clientFiles,
19419
+ watchPatterns: { ...clientFiles,
19420
+ ".jsenv/": false
19421
+ },
19400
19422
  cooldownBetweenFileEvents,
19401
19423
  keepProcessAlive: false,
19402
19424
  recursive: true,
@@ -19481,6 +19503,11 @@ const startDevServer = async ({
19481
19503
  kitchen.pluginController.callHooks("destroy", {});
19482
19504
  };
19483
19505
  });
19506
+
19507
+ if (reloadableWorker.isWorker) {
19508
+ parentPort.postMessage(server.origin);
19509
+ }
19510
+
19484
19511
  return {
19485
19512
  origin: server.origin,
19486
19513
  stop: () => {
@@ -20189,7 +20216,9 @@ const run = async ({
20189
20216
  const runOperation = Abort.startOperation();
20190
20217
  runOperation.addAbortSignal(signal);
20191
20218
 
20192
- if (typeof allocatedMs === "number" && allocatedMs !== Infinity) {
20219
+ if ( // ideally we would rather log than the timeout is ignored
20220
+ // when keepRunning is true
20221
+ !keepRunning && typeof allocatedMs === "number" && allocatedMs !== Infinity) {
20193
20222
  const timeoutAbortSource = runOperation.timeout(allocatedMs);
20194
20223
  resultTransformer = composeTransformer$1(resultTransformer, result => {
20195
20224
  if (result.status === "errored" && Abort.isAbortError(result.error) && timeoutAbortSource.signal.aborted) {
@@ -21206,15 +21235,6 @@ const executeInParallel = async ({
21206
21235
  return executionResults;
21207
21236
  };
21208
21237
 
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
21238
  /**
21219
21239
  * Execute a list of files and log how it goes
21220
21240
  * @param {Object} testPlanParameters
@@ -21258,7 +21278,15 @@ const executeTestPlan = async ({
21258
21278
  gcBetweenExecutions = logMemoryHeapUsage,
21259
21279
  coverage = process.argv.includes("--cover") || process.argv.includes("--coverage"),
21260
21280
  coverageTempDirectoryRelativeUrl = "./.coverage/tmp/",
21261
- coverageConfig = defaultCoverageConfig,
21281
+ coverageConfig = {
21282
+ "./src/**/*.js": true,
21283
+ "./**/*.test.*": false,
21284
+ // contains .test. -> no
21285
+ "./**/test/": false,
21286
+ // inside a test directory -> no
21287
+ "./**/tests/": false // inside a tests directory -> no
21288
+
21289
+ },
21262
21290
  coverageIncludeMissing = true,
21263
21291
  coverageAndExecutionAllowed = false,
21264
21292
  coverageForceIstanbul = false,
@@ -21499,7 +21527,7 @@ const createRuntimeFromPlaywright = ({
21499
21527
  keepRunning,
21500
21528
  onConsole,
21501
21529
  executablePath,
21502
- headful = false,
21530
+ headful = keepRunning,
21503
21531
  ignoreHTTPSErrors = true
21504
21532
  }) => {
21505
21533
  const cleanupCallbackList = createCallbackListNotifiedOnce();
@@ -23513,17 +23541,18 @@ const build = async ({
23513
23541
  buildDirectoryUrl,
23514
23542
  entryPoints = {},
23515
23543
  baseUrl = "/",
23516
- // default runtimeCompat corresponds to dynamic import
23517
- // (meaning we can keep <script type="module">)
23544
+ // default runtimeCompat corresponds to
23545
+ // "we can keep <script type="module"> intact":
23546
+ // so script_type_module + dynamic_import + import_meta
23518
23547
  runtimeCompat = {
23519
23548
  // android: "8",
23520
- chrome: "63",
23549
+ chrome: "64",
23521
23550
  edge: "79",
23522
23551
  firefox: "67",
23523
- ios: "11.3",
23524
- opera: "50",
23552
+ ios: "12",
23553
+ opera: "51",
23525
23554
  safari: "11.3",
23526
- samsung: "8.2"
23555
+ samsung: "9.2"
23527
23556
  },
23528
23557
  plugins = [],
23529
23558
  sourcemaps = false,
@@ -24738,17 +24767,13 @@ const startBuildServer = async ({
24738
24767
  keepProcessAlive = true,
24739
24768
  rootDirectoryUrl,
24740
24769
  buildDirectoryUrl,
24741
- mainBuildFileUrl = "/index.html",
24770
+ buildIndexPath = "/index.html",
24742
24771
  buildServerFiles = {
24743
24772
  "./package.json": true,
24744
24773
  "./jsenv.config.mjs": true
24745
24774
  },
24746
24775
  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,
24776
+ buildServerAutoreload = true,
24752
24777
  cooldownBetweenFileEvents
24753
24778
  }) => {
24754
24779
  const logger = createLogger({
@@ -24756,6 +24781,23 @@ const startBuildServer = async ({
24756
24781
  });
24757
24782
  rootDirectoryUrl = assertAndNormalizeDirectoryUrl(rootDirectoryUrl);
24758
24783
  buildDirectoryUrl = assertAndNormalizeDirectoryUrl(buildDirectoryUrl);
24784
+
24785
+ if (buildIndexPath) {
24786
+ if (typeof buildIndexPath !== "string") {
24787
+ throw new TypeError(`buildIndexPath must be a string, got ${buildIndexPath}`);
24788
+ }
24789
+
24790
+ if (buildIndexPath[0] !== "/") {
24791
+ const buildIndexUrl = new URL(buildIndexPath, buildDirectoryUrl).href;
24792
+
24793
+ if (!buildIndexUrl.startsWith(buildDirectoryUrl)) {
24794
+ throw new Error(`buildIndexPath must be relative, got ${buildIndexPath}`);
24795
+ }
24796
+
24797
+ buildIndexPath = buildIndexUrl.slice(buildDirectoryUrl.length);
24798
+ }
24799
+ }
24800
+
24759
24801
  const operation = Abort.startOperation();
24760
24802
  operation.addAbortSignal(signal);
24761
24803
 
@@ -24791,7 +24833,8 @@ const startBuildServer = async ({
24791
24833
  const stopWatchingBuildServerFiles = registerDirectoryLifecycle(rootDirectoryUrl, {
24792
24834
  watchPatterns: {
24793
24835
  [buildServerMainFile]: true,
24794
- ...buildServerFiles
24836
+ ...buildServerFiles,
24837
+ ".jsenv/": false
24795
24838
  },
24796
24839
  cooldownBetweenFileEvents,
24797
24840
  keepProcessAlive: false,
@@ -24826,10 +24869,12 @@ const startBuildServer = async ({
24826
24869
  reloadableWorker.terminate();
24827
24870
  });
24828
24871
  const worker = await reloadableWorker.load();
24829
-
24830
- if (!keepProcessAlive) {
24831
- worker.unref();
24832
- }
24872
+ const messagePromise = new Promise(resolve => {
24873
+ worker.once("message", resolve);
24874
+ });
24875
+ await messagePromise; // if (!keepProcessAlive) {
24876
+ // worker.unref()
24877
+ // }
24833
24878
 
24834
24879
  return {
24835
24880
  origin: `${protocol}://127.0.0.1:${port}`,
@@ -24848,7 +24893,8 @@ const startBuildServer = async ({
24848
24893
  stopOnExit: false,
24849
24894
  stopOnSIGINT: false,
24850
24895
  stopOnInternalError: false,
24851
- keepProcessAlive: true,
24896
+ // the worker should be kept alive by the parent otherwise
24897
+ keepProcessAlive,
24852
24898
  logLevel: serverLogLevel,
24853
24899
  startLog: false,
24854
24900
  protocol,
@@ -24874,7 +24920,7 @@ const startBuildServer = async ({
24874
24920
  requestToResponse: composeServices({ ...services,
24875
24921
  build_files_service: createBuildFilesService({
24876
24922
  buildDirectoryUrl,
24877
- mainBuildFileUrl
24923
+ buildIndexPath
24878
24924
  })
24879
24925
  })
24880
24926
  });
@@ -24884,6 +24930,11 @@ const startBuildServer = async ({
24884
24930
  logger.info(`- ${server.origins[key]}`);
24885
24931
  });
24886
24932
  logger.info(``);
24933
+
24934
+ if (reloadableWorker.isWorker) {
24935
+ parentPort.postMessage(server.origin);
24936
+ }
24937
+
24887
24938
  return {
24888
24939
  origin: server.origin,
24889
24940
  stop: () => {
@@ -24894,14 +24945,14 @@ const startBuildServer = async ({
24894
24945
 
24895
24946
  const createBuildFilesService = ({
24896
24947
  buildDirectoryUrl,
24897
- mainBuildFileUrl
24948
+ buildIndexPath
24898
24949
  }) => {
24899
24950
  return request => {
24900
24951
  const urlIsVersioned = new URL(request.ressource, request.origin).searchParams.has("v");
24901
24952
 
24902
- if (mainBuildFileUrl && request.ressource === "/") {
24953
+ if (buildIndexPath && request.ressource === "/") {
24903
24954
  request = { ...request,
24904
- ressource: mainBuildFileUrl
24955
+ ressource: `/${buildIndexPath}`
24905
24956
  };
24906
24957
  }
24907
24958
 
@@ -25142,4 +25193,4 @@ const jsenvPluginInjectGlobals = urlAssociations => {
25142
25193
  };
25143
25194
  };
25144
25195
 
25145
- export { build, chromium, chromiumIsolatedTab, defaultCoverageConfig, execute, executeTestPlan, firefox, firefoxIsolatedTab, jsenvPluginInjectGlobals, nodeProcess, startBuildServer, startDevServer, webkit, webkitIsolatedTab };
25196
+ 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.91",
3
+ "version": "27.0.0-alpha.94",
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",
@@ -97,16 +97,16 @@
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",
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
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
  }
@@ -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)
@@ -99,6 +111,7 @@ export const startBuildServer = async ({
99
111
  watchPatterns: {
100
112
  [buildServerMainFile]: true,
101
113
  ...buildServerFiles,
114
+ ".jsenv/": false,
102
115
  },
103
116
  cooldownBetweenFileEvents,
104
117
  keepProcessAlive: false,
@@ -119,9 +132,13 @@ export const startBuildServer = async ({
119
132
  reloadableWorker.terminate()
120
133
  })
121
134
  const worker = await reloadableWorker.load()
122
- if (!keepProcessAlive) {
123
- worker.unref()
124
- }
135
+ const messagePromise = new Promise((resolve) => {
136
+ worker.once("message", resolve)
137
+ })
138
+ await messagePromise
139
+ // if (!keepProcessAlive) {
140
+ // worker.unref()
141
+ // }
125
142
  return {
126
143
  origin: `${protocol}://127.0.0.1:${port}`,
127
144
  stop: () => {
@@ -139,7 +156,8 @@ export const startBuildServer = async ({
139
156
  stopOnExit: false,
140
157
  stopOnSIGINT: false,
141
158
  stopOnInternalError: false,
142
- keepProcessAlive: true,
159
+ // the worker should be kept alive by the parent otherwise
160
+ keepProcessAlive,
143
161
  logLevel: serverLogLevel,
144
162
  startLog: false,
145
163
 
@@ -168,7 +186,7 @@ export const startBuildServer = async ({
168
186
  ...services,
169
187
  build_files_service: createBuildFilesService({
170
188
  buildDirectoryUrl,
171
- mainBuildFileUrl,
189
+ buildIndexPath,
172
190
  }),
173
191
  }),
174
192
  })
@@ -178,6 +196,9 @@ export const startBuildServer = async ({
178
196
  logger.info(`- ${server.origins[key]}`)
179
197
  })
180
198
  logger.info(``)
199
+ if (reloadableWorker.isWorker) {
200
+ parentPort.postMessage(server.origin)
201
+ }
181
202
  return {
182
203
  origin: server.origin,
183
204
  stop: () => {
@@ -186,16 +207,16 @@ export const startBuildServer = async ({
186
207
  }
187
208
  }
188
209
 
189
- const createBuildFilesService = ({ buildDirectoryUrl, mainBuildFileUrl }) => {
210
+ const createBuildFilesService = ({ buildDirectoryUrl, buildIndexPath }) => {
190
211
  return (request) => {
191
212
  const urlIsVersioned = new URL(
192
213
  request.ressource,
193
214
  request.origin,
194
215
  ).searchParams.has("v")
195
- if (mainBuildFileUrl && request.ressource === "/") {
216
+ if (buildIndexPath && request.ressource === "/") {
196
217
  request = {
197
218
  ...request,
198
- ressource: mainBuildFileUrl,
219
+ ressource: `/${buildIndexPath}`,
199
220
  }
200
221
  }
201
222
  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: () => {
@@ -155,7 +155,10 @@ export const startDevServer = async ({
155
155
  })
156
156
  }
157
157
  const stopWatchingClientFiles = registerDirectoryLifecycle(rootDirectoryUrl, {
158
- watchPatterns: clientFiles,
158
+ watchPatterns: {
159
+ ...clientFiles,
160
+ ".jsenv/": false,
161
+ },
159
162
  cooldownBetweenFileEvents,
160
163
  keepProcessAlive: false,
161
164
  recursive: true,
@@ -230,6 +233,9 @@ export const startDevServer = async ({
230
233
  kitchen.pluginController.callHooks("destroy", {})
231
234
  }
232
235
  })
236
+ if (reloadableWorker.isWorker) {
237
+ parentPort.postMessage(server.origin)
238
+ }
233
239
  return {
234
240
  origin: server.origin,
235
241
  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,