quickbundle 2.2.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.
- package/README.md +33 -4
- package/dist/index.js +59 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,15 +34,44 @@ yarn add quickbundle
|
|
|
34
34
|
|
|
35
35
|
2️⃣ Set up your package configuration (`package.json`):
|
|
36
36
|
|
|
37
|
+
- When exporting exclusively ESM format:
|
|
38
|
+
|
|
39
|
+
```jsonc
|
|
40
|
+
{
|
|
41
|
+
"name": "lib", // Package name
|
|
42
|
+
"exports": {
|
|
43
|
+
".": {
|
|
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.
|
|
47
|
+
},
|
|
48
|
+
"./otherModulePath": {
|
|
49
|
+
// ...
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "quickbundle build", // Production mode (optimizes bundle)
|
|
54
|
+
"watch": "quickbundle watch", // Development mode (watches each file change)
|
|
55
|
+
},
|
|
56
|
+
// ...
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
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)):
|
|
61
|
+
|
|
37
62
|
```jsonc
|
|
38
63
|
{
|
|
39
64
|
"name": "lib", // Package name
|
|
40
65
|
"exports": {
|
|
41
66
|
".": {
|
|
42
|
-
"source": "src/index.ts(x)?", // Source code
|
|
43
|
-
"types": "./dist/index.d.ts", // Typing output file (if defined, can increase build time)
|
|
44
|
-
"
|
|
45
|
-
"
|
|
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
|
+
},
|
|
73
|
+
"./otherModulePath": {
|
|
74
|
+
// ...
|
|
46
75
|
}
|
|
47
76
|
}
|
|
48
77
|
"scripts": {
|
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,33 +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
|
|
88
|
+
const buildableExportFields = [
|
|
89
|
+
"default",
|
|
72
90
|
"import",
|
|
73
91
|
"require",
|
|
74
92
|
"types"
|
|
75
93
|
];
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
+
];
|
|
83
113
|
}
|
|
114
|
+
singleExport[field] = value;
|
|
84
115
|
}
|
|
85
|
-
return
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
+
}, []);
|
|
96
129
|
if (output.length === 0) {
|
|
97
|
-
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.");
|
|
98
131
|
}
|
|
99
132
|
return output;
|
|
100
133
|
};
|
|
@@ -127,14 +160,18 @@ const getPlugins = (...customPlugins)=>{
|
|
|
127
160
|
};
|
|
128
161
|
const createMainConfig = (entryPoints, options)=>{
|
|
129
162
|
const { minification, sourceMaps } = options;
|
|
163
|
+
const esmInput = entryPoints.import ?? entryPoints.default;
|
|
164
|
+
if (entryPoints.import && entryPoints.default && entryPoints.import !== entryPoints.default) {
|
|
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.");
|
|
166
|
+
}
|
|
130
167
|
const output = [
|
|
131
168
|
entryPoints.require && {
|
|
132
169
|
file: entryPoints.require,
|
|
133
170
|
format: "cjs",
|
|
134
171
|
sourcemap: sourceMaps
|
|
135
172
|
},
|
|
136
|
-
|
|
137
|
-
file:
|
|
173
|
+
esmInput && {
|
|
174
|
+
file: esmInput,
|
|
138
175
|
format: "es",
|
|
139
176
|
sourcemap: sourceMaps
|
|
140
177
|
}
|