@normed/bundle 4.3.2 → 4.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/CHANGELOG.md CHANGED
@@ -6,6 +6,14 @@ Given a version number MAJOR.MINOR.PATCH, increment the:
6
6
  2. MINOR version when you add functionality in a backwards compatible manner, and
7
7
  3. PATCH version when you make backwards compatible bug fixes.
8
8
 
9
+ # 4.4.0
10
+
11
+ * MINOR: Adds `css.externalUrls` configuration option for marking URL patterns as external in CSS files.
12
+ * MINOR: Adds `createCssExternalUrlsPlugin` esbuild plugin.
13
+ * MINOR: Adds the `asset` modifier for copying files verbatim without processing.
14
+ * MINOR: Adds default file loaders for common asset types (images, fonts, media).
15
+ * PATCH: Adds documentation for common pitfalls.
16
+
9
17
  # 4.3.2
10
18
 
11
19
  * MINOR: fixes map files being expected when no sourcemap value is set.
package/README.md CHANGED
@@ -83,6 +83,13 @@ type EntryConfig = {
83
83
  "config"?: string | ESBuildConfig,
84
84
  }
85
85
  }
86
+
87
+ // Configuration specific to CSS processing
88
+ "css"?: {
89
+ // URL patterns to mark as external (not resolved at build time)
90
+ // Supports glob-style wildcards, e.g. ["/fonts/*", "/images/*"]
91
+ "externalUrls"?: string[]
92
+ }
86
93
  }
87
94
  ```
88
95
 
@@ -160,6 +167,49 @@ Any files you don't want to name with such a suffix can be added manually. To ad
160
167
  yarn bundle --entrypoint anchovies.ts --entrypoint pics/cartoons.png
161
168
  ```
162
169
 
170
+ ### asset modifier
171
+
172
+ Use the `.asset` modifier to copy files verbatim without any processing. This is useful for pre-built CSS or JavaScript files that should not be processed by esbuild:
173
+
174
+ ```
175
+ src/
176
+ ├─ vendor/
177
+ │ ├─ legacy.asset.js → bundles/vendor/legacy.js (copied verbatim)
178
+ │ ├─ styles.asset.css → bundles/vendor/styles.css (copied verbatim)
179
+ ```
180
+
181
+ This is particularly helpful for:
182
+ - Third-party CSS/JS libraries with complex `url()` references
183
+ - Pre-minified vendor files
184
+ - Files with runtime paths that shouldn't be resolved at build time
185
+
186
+ ### default file loaders
187
+
188
+ Common asset types are automatically configured to use esbuild's `file` loader:
189
+ - Images: `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.svg`, `.ico`
190
+ - Fonts: `.ttf`, `.otf`, `.woff`, `.woff2`, `.eot`
191
+ - Media: `.mp4`, `.webm`, `.mp3`, `.wav`
192
+
193
+ This means these files referenced from your CSS/JS will be copied to the output directory and their paths will be rewritten appropriately.
194
+
195
+ ### external CSS URLs
196
+
197
+ For CSS files that reference runtime paths (like `/fonts/*` or `/images/*`) that should not be resolved at build time, use the `css.externalUrls` configuration:
198
+
199
+ ```json
200
+ {
201
+ "bundle": {
202
+ "baseConfig": {
203
+ "css": {
204
+ "externalUrls": ["/fonts/*", "/images/*", "https://*"]
205
+ }
206
+ }
207
+ }
208
+ }
209
+ ```
210
+
211
+ URL patterns support glob-style wildcards (`*`). URLs matching these patterns will be marked as external and left unchanged in the output CSS.
212
+
163
213
  ### analyse
164
214
 
165
215
  To get a report on bundle content and size enable analysis:
@@ -246,6 +296,44 @@ import { verifyBuilder } from '@normed/bundle';
246
296
 
247
297
  This does not fully test your builder, but it does run some tests we have found helpful.
248
298
 
