quickbundle 2.3.0 → 2.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.
Files changed (3) hide show
  1. package/README.md +12 -12
  2. package/dist/index.js +53 -21
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -34,20 +34,18 @@ yarn add quickbundle
34
34
 
35
35
  2️⃣ Set up your package configuration (`package.json`):
36
36
 
37
- - When exporting both CommonJS (CJS) and ECMAScript Modules (ESM) format:
37
+ - When exporting exclusively ESM format:
38
38
 
39
39
  ```jsonc
40
40
  {
41
41
  "name": "lib", // Package name
42
42
  "exports": {
43
43
  ".": {
44
- "source": "src/index.ts(x)?", // Source code entrypoint
45
- "types": "./dist/index.d.ts", // Typing output file (if defined, can increase build time)
46
- "import": "./dist/index.mjs", // ESM output file (matches when the package is loaded via import or import() consumer side)
47
- "require": "./dist/index.cjs", // CommonJS output file (matches when the module is loaded via require() consumer side)
48
- "default": "./dist/index.mjs", // The generic fallback that always matches (this condition should always come last). By default, Quickbundle will always output ESM format for the `default` field. However, take care: if both `import` and `default` fields are defined, provide the same file path, as the `import` field export instruction will be the only one considered to define the output file path.
44
+ "source": "src/index.ts(x)?", // Source code entry point.
45
+ "types": "./dist/index.d.ts", // Typing output file (if defined, can increase build time). This condition should always come first after the custom `source` field definition.
46
+ "default": "./dist/index.mjs", // By default, Quickbundle will always output ESM format for the `default` field (this condition should always come last since it always matches as a generic fallback). However, take care: if both `import` and `default` fields are defined, provide the same file path, as the `import` field export instruction will be the only one considered to define the output file path.
49
47
  },
50
- "./otherSubModule": {
48
+ "./otherModulePath": {
51
49
  // ...
52
50
  }
53
51
  }
@@ -59,18 +57,20 @@ yarn add quickbundle
59
57
  }
60
58
  ```
61
59
 
