@jsenv/plugin-bundling 2.7.25 → 2.8.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/plugin-bundling",
3
- "version": "2.7.25",
3
+ "version": "2.8.1",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,13 +20,14 @@
20
20
  "files": [
21
21
  "/src/"
22
22
  ],
23
+ "sideEffects": false,
23
24
  "dependencies": {
24
- "@jsenv/humanize": "1.2.8",
25
- "@jsenv/url-meta": "8.5.3",
26
- "@jsenv/urls": "2.6.0",
27
- "@jsenv/sourcemap": "1.2.30",
28
- "lightningcss": "1.29.1",
29
- "rollup": "4.31.0"
25
+ "@jsenv/humanize": "1.3.1",
26
+ "@jsenv/url-meta": "8.5.4",
27
+ "@jsenv/urls": "2.6.2",
28
+ "@jsenv/sourcemap": "1.3.1",
29
+ "lightningcss": "1.29.2",
30
+ "rollup": "4.35.0"
30
31
  },
31
32
  "peerDependencies": {
32
33
  "@jsenv/core": "*"
@@ -1,8 +1,10 @@
1
+ import { lookupPackageDirectory } from "@jsenv/filesystem";
1
2
  import { createDetailedMessage } from "@jsenv/humanize";
3
+ import { isSpecifierForNodeBuiltin } from "@jsenv/node-esm-resolution/src/node_builtin_specifiers.js";
2
4
  import { sourcemapConverter } from "@jsenv/sourcemap";
3
5
  import { URL_META } from "@jsenv/url-meta";
4
- import { isFileSystemPath } from "@jsenv/urls";
5
-
6
+ import { fileSystemPathToUrl, isFileSystemPath } from "@jsenv/urls";
7
+ import { readFileSync } from "node:fs";
6
8
  import { fileUrlConverter } from "../file_url_converter.js";
7
9
 
8
10
  export const bundleJsModules = async (
@@ -35,15 +37,59 @@ export const bundleJsModules = async (
35
37
  }
36
38
 
37
39
  let manualChunks;
38
- if (Object.keys(chunks).length) {
40
+ if (chunks) {
41
+ if (chunks.vendors) {
42
+ chunks.vendors = {
43
+ "file:///**/node_modules/": true,
44
+ ...chunks.vendors,
45
+ };
46
+ } else {
47
+ chunks.vendors = {
48
+ "file:///**/node_modules/": true,
49
+ };
50
+ }
51
+ const packageDirectoryUrl = lookupPackageDirectory(rootDirectoryUrl);
52
+ if (packageDirectoryUrl) {
53
+ try {
54
+ const packageFileContent = readFileSync(
55
+ new URL("package.json", packageDirectoryUrl),
56
+ "utf8",
57
+ );
58
+ const packageJSON = JSON.parse(packageFileContent);
59
+ const workspaces = packageJSON.workspaces;
60
+ if (workspaces) {
61
+ const workspacePatterns = {};
62
+ for (const workspace of workspaces) {
63
+ const workspacePattern = new URL(
64
+ workspace.endsWith("/*") ? workspace.slice(0, -1) : workspace,
65
+ packageDirectoryUrl,
66
+ ).href;
67
+ workspacePatterns[workspacePattern] = true;
68
+ }
69
+ if (chunks.workspaces) {
70
+ chunks.workspaces = {
71
+ ...workspacePatterns,
72
+ ...chunks.workspaces,
73
+ };
74
+ } else {
75
+ chunks.workspaces = workspacePatterns;
76
+ }
77
+ }
78
+ } catch {}
79
+ }
80
+
39
81
  const associations = URL_META.resolveAssociations(chunks, rootDirectoryUrl);
40
- manualChunks = (id) => {
82
+ manualChunks = (id, manualChunksApi) => {
41
83
  if (rollupOutput.manualChunks) {
42
- const manualChunkName = rollupOutput.manualChunks(id);
84
+ const manualChunkName = rollupOutput.manualChunks(id, manualChunksApi);
43
85
  if (manualChunkName) {
44
86
  return manualChunkName;
45
87
  }
46
88
  }
89
+ const moduleInfo = manualChunksApi.getModuleInfo(id);
90
+ if (moduleInfo.isEntry || moduleInfo.dynamicImporters.length) {
91
+ return null;
92
+ }
47
93
  const url = fileUrlConverter.asFileUrl(id);
48
94
  const urlObject = new URL(url);
49
95
  urlObject.search = "";
@@ -52,8 +98,12 @@ export const bundleJsModules = async (
52
98
  url: urlWithoutSearch,
53
99
  associations,
54
100
  });
55
- const chunkName = Object.keys(meta).find((key) => meta[key]);
56
- return chunkName || null;
101
+ for (const chunkNameCandidate of Object.keys(meta)) {
102
+ if (meta[chunkNameCandidate]) {
103
+ return chunkNameCandidate;
104
+ }
105
+ }
106
+ return undefined;
57
107
  };
58
108
  }
59
109
 
@@ -91,6 +141,18 @@ export const bundleJsModules = async (
91
141
  // ideally we should disable only for jsenv files
92
142
  return;
93
143
  }
144
+ if (
145
+ warning.code === "INVALID_ANNOTATION" &&
146
+ warning.loc.file.includes("/node_modules/")
147
+ ) {
148
+ return;
149
+ }
150
+ if (
151
+ warning.code === "EMPTY_BUNDLE" &&
152
+ warning.names.join("") === "vendors"
153
+ ) {
154
+ return;
155
+ }
94
156
  logger.warn(String(warning));
95
157
  },
96
158
  ...rollupInput,
@@ -126,6 +188,7 @@ export const bundleJsModules = async (
126
188
  const rollupPluginJsenv = ({
127
189
  // logger,
128
190
  rootDirectoryUrl,
191
+ buildDirectoryUrl,
129
192
  graph,
130
193
  jsModuleUrlInfos,
131
194
  sourcemaps,
@@ -163,16 +226,18 @@ const rollupPluginJsenv = ({
163
226
  }
164
227
 
165
228
  const getOriginalUrl = (rollupFileInfo) => {
166
- const { facadeModuleId } = rollupFileInfo;
167
- if (facadeModuleId) {
168
- return fileUrlConverter.asFileUrl(facadeModuleId);
229
+ if (rollupFileInfo.isEntry) {
230
+ const { facadeModuleId } = rollupFileInfo;
231
+ if (facadeModuleId) {
232
+ return fileUrlConverter.asFileUrl(facadeModuleId);
233
+ }
169
234
  }
170
235
  if (rollupFileInfo.isDynamicEntry) {
171
236
  const { moduleIds } = rollupFileInfo;
172
237
  const lastModuleId = moduleIds[moduleIds.length - 1];
173
238
  return fileUrlConverter.asFileUrl(lastModuleId);
174
239
  }
175
- return new URL(rollupFileInfo.fileName, rootDirectoryUrl).href;
240
+ return new URL(rollupFileInfo.fileName, buildDirectoryUrl).href;
176
241
  };
177
242
 
178
243
  return {
@@ -180,13 +245,13 @@ const rollupPluginJsenv = ({
180
245
  async buildStart() {
181
246
  _rollupEmitFile = (...args) => this.emitFile(...args);
182
247
  let previousNonEntryPointModuleId;
183
- jsModuleUrlInfos.forEach((jsModuleUrlInfo) => {
248
+ for (const jsModuleUrlInfo of jsModuleUrlInfos) {
184
249
  const id = jsModuleUrlInfo.url;
185
250
  if (jsModuleUrlInfo.isEntryPoint) {
186
251
  emitChunk({
187
252
  id,
188
253
  });
189
- return;
254
+ continue;
190
255
  }
191
256
  let preserveSignature;
192
257
  if (strictExports) {
@@ -218,8 +283,10 @@ const rollupPluginJsenv = ({
218
283
  : null,
219
284
  preserveSignature,
220
285
  });
221
- previousNonEntryPointModuleId = id;
222
- });
286
+ if (jsModuleUrlInfo.originalUrl.startsWith("file:")) {
287
+ previousNonEntryPointModuleId = id;
288
+ }
289
+ }
223
290
  },
224
291
  async generateBundle(outputOptions, rollupResult) {
225
292
  _rollupEmitFile = (...args) => this.emitFile(...args);
@@ -291,16 +358,32 @@ const rollupPluginJsenv = ({
291
358
  remapReference:
292
359
  specifierToUrlMap.size > 0
293
360
  ? (reference) => {
294
- // rollup generate specifiers only for static and dynamic imports
295
- // other references (like new URL()) are ignored
296
- // there is no need to remap them back
297
361
  if (
298
- reference.type === "js_import" &&
299
- reference.subtype !== "import_meta_resolve"
362
+ preserveDynamicImport &&
363
+ reference.subtype === "dynamic_import"
364
+ ) {
365
+ // when dynamic import are preserved, no need to remap them
366
+ return reference.specifier;
367
+ }
368
+ if (
369
+ reference.type !== "js_import" ||
370
+ reference.subtype === "import_meta_resolve"
300
371
  ) {
301
- return specifierToUrlMap.get(reference.specifier);
372
+ // rollup generate specifiers only for static and dynamic imports
373
+ // other references (like new URL()) are ignored
374
+ // there is no need to remap them back
375
+ return reference.specifier;
302
376
  }
303
- return reference.specifier;
377
+ const specifierBeforeRollup = specifierToUrlMap.get(
378
+ reference.specifier,
379
+ );
380
+ if (!specifierBeforeRollup) {
381
+ console.warn(
382
+ `cannot remap "${reference.specifier}" back to specifier before rollup, this is unexpected.`,
383
+ );
384
+ return reference.specifier;
385
+ }
386
+ return specifierBeforeRollup;
304
387
  }
305
388
  : undefined,
306
389
  };
@@ -308,11 +391,19 @@ const rollupPluginJsenv = ({
308
391
 
309
392
  const jsModuleBundleUrlInfos = {};
310
393
  const fileNames = Object.keys(rollupResult);
394
+ const originalUrlSet = new Set();
311
395
  for (const fileName of fileNames) {
312
396
  const rollupFileInfo = rollupResult[fileName];
313
397
  // there is 3 types of file: "placeholder", "asset", "chunk"
314
398
  if (rollupFileInfo.type === "chunk") {
315
399
  const jsModuleInfo = createBundledFileInfo(rollupFileInfo);
400
+ const originalUrl = jsModuleInfo.originalUrl;
401
+ if (originalUrlSet.has(originalUrl)) {
402
+ throw new Error(
403
+ `duplicate bundle info, cannot override ${originalUrl}`,
404
+ );
405
+ }
406
+ originalUrlSet.add(originalUrl);
316
407
  jsModuleBundleUrlInfos[jsModuleInfo.originalUrl] = jsModuleInfo;
317
408
  }
318
409
  }
@@ -335,37 +426,45 @@ const rollupPluginJsenv = ({
335
426
  return `[name].js`;
336
427
  },
337
428
  chunkFileNames: (chunkInfo) => {
429
+ if (chunkInfo.isEntry) {
430
+ const originalFileUrl = getOriginalUrl(chunkInfo);
431
+ const jsModuleUrlInfo = jsModuleUrlInfos.find(
432
+ (candidate) => candidate.url === originalFileUrl,
433
+ );
434
+ if (jsModuleUrlInfo && jsModuleUrlInfo.filenameHint) {
435
+ return jsModuleUrlInfo.filenameHint;
436
+ }
437
+ }
338
438
  return `${chunkInfo.name}.js`;
339
439
  },
340
440
  });
341
441
  },
342
442
  // https://rollupjs.org/guide/en/#resolvedynamicimport
343
443
  resolveDynamicImport: (specifier, importer) => {
344
- if (preserveDynamicImport) {
345
- let urlObject;
346
- if (specifier[0] === "/") {
347
- urlObject = new URL(specifier.slice(1), rootDirectoryUrl);
348
- } else {
349
- if (isFileSystemPath(importer)) {
350
- importer = fileUrlConverter.asFileUrl(importer);
351
- }
352
- urlObject = new URL(specifier, importer);
353
- }
354
- const searchParamsToAdd =
355
- augmentDynamicImportUrlSearchParams(urlObject);
356
- if (searchParamsToAdd) {
357
- Object.keys(searchParamsToAdd).forEach((key) => {
358
- const value = searchParamsToAdd[key];
359
- if (value === undefined) {
360
- urlObject.searchParams.delete(key);
361
- } else {
362
- urlObject.searchParams.set(key, value);
363
- }
364
- });
444
+ if (!preserveDynamicImport) {
445
+ return null;
446
+ }
447
+ let urlObject;
448
+ if (specifier[0] === "/") {
449
+ urlObject = new URL(specifier.slice(1), rootDirectoryUrl);
450
+ } else {
451
+ if (isFileSystemPath(importer)) {
452
+ importer = fileUrlConverter.asFileUrl(importer);
365
453
  }
366
- return { external: true, id: urlObject.href };
454
+ urlObject = new URL(specifier, importer);
455
+ }
456
+ const searchParamsToAdd = augmentDynamicImportUrlSearchParams(urlObject);
457
+ if (searchParamsToAdd) {
458
+ Object.keys(searchParamsToAdd).forEach((key) => {
459
+ const value = searchParamsToAdd[key];
460
+ if (value === undefined) {
461
+ urlObject.searchParams.delete(key);
462
+ } else {
463
+ urlObject.searchParams.set(key, value);
464
+ }
465
+ });
367
466
  }
368
- return null;
467
+ return { external: true, id: urlObject.href };
369
468
  },
370
469
  resolveId: (specifier, importer = rootDirectoryUrl) => {
371
470
  if (isFileSystemPath(importer)) {
@@ -388,7 +487,7 @@ const rollupPluginJsenv = ({
388
487
  // happen when excluded by referenceAnalysis.include
389
488
  return { id: url, external: true };
390
489
  }
391
- if (urlInfo.url.startsWith("ignore:")) {
490
+ if (url.startsWith("ignore:")) {
392
491
  return { id: url, external: true };
393
492
  }
394
493
  const filePath = fileUrlConverter.asFilePath(url);
@@ -419,8 +518,83 @@ const applyRollupPlugins = async ({
419
518
  const rollupModule = await import("rollup");
420
519
  rollup = rollupModule.rollup;
421
520
  }
521
+
522
+ const packageSideEffectsCacheMap = new Map();
523
+ const readClosestPackageJsonSideEffects = (url) => {
524
+ const packageDirectoryUrl = lookupPackageDirectory(url);
525
+ if (!packageDirectoryUrl) {
526
+ return undefined;
527
+ }
528
+ const fromCache = packageSideEffectsCacheMap.get(packageDirectoryUrl);
529
+ if (fromCache) {
530
+ return fromCache.value;
531
+ }
532
+ try {
533
+ const packageFileContent = readFileSync(
534
+ new URL("./package.json", packageDirectoryUrl),
535
+ "utf8",
536
+ );
537
+ const packageJSON = JSON.parse(packageFileContent);
538
+ const value = packageJSON.sideEffects;
539
+ if (Array.isArray(value)) {
540
+ const sideEffectPatterns = {};
541
+ for (const v of value) {
542
+ sideEffectPatterns[v] = true;
543
+ }
544
+ const associations = URL_META.resolveAssociations(
545
+ { sideEffects: sideEffectPatterns },
546
+ packageDirectoryUrl,
547
+ );
548
+ const isMatching = (url) => {
549
+ const meta = URL_META.applyAssociations({ url, associations });
550
+ return meta.sideEffects || false;
551
+ };
552
+ packageSideEffectsCacheMap.set(packageDirectoryUrl, {
553
+ value: isMatching,
554
+ });
555
+ } else {
556
+ packageSideEffectsCacheMap.set(packageDirectoryUrl, { value });
557
+ }
558
+ return value;
559
+ } catch {
560
+ packageSideEffectsCacheMap.set(packageDirectoryUrl, { value: undefined });
561
+ return undefined;
562
+ }
563
+ };
564
+
422
565
  const rollupReturnValue = await rollup({
423
566
  ...rollupInput,
567
+ treeshake: {
568
+ ...rollupInput.treeshake,
569
+ moduleSideEffects: (id, external) => {
570
+ if (id.startsWith("ignore:node:")) {
571
+ return false;
572
+ }
573
+ if (isSpecifierForNodeBuiltin(id)) {
574
+ return false;
575
+ }
576
+ if (id.startsWith("ignore:")) {
577
+ return null;
578
+ }
579
+ const url = id.startsWith("file:") ? id : fileSystemPathToUrl(id);
580
+ const closestPackageJsonSideEffects =
581
+ readClosestPackageJsonSideEffects(url);
582
+ if (closestPackageJsonSideEffects !== undefined) {
583
+ if (typeof closestPackageJsonSideEffects === "function") {
584
+ return closestPackageJsonSideEffects(url);
585
+ }
586
+ return closestPackageJsonSideEffects;
587
+ }
588
+ const moduleSideEffects = rollupInput.treeshake?.moduleSideEffects;
589
+ if (moduleSideEffects) {
590
+ if (typeof moduleSideEffects === "function") {
591
+ return moduleSideEffects(id, external);
592
+ }
593
+ return moduleSideEffects;
594
+ }
595
+ return null;
596
+ },
597
+ },
424
598
  plugins: rollupPlugins,
425
599
  });
426
600
  const rollupOutputArray = await rollupReturnValue.generate(rollupOutput);