299
+ # Common Pitfalls
300
+
301
+ ### Custom entrypoint modifiers not discovered
302
+
303
+ **Problem**: You want to use a custom file suffix like `.worker.ts` but files aren't being discovered.
304
+
305
+ **Cause**: Using `platformModifiers` in package.json. This is a CLI-only option, not a package.json config.
306
+
307
+ **Solution**: Use `modifiers` with `entrypoint: true`:
308
+
309
+ ```json
310
+ {
311
+ "bundle": {
312
+ "modifiers": {
313
+ "worker": {
314
+ "entrypoint": true,
315
+ "extends": "server"
316
+ }
317
+ }
318
+ }
319
+ }
320
+ ```
321
+
322
+ Now `*.worker.ts` files will be discovered and built with server platform settings.
323
+
324
+ ### No entrypoints found
325
+
326
+ **Problem**: Build completes but reports "No entrypoints".
327
+
328
+ **Cause**: Files must match a recognized pattern (`.static.*`, `.node.*`, `.web.*`, or custom modifiers with `entrypoint: true`).
329
+
330
+ **Solution**: Either:
331
+ 1. Rename your file to use a recognized pattern (e.g., `index.static.ts`)
332
+ 2. Add a custom modifier in package.json (see above)
333
+ 3. Manually specify entrypoints: `"entrypoints": ["myfile.ts"]`
334
+
335
+ Use `LOG_LEVEL=verbose yarn bundle` to see which patterns are being searched.
336
+
249
337
  # Potential errors
250
338
 
251
339
  es-build, which is essentially the basis for this whole thing, breaks reproducible builds as it includes the full path to a file as both a comment and a map key. To get around this we manually replace certain paths on build. There is a good chance this will not work for globally installed modules and will break certain hard coded strings.
@@ -68637,7 +68637,7 @@ async function copy(from, to) {
68637
68637
  }
68638
68638
  await import_fs_extra2.default.promises.copyFile(from, to);
68639
68639
  }
68640
- var contextModifiers = ["context"];
68640
+ var contextModifiers = ["context", "asset"];
68641
68641
  function __throw__(error) {
68642
68642
  throw error;
68643
68643
  }
@@ -68689,6 +68689,9 @@ var refineEntryConfig = makePartialRefinement({
68689
68689
  import_refinements2.refineString,
68690
68690
  refineESBuildOptions
68691
68691
  )
68692
+ }),
68693
+ css: makePartialRefinement({
68694
+ externalUrls: (0, import_refinements2.refineArrayOf)(import_refinements2.refineString)
68692
68695
  })
68693
68696
  });