62
- - When exporting exclusively ESM format:
60
+ - When exporting both CommonJS (CJS) and ECMAScript Modules (ESM) format (please be aware of [dual package hazard risk](https://nodejs.org/api/packages.html#dual-package-hazard)):
63
61
 
64
62
  ```jsonc
65
63
  {
66
64
  "name": "lib", // Package name
67
65
  "exports": {
68
66
  ".": {
69
- "source": "src/index.ts(x)?", // Source code entrypoint
70
- "types": "./dist/index.d.ts", // Typing output file (if defined, can increase build time)
71
- "default": "./dist/index.js", // The generic fallback that always matches (this condition should always come last). By default, Quickbundle will always output ESM format for the `default` field. However, take care: if both `import` and `default` fields are defined, provide the same file path, as the `import` field export instruction will be the only one considered to define the output file path.
67
+ "source": "src/index.ts(x)?", // Source code entry point.
68
+ "types": "./dist/index.d.ts", // // Typing output file (if defined, can increase build time). This condition should always come first after the custom `source` field definition.
69
+ "require": "./dist/index.cjs", // CommonJS output file (matches when the module is loaded via require() consumer side).
70
+ "import": "./dist/index.mjs", // ESM output file (matches when the package is loaded via import or import() consumer side).
71
+ "default": "./dist/index.mjs", // By default, Quickbundle will always output ESM format for the `default` field (this condition should always come last since it always matches as a generic fallback). However, take care: if both `import` and `default` fields are defined, provide the same file path, as the `import` field export instruction will be the only one considered to define the output file path.
72
72
  },
73
- "./otherSubModule": {
73
+ "./otherModulePath": {
74
74
  // ...
75
75
  }
76
76
  }
package/dist/index.js CHANGED
@@ -16,6 +16,9 @@ import { readFile as readFile$1 } from 'node:fs/promises';
16
16
  const onLog = (_, log)=>{
17
17
  if (log.message.includes("Generated an empty chunk")) return;
18
18
  };
19
+ const isRecord = (value)=>{
20
+ return typeof value === "object" && value !== null && !Array.isArray(value);
21
+ };
19
22
 
20
23
  const build = async (configurations)=>{
21
24
  var _process_env;
@@ -60,6 +63,20 @@ const createConfigurations = (options = {
60
63
  minification: false,
61
64
  sourceMaps: false
62
65
  })=>{
66
+ return getBuildableExports().flatMap((buildableExport)=>{
67
+ return [
68
+ buildableExport.source && createMainConfig({
69
+ ...buildableExport,
70
+ source: buildableExport.source
71
+ }, options),
72
+ buildableExport.source && buildableExport.types && createTypesConfig({
73
+ source: buildableExport.source,
74
+ types: buildableExport.types
75
+ })
76
+ ].filter(Boolean);
77
+ });
78
+ };
79
+ const getBuildableExports = ()=>{
63
80
  /**
64
81
  * Entry-point resolution:
65
82
  * Following the [package entry-point specification](https://nodejs.org/api/packages.html#package-entry-points),
@@ -68,34 +85,49 @@ const createConfigurations = (options = {
68
85
  */ if (PKG.main ?? PKG.module ?? PKG.types ?? !PKG.exports) {
69
86
  throw new Error("Invalid package entry points contract. Use the recommended [`exports` field](https://nodejs.org/api/packages.html#package-entry-points) instead and, for TypeScript-based projects, update the `tsconfig.json` file to resolve it properly (`moduleResolution` must be set to `Bundler` (or `NodeNext`)).");
70
87
  }
71
- const outputEntryPointFields = [
88
+ const buildableExportFields = [
72
89
  "default",
73
90
  "import",
74
91
  "require",
75
92
  "types"
76
93
  ];
77
- const output = Object.entries(PKG.exports).flatMap(([name, entryPoints])=>{
78
- if (typeof entryPoints === "string") return [];
79
- const entryPointKeys = Object.keys(entryPoints);
80
- if (entryPointKeys.includes("source")) {
81
- const hasAtLeastOneRequiredField = outputEntryPointFields.some((field)=>entryPointKeys.includes(field));
82
- if (!hasAtLeastOneRequiredField) {
83
- throw new Error(`A \`source\` field is defined without a provided output target for the \`${name}\` export. Make sure to define at least one entry point (including ${outputEntryPointFields.join(", ")})`);
94
+ let singleExport = undefined;
95
+ const output = Object.entries(PKG.exports).map(([field, value])=>{
96
+ if (isRecord(value)) {
97
+ return [
98
+ field,
99
+ value
100
+ ];
101
+ }
102
+ if ([
103
+ "source",
104
+ ...buildableExportFields
105
+ ].includes(field)) {
106
+ if (!singleExport) {
107
+ singleExport = {};
108
+ singleExport[field] = value;
109
+ return [
110
+ ".",
111
+ singleExport
112
+ ];
84
113
  }
114
+ singleExport[field] = value;
85
115
  }
86
- return [
87
- entryPoints.source && createMainConfig({
88
- ...entryPoints,
89
- source: entryPoints.source
90
- }, options),
91
- entryPoints.source && entryPoints.types && createTypesConfig({
92
- source: entryPoints.source,
93
- types: entryPoints.types
94
- })
95
- ].filter(Boolean);
96
- });
116
+ return undefined;
117
+ }).reduce((buildableExports, currentExport)=>{
118
+ if (!currentExport) return buildableExports;
119
+ const [exportField, exportValue] = currentExport;
120
+ const conditionalExportFields = Object.keys(exportValue);
121
+ if (!conditionalExportFields.includes("source")) return buildableExports;
122
+ const hasAtLeastOneRequiredField = buildableExportFields.some((entryPointField)=>conditionalExportFields.includes(entryPointField));
123
+ if (hasAtLeastOneRequiredField) {
124
+ buildableExports.push(exportValue);
125
+ return buildableExports;
126
+ }
127
+ throw new Error(`A \`source\` field is defined without an output defined for the \`${exportField}\` export. Make sure to define at least one conditional entry point (including ${buildableExportFields.map((field)=>`\`${field}\``).join(", ")})`);
128
+ }, []);
97
129
  if (output.length === 0) {
98
- throw new Error("No `source` field is set for the targeted package. If a build step is necessary, make sure to configure at least one `source` field in the package `exports` contract.");
130
+ throw new Error("No `source` field is set for the targeted package. If a build step is necessary, make sure to configure at least one `source` field in the package `exports` contract. If not, do not execute quickbundle on this package.");
99
131
  }
100
132
  return output;
101
133
  };
@@ -130,7 +162,7 @@ const createMainConfig = (entryPoints, options)=>{
130
162
  const { minification, sourceMaps } = options;
131
163
  const esmInput = entryPoints.import ?? entryPoints.default;
132
164
  if (entryPoints.import && entryPoints.default && entryPoints.import !== entryPoints.default) {
133
- throw new Error("Both `import` and `default` export fields have been defined but with different values. To preserve proper `default` field resolution on the consumer side, make sure to provide the same file path for both fields, as the `import` field export instruction will be the only one considered to define the output file path.");
165
+ throw new Error("Both `import` and `default` export fields have been defined but with different values. To preserve proper `default` field resolution on the consumer side (i.e. to target ESM format), make sure to provide the same file path for both fields.");
134
166
  }
135
167
  const output = [
136
168
  entryPoints.require && {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quickbundle",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "The zero-configuration transpiler and bundler for the web",
5
5
  "author": {
6
6
  "name": "Ayoub Adib",