@jsenv/core 30.3.8 → 30.4.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/dist/main.js CHANGED
@@ -7093,10 +7093,30 @@ const createUrlGraph = () => {
7093
7093
  if (!parentUrlInfo) {
7094
7094
  return null;
7095
7095
  }
7096
- const firstReferenceOnThatUrl = parentUrlInfo.references.find(reference => {
7097
- return urlSpecifierEncoding.decode(reference) === specifier;
7098
- });
7099
- return firstReferenceOnThatUrl;
7096
+ const seen = [];
7097
+ const search = urlInfo => {
7098
+ const firstReferenceFound = urlInfo.references.find(reference => {
7099
+ return urlSpecifierEncoding.decode(reference) === specifier;
7100
+ });
7101
+ if (firstReferenceFound) {
7102
+ return firstReferenceFound;
7103
+ }
7104
+ for (const dependencyUrl of parentUrlInfo.dependencies) {
7105
+ if (seen.includes(dependencyUrl)) {
7106
+ continue;
7107
+ }
7108
+ seen.push(dependencyUrl);
7109
+ const dependencyUrlInfo = getUrlInfo(dependencyUrl);
7110
+ if (dependencyUrlInfo.isInline) {
7111
+ const firstRef = search(dependencyUrlInfo);
7112
+ if (firstRef) {
7113
+ return firstRef;
7114
+ }
7115
+ }
7116
+ }
7117
+ return null;
7118
+ };
7119
+ return search(parentUrlInfo);
7100
7120
  };
7101
7121
  const findDependent = (urlInfo, visitor) => {
7102
7122
  const seen = [urlInfo.url];
@@ -8852,7 +8872,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
8852
8872
  type,
8853
8873
  subtype,
8854
8874
  originalUrl,
8855
- originalContent,
8875
+ originalContent = content,
8856
8876
  sourcemap,
8857
8877
  filename,
8858
8878
  status = 200,
@@ -8875,7 +8895,15 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
8875
8895
  urlInfo.subtype = subtype || reference.expectedSubtype || "";
8876
8896
  // during build urls info are reused and load returns originalUrl/originalContent
8877
8897
  urlInfo.originalUrl = originalUrl || urlInfo.originalUrl;
8878
- urlInfo.originalContent = originalContent === undefined ? content : originalContent;
8898
+ if (originalContent !== urlInfo.originalContent) {
8899
+ urlInfo.originalContentEtag = undefined; // set by "initTransformations"
8900
+ }
8901
+
8902
+ if (content !== urlInfo.content) {
8903
+ urlInfo.contentEtag = undefined; // set by "applyFinalTransformations"
8904
+ }
8905
+
8906
+ urlInfo.originalContent = originalContent;
8879
8907
  urlInfo.content = content;
8880
8908
  urlInfo.sourcemap = sourcemap;
8881
8909
  if (data) {
@@ -20017,17 +20045,20 @@ const jsenvPluginAutoreload = ({
20017
20045
  })];
20018
20046
  };
20019
20047
 