68694
68697
  var refinePackageJSONBuildConfig = makePartialRefinement({
@@ -69364,6 +69367,33 @@ var plugin3 = (options2) => {
69364
69367
  };
69365
69368
  var load_ts_js_default = plugin3;
69366
69369
 
69370
+ // pnp:/builds/normed/bundle/packages/bundle/src/esbuild-plugins/css_external_urls.ts
69371
+ function createCssExternalUrlsPlugin(patterns) {
69372
+ const name3 = "css-external-urls";
69373
+ const regexPatterns = patterns.map((pattern) => {
69374
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
69375
+ const regexStr = "^" + escaped.replace(/\*/g, ".*") + "$";
69376
+ return new RegExp(regexStr);
69377
+ });
69378
+ return {
69379
+ name: name3,
69380
+ setup(build2) {
69381
+ build2.onResolve({ filter: /.*/ }, (args) => {
69382
+ const path12 = args.path;
69383
+ for (const regex of regexPatterns) {
69384
+ if (regex.test(path12)) {
69385
+ return {
69386
+ path: path12,
69387
+ external: true
69388
+ };
69389
+ }
69390
+ }
69391
+ return void 0;
69392
+ });
69393
+ }
69394
+ };
69395
+ }
69396
+
69367
69397
  // pnp:/builds/normed/bundle/packages/bundle/src/builders/esbuilder.ts
69368
69398
  var import_esbuild_plugin_pnp = __toESM(require_lib15());
69369
69399
  var ts = __toESM(require("typescript"));
@@ -69444,6 +69474,7 @@ var esbuilder = {
69444
69474
  ([k, v]) => `${v.entrypoint.infile.relative} -> ${k}`
69445
69475
  )
69446
69476
  );
69477
+ const externalUrlsPlugin = exampleFile.entryconfig.css?.externalUrls?.length ? createCssExternalUrlsPlugin(exampleFile.entryconfig.css.externalUrls) : null;
69447
69478
  const finalConfig = {
69448
69479
  ...baseConfig,
69449
69480
  plugins: [
@@ -69451,6 +69482,7 @@ var esbuilder = {
69451
69482
  load_less_default,
69452
69483
  load_pug_default,
69453
69484
  load_ts_js_default({ sourceRelativeDirnameFilename: true, basedir: indir }),
69485
+ ...externalUrlsPlugin ? [externalUrlsPlugin] : [],
69454
69486
  (0, import_esbuild_plugin_pnp.pnpPlugin)()
69455
69487
  // if running in yarn/other pnp env
69456
69488
  ],
@@ -69652,7 +69684,10 @@ var builders = {
69652
69684
  copy: copyBuilder
69653
69685
  };
69654
69686
  var defaultBuilders = [builders.es, builders.copy];
69655
- function getBuilder(builders2, ext) {
69687
+ function getBuilder(builders2, ext, modifiers) {
69688
+ if (modifiers?.includes("asset")) {
69689
+ return copyBuilder;
69690
+ }
69656
69691
  for (const builder of builders2) {
69657
69692
  for (const inExt of builder.inExt) {
69658
69693
  if (inExt instanceof RegExp && inExt.test(ext) || inExt === ext) {
@@ -70171,7 +70206,10 @@ var EntryConfigInstance = class _EntryConfigInstance {
70171
70206
  analyse: merged.analyse ?? absurd(),
70172
70207
  tsconfig: merged.typescript?.tsconfig ?? absurd(),
70173
70208
  declarations: merged.typescript?.declarations ?? absurd(),
70174
- esbuild: merged.javascript?.esbuild ?? absurd()
70209
+ esbuild: merged.javascript?.esbuild ?? absurd(),
70210
+ css: {
70211
+ externalUrls: merged.css?.externalUrls ?? []
70212
+ }
70175
70213
  };
70176
70214
  this.completed = complete;
70177
70215
  return complete;
@@ -70241,6 +70279,15 @@ var EntryConfigInstance = class _EntryConfigInstance {
70241
70279
  ...a.javascript?.esbuild,
70242
70280
  ...b.javascript?.esbuild
70243
70281
  }
70282
+ },
70283
+ css: {
70284
+ ...a.css,
70285
+ ...b.css,
70286
+ // Merge external URLs arrays
70287
+ externalUrls: [
70288
+ ...a.css?.externalUrls ?? [],
70289
+ ...b.css?.externalUrls ?? []
70290
+ ]
70244
70291
  }
70245
70292
  };
70246
70293
  }
@@ -70302,7 +70349,11 @@ async function pathToEntrypoint(buildConfig, file, source) {
70302
70349
  `WARN: Determined "${infile.relative}" is not a file, but continuing on as though it is`
70303
70350
  );
70304
70351
  }
70305
- const builder = getBuilder(buildConfig.builders, infile.extension);
70352
+ const builder = getBuilder(
70353
+ buildConfig.builders,
70354
+ infile.extension,
70355
+ infile.modifiers
70356
+ );
70306
70357
  if (!builder) {
70307
70358
  return new NoMatchingBuilder(infile.relative, infile.extension);
70308
70359
  }
@@ -70375,7 +70426,11 @@ async function discoveredEntrypoints(buildConfig) {
70375
70426
  parseModifiers: true,
70376
70427
  supportedModifiers: buildConfig.modifiers
70377
70428
  });
70378
- const builder = getBuilder(buildConfig.builders, infile.extension);
70429
+ const builder = getBuilder(
70430
+ buildConfig.builders,
70431
+ infile.extension,
70432
+ infile.modifiers
70433
+ );
70379
70434
  if (builder === null) {
70380
70435
  return new NoMatchingBuilder(infile.relative, infile.extension);
70381
70436
  }
@@ -70464,6 +70519,10 @@ async function getBuildConfig(options2) {
70464
70519
  entrypoint: true,
70465
70520
  extends: "node"
70466
70521
  },
70522
+ asset: {
70523
+ entrypoint: true
70524
+ // No extends - files with .asset modifier are copied verbatim
70525
+ },
70467
70526
  web: {
70468
70527
  entrypoint: true,
70469
70528
  extends: "browser"
@@ -70518,7 +70577,23 @@ async function getBuildConfig(options2) {
70518
70577
  sourcemap: "external",
70519
70578
  platform: "neutral",
70520
70579
  loader: {
70521
- // ".pug": "text",
70580
+ // Default loaders for common asset types
70581
+ ".png": "file",
70582
+ ".jpg": "file",
70583
+ ".jpeg": "file",
70584
+ ".gif": "file",
70585
+ ".webp": "file",
70586
+ ".svg": "file",
70587
+ ".ttf": "file",
70588
+ ".otf": "file",
70589
+ ".woff": "file",
70590
+ ".woff2": "file",
70591
+ ".eot": "file",
70592
+ ".ico": "file",
70593
+ ".mp4": "file",
70594
+ ".webm": "file",
70595
+ ".mp3": "file",
70596
+ ".wav": "file"
70522
70597
  },
70523
70598
  minify: false,
70524
70599
  external: [],