20020
- const jsenvPluginCacheControl = () => {
20048
+ const jsenvPluginCacheControl = ({
20049
+ versionedUrls = true,
20050
+ maxAge = SECONDS_IN_30_DAYS$1
20051
+ }) => {
20021
20052
  return {
20022
20053
  name: "jsenv:cache_control",
20023
20054
  appliesDuring: "dev",
20024
20055
  augmentResponse: ({
20025
20056
  reference
20026
20057
  }) => {
20027
- if (reference.searchParams.has("v") && !reference.searchParams.has("hmr")) {
20058
+ if (versionedUrls && reference.searchParams.has("v") && !reference.searchParams.has("hmr")) {
20028
20059
  return {
20029
20060
  headers: {
20030
- "cache-control": `private,max-age=${SECONDS_IN_30_DAYS$1},immutable`
20061
+ "cache-control": `private,max-age=${maxAge},immutable`
20031
20062
  }
20032
20063
  };
20033
20064
  }
@@ -20169,11 +20200,15 @@ const getCorePlugins = ({
20169
20200
  clientFileChangeCallbackList,
20170
20201
  clientFilesPruneCallbackList,
20171
20202
  explorer,
20203
+ cacheControl,
20172
20204
  ribbon = true
20173
20205
  } = {}) => {
20174
20206
  if (explorer === true) {
20175
20207
  explorer = {};
20176
20208
  }
20209
+ if (cacheControl === true) {
20210
+ cacheControl = {};
20211
+ }
20177
20212
  if (supervisor === true) {
20178
20213
  supervisor = {};
20179
20214
  }
@@ -20214,7 +20249,7 @@ const getCorePlugins = ({
20214
20249
  ...clientAutoreload,
20215
20250
  clientFileChangeCallbackList,
20216
20251
  clientFilesPruneCallbackList
20217
- })] : []), jsenvPluginCacheControl(), ...(explorer ? [jsenvPluginExplorer({
20252
+ })] : []), ...(cacheControl ? [jsenvPluginCacheControl(cacheControl)] : []), ...(explorer ? [jsenvPluginExplorer({
20218
20253
  ...explorer,
20219
20254
  clientMainFileUrl
20220
20255
  })] : []), ...(ribbon ? [jsenvPluginRibbon({
@@ -20223,6 +20258,44 @@ const getCorePlugins = ({
20223
20258
  })] : [])];
20224
20259
  };
20225
20260
 
20261
+ const ensureUnixLineBreaks = stringOrBuffer => {
20262
+ if (typeof stringOrBuffer === "string") {
20263
+ const stringWithLinuxBreaks = stringOrBuffer.replace(/\r\n/g, "\n");
20264
+ return stringWithLinuxBreaks;
20265
+ }
20266
+ return ensureUnixLineBreaksOnBuffer(stringOrBuffer);
20267
+ };
20268
+
20269
+ // https://github.com/nodejs/help/issues/1738#issuecomment-458460503
20270
+ const ensureUnixLineBreaksOnBuffer = buffer => {
20271
+ const int32Array = new Int32Array(buffer, 0, buffer.length);
20272
+ const int32ArrayWithLineBreaksNormalized = int32Array.filter((element, index, typedArray) => {
20273
+ if (element === 0x0d) {
20274
+ if (typedArray[index + 1] === 0x0a) {
20275
+ // Windows -> Unix
20276
+ return false;
20277
+ }
20278
+ // Mac OS -> Unix
20279
+ typedArray[index] = 0x0a;
20280
+ }
20281
+ return true;
20282
+ });
20283
+ return Buffer.from(int32ArrayWithLineBreaksNormalized);
20284
+ };
20285
+
20286
+ const jsenvPluginLineBreakNormalization = () => {
20287
+ return {
20288
+ name: "jsenv:line_break_normalizer",
20289
+ appliesDuring: "build",
20290
+ transformUrlContent: urlInfo => {
20291
+ if (CONTENT_TYPE.isTextual(urlInfo.contentType)) {
20292
+ return ensureUnixLineBreaks(urlInfo.content);
20293
+ }
20294
+ return null;
20295
+ }
20296
+ };
20297
+ };
20298
+
20226
20299
  const GRAPH = {
20227
20300
  map: (graph, callback) => {
20228
20301
  const array = [];
@@ -20485,42 +20558,13 @@ const injectVersionMappingsAsImportmap = async ({
20485
20558
  });
20486
20559
  };
20487
20560
 
20488
- const ensureUnixLineBreaks = stringOrBuffer => {
20489
- if (typeof stringOrBuffer === "string") {
20490
- const stringWithLinuxBreaks = stringOrBuffer.replace(/\r\n/g, "\n");
20491
- return stringWithLinuxBreaks;
20492
- }
20493
- return ensureUnixLineBreaksOnBuffer(stringOrBuffer);
20494
- };
20495
-
20496
- // https://github.com/nodejs/help/issues/1738#issuecomment-458460503
20497
- const ensureUnixLineBreaksOnBuffer = buffer => {
20498
- const int32Array = new Int32Array(buffer, 0, buffer.length);
20499
- const int32ArrayWithLineBreaksNormalized = int32Array.filter((element, index, typedArray) => {
20500
- if (element === 0x0d) {
20501
- if (typedArray[index + 1] === 0x0a) {
20502
- // Windows -> Unix
20503
- return false;
20504
- }
20505
- // Mac OS -> Unix
20506
- typedArray[index] = 0x0a;
20507
- }
20508
- return true;
20509
- });
20510
- return Buffer.from(int32ArrayWithLineBreaksNormalized);
20511
- };
20512
-
20513
20561
  // https://github.com/rollup/rollup/blob/19e50af3099c2f627451a45a84e2fa90d20246d5/src/utils/FileEmitter.ts#L47
20514
20562
  // https://github.com/rollup/rollup/blob/5a5391971d695c808eed0c5d7d2c6ccb594fc689/src/Chunk.ts#L870
20515
20563
  const createVersionGenerator = () => {
20516
20564
  const hash = createHash("sha256");
20517
20565
  return {
20518
- augmentWithContent: ({
20519
- content,
20520
- contentType = "application/octet-stream",
20521
- lineBreakNormalization = false
20522
- }) => {
20523
- hash.update(lineBreakNormalization && CONTENT_TYPE.isTextual(contentType) ? ensureUnixLineBreaks(content) : content);
20566
+ augmentWithContent: content => {
20567
+ hash.update(content);
20524
20568
  },
20525
20569
  augment: value => {
20526
20570
  hash.update(value);
@@ -20772,7 +20816,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
20772
20816
  build: true,
20773
20817
  runtimeCompat,
20774
20818
  ...contextSharedDuringBuild,
20775
- plugins: [urlAnalysisPlugin, jsenvPluginAsJsClassic({
20819
+ plugins: [urlAnalysisPlugin, ...(lineBreakNormalization ? [jsenvPluginLineBreakNormalization()] : []), jsenvPluginAsJsClassic({
20776
20820
  jsClassicLibrary: false,
20777
20821
  jsClassicFallback: true,
20778
20822
  systemJsInjection: true
@@ -21364,11 +21408,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
21364
21408
  cleanupJsenvAttributes: true
21365
21409
  }) : urlInfo.content;
21366
21410
  const contentVersionGenerator = createVersionGenerator();
21367
- contentVersionGenerator.augmentWithContent({
21368
- content: urlContent,
21369
- contentType: urlInfo.contentType,
21370
- lineBreakNormalization
21371
- });
21411
+ contentVersionGenerator.augmentWithContent(urlContent);
21372
21412
  const contentVersion = contentVersionGenerator.generate();
21373
21413
  contentVersionMap.set(urlInfo.url, contentVersion);
21374
21414
  const versionMutations = [];
@@ -21387,7 +21427,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
21387
21427
  }
21388
21428
  if (preferWithoutVersioning(reference)) {
21389
21429
  // when versioning is dynamic no need to take into account
21390
- // happend for:
21430
+ // happens for:
21391
21431
  // - specifier mapped by window.__v__()
21392
21432
  // - specifier mapped by importmap
21393
21433
  return null;
@@ -21747,7 +21787,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
21747
21787
  return finalUrlInfo.subtype === "service_worker" && finalUrlInfo.isEntryPoint;
21748
21788
  });
21749
21789
  if (serviceWorkerEntryUrlInfos.length > 0) {
21750
- const serviceWorkerUrls = {};
21790
+ const serviceWorkerResources = {};
21751
21791
  GRAPH.forEach(finalGraph, urlInfo => {
21752
21792
  if (urlInfo.isInline || !urlInfo.shouldHandle) {
21753
21793
  return;
@@ -21760,26 +21800,27 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
21760
21800
  // so that service worker source still changes and navigator
21761
21801
  // detect there is a change
21762
21802
  const specifier = findKey(buildUrls, urlInfo.url);
21763
- serviceWorkerUrls[specifier] = {
21764
- versioned: false,
21803
+ serviceWorkerResources[specifier] = {
21765
21804
  version: versionMap.get(urlInfo.url)
21766
21805
  };
21767
21806
  return;
21768
21807
  }
21808
+ const specifier = findKey(buildUrls, urlInfo.url);
21769
21809
  const versionedUrl = versionedUrlMap.get(urlInfo.url);
21770
21810
  const versionedSpecifier = findKey(buildUrls, versionedUrl);
21771
- serviceWorkerUrls[versionedSpecifier] = {
21772
- versioned: true
21811
+ serviceWorkerResources[specifier] = {
21812
+ version: versionMap.get(urlInfo.url),
21813
+ versionedUrl: versionedSpecifier
21773
21814
  };
21774
21815
  });
21775
21816
  serviceWorkerEntryUrlInfos.forEach(serviceWorkerEntryUrlInfo => {
21776
21817
  const magicSource = createMagicSource(serviceWorkerEntryUrlInfo.content);
21777
- const urlsWithoutSelf = {
21778
- ...serviceWorkerUrls
21818
+ const serviceWorkerResourcesWithoutSwScriptItSelf = {
21819
+ ...serviceWorkerResources
21779
21820
  };
21780
21821
  const serviceWorkerSpecifier = findKey(buildUrls, serviceWorkerEntryUrlInfo.url);
21781
- delete urlsWithoutSelf[serviceWorkerSpecifier];
21782
- magicSource.prepend(`\nself.serviceWorkerUrls = ${JSON.stringify(urlsWithoutSelf, null, " ")};\n`);
21822
+ delete serviceWorkerResourcesWithoutSwScriptItSelf[serviceWorkerSpecifier];
21823
+ magicSource.prepend(`\nself.resourcesFromJsenvBuild = ${JSON.stringify(serviceWorkerResourcesWithoutSwScriptItSelf, null, " ")};\n`);
21783
21824
  const {
21784
21825
  content,
21785
21826
  sourcemap
@@ -22152,6 +22193,7 @@ const createFileService = ({
22152
22193
  clientMainFileUrl,
22153
22194
  cooldownBetweenFileEvents,
22154
22195
  explorer,
22196
+ cacheControl,
22155
22197
  ribbon,
22156
22198
  sourcemaps,
22157
22199
  sourcemapsSourcesProtocol,
@@ -22259,6 +22301,7 @@ const createFileService = ({
22259
22301
  clientFileChangeCallbackList,
22260
22302
  clientFilesPruneCallbackList,
22261
22303
  explorer,
22304
+ cacheControl,
22262
22305
  ribbon
22263
22306
  })],
22264
22307
  minification: false,
@@ -22288,18 +22331,25 @@ const createFileService = ({
22288
22331
  // when file is modified
22289
22332
  return false;
22290
22333
  }
22291
- if (!watch) {
22334
+ if (!watch && urlInfo.contentEtag) {
22335
+ // file is not watched, check the filesystem
22292
22336
  let fileContentAsBuffer;
22293
22337
  try {
22294
22338
  fileContentAsBuffer = readFileSync$1(new URL(urlInfo.url));
22295
22339
  } catch (e) {
22296
22340
  if (e.code === "ENOENT") {
22341
+ // we should consider calling urlGraph.deleteUrlInfo(urlInfo)
22342
+ urlInfo.originalContentEtag = undefined;
22343
+ urlInfo.contentEtag = undefined;
22297
22344
  return false;
22298
22345
  }
22299
22346
  return false;
22300
22347
  }
22301
22348
  const fileContentEtag = bufferToEtag$1(fileContentAsBuffer);
22302
22349
  if (fileContentEtag !== urlInfo.originalContentEtag) {
22350
+ // we should consider calling urlGraph.considerModified(urlInfo)
22351
+ urlInfo.originalContentEtag = undefined;
22352
+ urlInfo.contentEtag = undefined;
22303
22353
  return false;
22304
22354
  }
22305
22355
  }
@@ -22617,6 +22667,7 @@ const startDevServer = async ({
22617
22667
  transpilation,
22618
22668
  explorer = true,
22619
22669
  // see jsenv_plugin_explorer.js
22670
+ cacheControl = true,
22620
22671
  ribbon = true,
22621
22672
  // toolbar = false,
22622
22673
 
@@ -22755,6 +22806,7 @@ const startDevServer = async ({
22755
22806
  clientMainFileUrl,
22756
22807
  cooldownBetweenFileEvents,
22757
22808
  explorer,
22809
+ cacheControl,
22758
22810
  ribbon,
22759
22811
  sourcemaps,
22760
22812
  sourcemapsSourcesProtocol,
@@ -23389,6 +23441,17 @@ const getCoverageFromReport = async ({
23389
23441
  };
23390
23442
  const isV8Coverage = coverage => Boolean(coverage.result);
23391
23443
 
23444
+ /*
23445
+ * Export a function capable to run a file on a runtime.
23446
+ *
23447
+ * - Used internally by "executeTestPlan" part of the documented API
23448
+ * - Used internally by "execute" an advanced API not documented
23449
+ * - logs generated during file execution can be collected
23450
+ * - logs generated during file execution can be mirrored (re-logged to the console)
23451
+ * - File is given allocatedMs to complete
23452
+ * - Errors are collected
23453
+ * - File execution result is returned, it contains status/errors/namespace/consoleCalls
23454
+ */
23392
23455
  const run = async ({
23393
23456
  signal = new AbortController().signal,
23394
23457
  logger,
@@ -24239,6 +24302,7 @@ const executePlan = async (plan, {
24239
24302
  }
24240
24303
  const afterExecutionInfo = {
24241
24304
  ...beforeExecutionInfo,
24305
+ runtimeVersion: runtime.version,
24242
24306
  endMs: Date.now(),
24243
24307
  executionResult
24244
24308
  };
@@ -24631,8 +24695,8 @@ const createRuntimeFromPlaywright = ({
24631
24695
  stopSignal,
24632
24696
  keepRunning,
24633
24697
  onConsole,
24634
- executablePath,
24635
24698
  headful = keepRunning,
24699
+ playwrightLaunchOptions = {},
24636
24700
  ignoreHTTPSErrors = true
24637
24701
  }) => {
24638
24702
  const cleanupCallbackList = createCallbackListNotifiedOnce();
@@ -24648,11 +24712,14 @@ const createRuntimeFromPlaywright = ({
24648
24712
  signal,
24649
24713
  browserName,
24650
24714
  stopOnExit: true,
24651
- playwrightOptions: {
24652
- headless: !headful,
24653
- executablePath
24715
+ playwrightLaunchOptions: {
24716
+ ...playwrightLaunchOptions,
24717
+ headless: !headful
24654
24718
  }
24655
24719
  });
24720
+ if (browser._initializer.version) {
24721
+ runtime.version = browser._initializer.version;
24722
+ }
24656
24723
  const browserContext = await browser.newContext({
24657
24724
  ignoreHTTPSErrors
24658
24725
  });
@@ -24969,7 +25036,7 @@ const launchBrowserUsingPlaywright = async ({
24969
25036
  signal,
24970
25037
  browserName,
24971
25038
  stopOnExit,
24972
- playwrightOptions
25039
+ playwrightLaunchOptions
24973
25040
  }) => {
24974
25041
  const launchBrowserOperation = Abort.startOperation();
24975
25042
  launchBrowserOperation.addAbortSignal(signal);
@@ -24990,7 +25057,7 @@ const launchBrowserUsingPlaywright = async ({
24990
25057
  const browserClass = playwright[browserName];
24991
25058
  try {
24992
25059
  const browser = await browserClass.launch({
24993
- ...playwrightOptions,
25060
+ ...playwrightLaunchOptions,
24994
25061
  // let's handle them to close properly browser + remove listener
24995
25062
  // instead of relying on playwright to do so
24996
25063
  handleSIGINT: false,
@@ -25081,23 +25148,26 @@ const registerEvent = ({
25081
25148
 
25082
25149
  const chromium = createRuntimeFromPlaywright({
25083
25150
  browserName: "chromium",
25084
- browserVersion: "110.0.5481.38",
25085
- // to update, check https://github.com/microsoft/playwright/releases
25151
+ // browserVersion will be set by "browser._initializer.version"
25152
+ // see also https://github.com/microsoft/playwright/releases
25153
+ browserVersion: "unset",
25086
25154
  coveragePlaywrightAPIAvailable: true
25087
25155
  });
25088
25156
  const chromiumIsolatedTab = chromium.isolatedTab;
25089
25157
 
25090
25158
  const firefox = createRuntimeFromPlaywright({
25091
25159
  browserName: "firefox",
25092
- browserVersion: "108.0.2" // to update, check https://github.com/microsoft/playwright/releases
25160
+ // browserVersion will be set by "browser._initializer.version"
25161
+ // see also https://github.com/microsoft/playwright/releases
25162
+ browserVersion: "unset"
25093
25163
  });
25094
-
25095
25164
  const firefoxIsolatedTab = firefox.isolatedTab;
25096
25165
 
25097
25166
  const webkit = createRuntimeFromPlaywright({
25098
25167
  browserName: "webkit",
25099
- browserVersion: "16.4",
25100
- // to update, check https://github.com/microsoft/playwright/releases
25168
+ // browserVersion will be set by "browser._initializer.version"
25169
+ // see also https://github.com/microsoft/playwright/releases
25170
+ browserVersion: "unset",
25101
25171
  ignoreErrorHook: error => {
25102
25172
  // we catch error during execution but safari throw unhandled rejection
25103
25173
  // in a non-deterministic way.
@@ -26171,6 +26241,17 @@ const createBuildFilesService = ({
26171
26241
  };
26172
26242
  const SECONDS_IN_30_DAYS = 60 * 60 * 24 * 30;
26173
26243
 
26244
+ /*
26245
+ * Export a function capable to execute a file on a runtime (browser or node) and return how it goes.
26246
+ *
26247
+ * - can be useful to execute a file in a browser/node.js programmatically
26248
+ * - not documented
26249
+ * - the most importants parts:
26250
+ * - fileRelativeUrl: the file to execute inside rootDirectoryUrl
26251
+ * - runtime: an object with a "run" method.
26252
+ * The run method will start a browser/node process and execute file in it
26253
+ * - Most of the logic lives in "./run.js" used by executeTestPlan to run tests
26254
+ */
26174
26255
  const execute = async ({
26175
26256
  signal = new AbortController().signal,
26176
26257
  handleSIGINT = true,
@@ -26211,11 +26292,11 @@ const execute = async ({
26211
26292
  };
26212
26293
  if (runtime.type === "browser") {
26213
26294
  if (!devServerOrigin) {
26214
- throw new TypeError(`devServerOrigin is required when running tests on browser(s)`);
26295
+ throw new TypeError(`devServerOrigin is required to execute file on a browser`);
26215
26296
  }
26216
26297
  const devServerStarted = await pingServer(devServerOrigin);
26217
26298
  if (!devServerStarted) {
26218
- throw new Error(`dev server not started at ${devServerOrigin}. It is required to run tests`);
26299
+ throw new Error(`no server listening at ${devServerOrigin}. It is required to execute file`);
26219
26300
  }
26220
26301
  }
26221
26302
  let result = await run({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "30.3.8",
3
+ "version": "30.4.0",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -44,8 +44,8 @@
44
44
  "dev": "node --conditions=development ./scripts/dev/dev.mjs",
45
45
  "test": "node --conditions=development ./scripts/test/test.mjs",
46
46
  "test:resource_hints": "npm run test -- --only-resource-hints",
47
- "test:workspace": "npm run test --workspaces --if-present -- --workspace",
48
47
  "build": "node --conditions=development ./scripts/build/build.mjs",
48
+ "workspace:test": "npm run test --workspaces --if-present -- --workspace",
49
49
  "workspace:versions": "node ./scripts/publish/workspace_versions.mjs",
50
50
  "workspace:publish": "node ./scripts/publish/workspace_publish.mjs",
51
51
  "performances": "node --expose-gc ./scripts/performance/generate_performance_report.mjs --log --once",
@@ -107,11 +107,11 @@
107
107
  "@jsenv/plugin-globals": "./packages/jsenv-plugin-globals/",
108
108
  "@jsenv/plugin-placeholders": "./packages/jsenv-plugin-placeholders/",
109
109
  "@jsenv/performance-impact": "4.1.0",
110
- "eslint": "8.32.0",
110
+ "eslint": "8.35.0",
111
111
  "eslint-plugin-html": "7.1.0",
112
112
  "eslint-plugin-import": "2.27.5",
113
- "eslint-plugin-react": "7.32.1",
114
- "playwright": "1.30.0",
115
- "prettier": "2.8.3"
113
+ "eslint-plugin-react": "7.32.2",
114
+ "playwright": "1.31.2",
115
+ "prettier": "2.8.4"
116
116
  }
117
117
  }
@@ -67,6 +67,7 @@ import { jsenvPluginUrlAnalysis } from "../plugins/url_analysis/jsenv_plugin_url
67
67
  import { jsenvPluginInline } from "../plugins/inline/jsenv_plugin_inline.js"
68
68
  import { jsenvPluginAsJsClassic } from "../plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js"
69
69
  import { getCorePlugins } from "../plugins/plugins.js"
70
+ import { jsenvPluginLineBreakNormalization } from "./jsenv_plugin_line_break_normalization.js"
70
71
 
71
72
  import { GRAPH } from "./graph_utils.js"
72
73
  import { createBuildUrlsGenerator } from "./build_urls_generator.js"
@@ -333,6 +334,9 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
333
334
  ...contextSharedDuringBuild,
334
335
  plugins: [
335
336
  urlAnalysisPlugin,
337
+ ...(lineBreakNormalization
338
+ ? [jsenvPluginLineBreakNormalization()]
339
+ : []),
336
340
  jsenvPluginAsJsClassic({
337
341
  jsClassicLibrary: false,
338
342
  jsClassicFallback: true,
@@ -1017,11 +1021,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
1017
1021
  )
1018
1022
  : urlInfo.content
1019
1023
  const contentVersionGenerator = createVersionGenerator()
1020
- contentVersionGenerator.augmentWithContent({
1021
- content: urlContent,
1022
- contentType: urlInfo.contentType,
1023
- lineBreakNormalization,
1024
- })
1024
+ contentVersionGenerator.augmentWithContent(urlContent)
1025
1025
  const contentVersion = contentVersionGenerator.generate()
1026
1026
  contentVersionMap.set(urlInfo.url, contentVersion)
1027
1027
  const versionMutations = []
@@ -1042,7 +1042,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
1042
1042
  }
1043
1043
  if (preferWithoutVersioning(reference)) {
1044
1044
  // when versioning is dynamic no need to take into account
1045
- // happend for:
1045
+ // happens for:
1046
1046
  // - specifier mapped by window.__v__()
1047
1047
  // - specifier mapped by importmap
1048
1048
  return null
@@ -1477,7 +1477,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
1477
1477
  },
1478
1478
  )
1479
1479
  if (serviceWorkerEntryUrlInfos.length > 0) {
1480
- const serviceWorkerUrls = {}
1480
+ const serviceWorkerResources = {}
1481
1481
  GRAPH.forEach(finalGraph, (urlInfo) => {
1482
1482
  if (urlInfo.isInline || !urlInfo.shouldHandle) {
1483
1483
  return
@@ -1490,31 +1490,36 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
1490
1490
  // so that service worker source still changes and navigator
1491
1491
  // detect there is a change
1492
1492
  const specifier = findKey(buildUrls, urlInfo.url)
1493
- serviceWorkerUrls[specifier] = {
1494
- versioned: false,
1493
+ serviceWorkerResources[specifier] = {
1495
1494
  version: versionMap.get(urlInfo.url),
1496
1495
  }
1497
1496
  return
1498
1497
  }
1498
+ const specifier = findKey(buildUrls, urlInfo.url)
1499
1499
  const versionedUrl = versionedUrlMap.get(urlInfo.url)
1500
1500
  const versionedSpecifier = findKey(buildUrls, versionedUrl)
1501
- serviceWorkerUrls[versionedSpecifier] = { versioned: true }
1501
+ serviceWorkerResources[specifier] = {
1502
+ version: versionMap.get(urlInfo.url),
1503
+ versionedUrl: versionedSpecifier,
1504
+ }
1502
1505
  })
1503
1506
  serviceWorkerEntryUrlInfos.forEach((serviceWorkerEntryUrlInfo) => {
1504
1507
  const magicSource = createMagicSource(
1505
1508
  serviceWorkerEntryUrlInfo.content,
1506
1509
  )
1507
- const urlsWithoutSelf = {
1508
- ...serviceWorkerUrls,
1510
+ const serviceWorkerResourcesWithoutSwScriptItSelf = {
1511
+ ...serviceWorkerResources,
1509
1512
  }
1510
1513
  const serviceWorkerSpecifier = findKey(
1511
1514
  buildUrls,
1512
1515
  serviceWorkerEntryUrlInfo.url,
1513
1516
  )
1514
- delete urlsWithoutSelf[serviceWorkerSpecifier]
1517
+ delete serviceWorkerResourcesWithoutSwScriptItSelf[
1518
+ serviceWorkerSpecifier
1519
+ ]
1515
1520
  magicSource.prepend(
1516
- `\nself.serviceWorkerUrls = ${JSON.stringify(
1517
- urlsWithoutSelf,
1521
+ `\nself.resourcesFromJsenvBuild = ${JSON.stringify(
1522
+ serviceWorkerResourcesWithoutSwScriptItSelf,
1518
1523
  null,
1519
1524
  " ",
1520
1525
  )};\n`,
@@ -0,0 +1,16 @@
1
+ import { CONTENT_TYPE } from "@jsenv/utils/src/content_type/content_type.js"
2
+
3
+ import { ensureUnixLineBreaks } from "./line_break_unix.js"
4
+
5
+ export const jsenvPluginLineBreakNormalization = () => {
6
+ return {
7
+ name: "jsenv:line_break_normalizer",
8
+ appliesDuring: "build",
9
+ transformUrlContent: (urlInfo) => {
10
+ if (CONTENT_TYPE.isTextual(urlInfo.contentType)) {
11
+ return ensureUnixLineBreaks(urlInfo.content)
12
+ }
13
+ return null
14
+ },
15
+ }
16
+ }
@@ -0,0 +1,3 @@
1
+ # build/
2
+
3
+ Code implementing jsenv build can be found here.
@@ -1,24 +1,13 @@
1
1
  import { createHash } from "node:crypto"
2
2
 
3
- import { CONTENT_TYPE } from "@jsenv/utils/src/content_type/content_type.js"
4
- import { ensureUnixLineBreaks } from "./line_break_unix.js"
5
-
6
3
  // https://github.com/rollup/rollup/blob/19e50af3099c2f627451a45a84e2fa90d20246d5/src/utils/FileEmitter.ts#L47
7
4
  // https://github.com/rollup/rollup/blob/5a5391971d695c808eed0c5d7d2c6ccb594fc689/src/Chunk.ts#L870
8
5
  export const createVersionGenerator = () => {
9
6
  const hash = createHash("sha256")
10
7
 
11
8
  return {
12
- augmentWithContent: ({
13
- content,
14
- contentType = "application/octet-stream",
15
- lineBreakNormalization = false,
16
- }) => {
17
- hash.update(
18
- lineBreakNormalization && CONTENT_TYPE.isTextual(contentType)
19
- ? ensureUnixLineBreaks(content)
20
- : content,
21
- )
9
+ augmentWithContent: (content) => {
10
+ hash.update(content)
22
11
  },
23
12
  augment: (value) => {
24
13
  hash.update(value)