@b9g/libuild 0.1.15 → 0.1.17
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 +18 -0
- package/package.json +1 -1
- package/src/libuild.cjs +66 -7
- package/src/libuild.js +66 -7
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.1.17] - 2025-01-25
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Ambient .d.ts file copying** - Hand-written ambient TypeScript declaration files (e.g., global.d.ts with `declare module` statements) are now automatically copied from src/ to dist/src/ during build. These files are automatically discovered by TypeScript when the package is consumed, providing global type declarations for module augmentation.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Non-deterministic export field ordering** - Fixed issue where package.json exports fields (types/import/require) would reorder non-deterministically across rebuilds with --save flag, causing unnecessary git diffs. All builds now consistently use types-first ordering.
|
|
12
|
+
|
|
13
|
+
## [0.1.16] - 2025-01-14
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- **Code splitting for dynamic imports** - ESM builds now use ESBuild's `splitting: true` to create separate chunk files for dynamically imported modules, enabling lazy loading and reducing initial bundle size
|
|
17
|
+
- **Smart entry point detection** - Packages with only "." or bin exports build only index.ts as entry point, allowing subdirectory files to be chunked when dynamically imported
|
|
18
|
+
- **Code splitting warning** - Warns when dual-format builds have chunks, informing users that CommonJS builds cannot benefit from code splitting (CJS bundles dynamic imports inline)
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- **Export validation** - Invalid export paths that don't point to src/ files are now properly validated and rejected with clear error messages
|
|
22
|
+
|
|
5
23
|
## [0.1.15] - 2025-01-14
|
|
6
24
|
|
|
7
25
|
### Fixed
|
package/package.json
CHANGED
package/src/libuild.cjs
CHANGED
|
@@ -215370,6 +215370,8 @@ function checkIfExportIsStale(exportKey, exportValue, entries) {
|
|
|
215370
215370
|
} else {
|
|
215371
215371
|
entryName = match[1];
|
|
215372
215372
|
}
|
|
215373
|
+
} else if (exportValue.startsWith("./") && !exportValue.includes("package.json")) {
|
|
215374
|
+
hasInvalidPath = true;
|
|
215373
215375
|
}
|
|
215374
215376
|
}
|
|
215375
215377
|
} else if (typeof exportValue === "object" && exportValue !== null) {
|
|
@@ -215386,6 +215388,8 @@ function checkIfExportIsStale(exportKey, exportValue, entries) {
|
|
|
215386
215388
|
} else {
|
|
215387
215389
|
entryName = match[1];
|
|
215388
215390
|
}
|
|
215391
|
+
} else if (importPath.startsWith("./") && !importPath.includes("package.json")) {
|
|
215392
|
+
hasInvalidPath = true;
|
|
215389
215393
|
}
|
|
215390
215394
|
}
|
|
215391
215395
|
}
|
|
@@ -215407,20 +215411,17 @@ async function generateExports(entries, mainEntry, options, existingExports = {}
|
|
|
215407
215411
|
async function createExportEntry(entry) {
|
|
215408
215412
|
if (entry.startsWith("bin/")) {
|
|
215409
215413
|
const binEntry = entry.replace("bin/", "");
|
|
215410
|
-
const exportEntry = {
|
|
215411
|
-
import: `./bin/${binEntry}.js`
|
|
215412
|
-
};
|
|
215414
|
+
const exportEntry = {};
|
|
215413
215415
|
if (distDir) {
|
|
215414
215416
|
const dtsPath = Path3.join(distDir, "bin", `${binEntry}.d.ts`);
|
|
215415
215417
|
if (await fileExists(dtsPath)) {
|
|
215416
215418
|
exportEntry.types = `./bin/${binEntry}.d.ts`;
|
|
215417
215419
|
}
|
|
215418
215420
|
}
|
|
215421
|
+
exportEntry.import = `./bin/${binEntry}.js`;
|
|
215419
215422
|
return exportEntry;
|
|
215420
215423
|
} else {
|
|
215421
|
-
const exportEntry = {
|
|
215422
|
-
import: `./src/${entry}.js`
|
|
215423
|
-
};
|
|
215424
|
+
const exportEntry = {};
|
|
215424
215425
|
if (distDir) {
|
|
215425
215426
|
const dtsPath = Path3.join(distDir, "src", `${entry}.d.ts`);
|
|
215426
215427
|
const exists = await fileExists(dtsPath);
|
|
@@ -215428,6 +215429,7 @@ async function generateExports(entries, mainEntry, options, existingExports = {}
|
|
|
215428
215429
|
exportEntry.types = `./src/${entry}.d.ts`;
|
|
215429
215430
|
}
|
|
215430
215431
|
}
|
|
215432
|
+
exportEntry.import = `./src/${entry}.js`;
|
|
215431
215433
|
if (options.formats.cjs) {
|
|
215432
215434
|
exportEntry.require = `./src/${entry}.cjs`;
|
|
215433
215435
|
}
|
|
@@ -215950,8 +215952,37 @@ async function build2(cwd, save = false) {
|
|
|
215950
215952
|
}
|
|
215951
215953
|
}
|
|
215952
215954
|
const binDir = Path3.join(cwd, "bin");
|
|
215953
|
-
const
|
|
215955
|
+
const allSrcFiles = await findEntrypoints(srcDir);
|
|
215954
215956
|
const binEntries = await findBinEntrypoints(binDir);
|
|
215957
|
+
let srcEntries;
|
|
215958
|
+
if (pkg.exports && typeof pkg.exports === "object") {
|
|
215959
|
+
const srcExportKeys = Object.keys(pkg.exports).filter((key) => {
|
|
215960
|
+
if (key === "." || key === "./package.json")
|
|
215961
|
+
return false;
|
|
215962
|
+
const val = pkg.exports[key];
|
|
215963
|
+
if (typeof val === "string")
|
|
215964
|
+
return val.includes("/src/");
|
|
215965
|
+
if (typeof val === "object" && val !== null) {
|
|
215966
|
+
return Object.values(val).some((v) => typeof v === "string" && v.includes("/src/"));
|
|
215967
|
+
}
|
|
215968
|
+
return false;
|
|
215969
|
+
});
|
|
215970
|
+
const dotExport = pkg.exports["."];
|
|
215971
|
+
let hasCustomMain = false;
|
|
215972
|
+
if (dotExport) {
|
|
215973
|
+
const importPath = typeof dotExport === "string" ? dotExport : dotExport.import || dotExport.default;
|
|
215974
|
+
if (importPath && !importPath.includes("/index.")) {
|
|
215975
|
+
hasCustomMain = true;
|
|
215976
|
+
}
|
|
215977
|
+
}
|
|
215978
|
+
if (srcExportKeys.length > 0 || hasCustomMain) {
|
|
215979
|
+
srcEntries = allSrcFiles;
|
|
215980
|
+
} else {
|
|
215981
|
+
srcEntries = allSrcFiles.includes("index") ? ["index"] : allSrcFiles;
|
|
215982
|
+
}
|
|
215983
|
+
} else {
|
|
215984
|
+
srcEntries = allSrcFiles;
|
|
215985
|
+
}
|
|
215955
215986
|
const allBinEntries = binEntries.map((entry) => ({ name: entry, source: "top-level" }));
|
|
215956
215987
|
const entries = [
|
|
215957
215988
|
...srcEntries,
|
|
@@ -216060,6 +216091,8 @@ async function build2(cwd, save = false) {
|
|
|
216060
216091
|
format: "esm",
|
|
216061
216092
|
outExtension: { ".js": ".js" },
|
|
216062
216093
|
bundle: true,
|
|
216094
|
+
splitting: true,
|
|
216095
|
+
// Enable code splitting for dynamic imports
|
|
216063
216096
|
minify: false,
|
|
216064
216097
|
sourcemap: false,
|
|
216065
216098
|
external: externalDeps,
|
|
@@ -216086,6 +216119,20 @@ async function build2(cwd, save = false) {
|
|
|
216086
216119
|
})] : []
|
|
216087
216120
|
]
|
|
216088
216121
|
});
|
|
216122
|
+
if (options.formats.cjs) {
|
|
216123
|
+
const distFiles = await FS3.readdir(distDir);
|
|
216124
|
+
const chunkFiles = distFiles.filter(
|
|
216125
|
+
(f) => f.endsWith(".js") && !f.endsWith(".d.ts") && (f.startsWith("chunk-") || f.includes("-") && !f.startsWith("package"))
|
|
216126
|
+
);
|
|
216127
|
+
if (chunkFiles.length > 0) {
|
|
216128
|
+
console.info(`
|
|
216129
|
+
\u26A0\uFE0F Code splitting detected - CommonJS build will bundle dynamic imports inline`);
|
|
216130
|
+
console.info(` ESM build: ${chunkFiles.length} chunk file(s) created for lazy loading`);
|
|
216131
|
+
console.info(` CJS build: Dynamic imports bundled inline (no chunks)`);
|
|
216132
|
+
console.info(` To get code splitting benefits, use ESM imports or remove "main" field
|
|
216133
|
+
`);
|
|
216134
|
+
}
|
|
216135
|
+
}
|
|
216089
216136
|
if (binEntryPoints.length > 0) {
|
|
216090
216137
|
const runtimeBanner = generateRuntimeBanner(pkg);
|
|
216091
216138
|
for (const binEntryName of binEntryNames) {
|
|
@@ -216191,6 +216238,18 @@ async function build2(cwd, save = false) {
|
|
|
216191
216238
|
await FS3.copyFile(srcPath, Path3.join(distDir, file));
|
|
216192
216239
|
}
|
|
216193
216240
|
}
|
|
216241
|
+
if (await fileExists(srcDir)) {
|
|
216242
|
+
const srcFiles = await FS3.readdir(srcDir);
|
|
216243
|
+
const ambientDtsFiles = srcFiles.filter((f) => f.endsWith(".d.ts"));
|
|
216244
|
+
if (ambientDtsFiles.length > 0) {
|
|
216245
|
+
console.info(` Copying ${ambientDtsFiles.length} ambient .d.ts file(s)...`);
|
|
216246
|
+
for (const dtsFile of ambientDtsFiles) {
|
|
216247
|
+
const srcPath = Path3.join(srcDir, dtsFile);
|
|
216248
|
+
const destPath = Path3.join(distSrcDir, dtsFile);
|
|
216249
|
+
await FS3.copyFile(srcPath, destPath);
|
|
216250
|
+
}
|
|
216251
|
+
}
|
|
216252
|
+
}
|
|
216194
216253
|
const commonFiles = ["README.md", "LICENSE", "CHANGELOG.md", "COPYING", "AUTHORS"];
|
|
216195
216254
|
if (pkg.files && Array.isArray(pkg.files)) {
|
|
216196
216255
|
for (const commonFile of commonFiles) {
|
package/src/libuild.js
CHANGED
|
@@ -357,6 +357,8 @@ function checkIfExportIsStale(exportKey, exportValue, entries) {
|
|
|
357
357
|
} else {
|
|
358
358
|
entryName = match[1];
|
|
359
359
|
}
|
|
360
|
+
} else if (exportValue.startsWith("./") && !exportValue.includes("package.json")) {
|
|
361
|
+
hasInvalidPath = true;
|
|
360
362
|
}
|
|
361
363
|
}
|
|
362
364
|
} else if (typeof exportValue === "object" && exportValue !== null) {
|
|
@@ -373,6 +375,8 @@ function checkIfExportIsStale(exportKey, exportValue, entries) {
|
|
|
373
375
|
} else {
|
|
374
376
|
entryName = match[1];
|
|
375
377
|
}
|
|
378
|
+
} else if (importPath.startsWith("./") && !importPath.includes("package.json")) {
|
|
379
|
+
hasInvalidPath = true;
|
|
376
380
|
}
|
|
377
381
|
}
|
|
378
382
|
}
|
|
@@ -394,20 +398,17 @@ async function generateExports(entries, mainEntry, options, existingExports = {}
|
|
|
394
398
|
async function createExportEntry(entry) {
|
|
395
399
|
if (entry.startsWith("bin/")) {
|
|
396
400
|
const binEntry = entry.replace("bin/", "");
|
|
397
|
-
const exportEntry = {
|
|
398
|
-
import: `./bin/${binEntry}.js`
|
|
399
|
-
};
|
|
401
|
+
const exportEntry = {};
|
|
400
402
|
if (distDir) {
|
|
401
403
|
const dtsPath = Path3.join(distDir, "bin", `${binEntry}.d.ts`);
|
|
402
404
|
if (await fileExists(dtsPath)) {
|
|
403
405
|
exportEntry.types = `./bin/${binEntry}.d.ts`;
|
|
404
406
|
}
|
|
405
407
|
}
|
|
408
|
+
exportEntry.import = `./bin/${binEntry}.js`;
|
|
406
409
|
return exportEntry;
|
|
407
410
|
} else {
|
|
408
|
-
const exportEntry = {
|
|
409
|
-
import: `./src/${entry}.js`
|
|
410
|
-
};
|
|
411
|
+
const exportEntry = {};
|
|
411
412
|
if (distDir) {
|
|
412
413
|
const dtsPath = Path3.join(distDir, "src", `${entry}.d.ts`);
|
|
413
414
|
const exists = await fileExists(dtsPath);
|
|
@@ -415,6 +416,7 @@ async function generateExports(entries, mainEntry, options, existingExports = {}
|
|
|
415
416
|
exportEntry.types = `./src/${entry}.d.ts`;
|
|
416
417
|
}
|
|
417
418
|
}
|
|
419
|
+
exportEntry.import = `./src/${entry}.js`;
|
|
418
420
|
if (options.formats.cjs) {
|
|
419
421
|
exportEntry.require = `./src/${entry}.cjs`;
|
|
420
422
|
}
|
|
@@ -937,8 +939,37 @@ async function build2(cwd, save = false) {
|
|
|
937
939
|
}
|
|
938
940
|
}
|
|
939
941
|
const binDir = Path3.join(cwd, "bin");
|
|
940
|
-
const
|
|
942
|
+
const allSrcFiles = await findEntrypoints(srcDir);
|
|
941
943
|
const binEntries = await findBinEntrypoints(binDir);
|
|
944
|
+
let srcEntries;
|
|
945
|
+
if (pkg.exports && typeof pkg.exports === "object") {
|
|
946
|
+
const srcExportKeys = Object.keys(pkg.exports).filter((key) => {
|
|
947
|
+
if (key === "." || key === "./package.json")
|
|
948
|
+
return false;
|
|
949
|
+
const val = pkg.exports[key];
|
|
950
|
+
if (typeof val === "string")
|
|
951
|
+
return val.includes("/src/");
|
|
952
|
+
if (typeof val === "object" && val !== null) {
|
|
953
|
+
return Object.values(val).some((v) => typeof v === "string" && v.includes("/src/"));
|
|
954
|
+
}
|
|
955
|
+
return false;
|
|
956
|
+
});
|
|
957
|
+
const dotExport = pkg.exports["."];
|
|
958
|
+
let hasCustomMain = false;
|
|
959
|
+
if (dotExport) {
|
|
960
|
+
const importPath = typeof dotExport === "string" ? dotExport : dotExport.import || dotExport.default;
|
|
961
|
+
if (importPath && !importPath.includes("/index.")) {
|
|
962
|
+
hasCustomMain = true;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
if (srcExportKeys.length > 0 || hasCustomMain) {
|
|
966
|
+
srcEntries = allSrcFiles;
|
|
967
|
+
} else {
|
|
968
|
+
srcEntries = allSrcFiles.includes("index") ? ["index"] : allSrcFiles;
|
|
969
|
+
}
|
|
970
|
+
} else {
|
|
971
|
+
srcEntries = allSrcFiles;
|
|
972
|
+
}
|
|
942
973
|
const allBinEntries = binEntries.map((entry) => ({ name: entry, source: "top-level" }));
|
|
943
974
|
const entries = [
|
|
944
975
|
...srcEntries,
|
|
@@ -1047,6 +1078,8 @@ async function build2(cwd, save = false) {
|
|
|
1047
1078
|
format: "esm",
|
|
1048
1079
|
outExtension: { ".js": ".js" },
|
|
1049
1080
|
bundle: true,
|
|
1081
|
+
splitting: true,
|
|
1082
|
+
// Enable code splitting for dynamic imports
|
|
1050
1083
|
minify: false,
|
|
1051
1084
|
sourcemap: false,
|
|
1052
1085
|
external: externalDeps,
|
|
@@ -1073,6 +1106,20 @@ async function build2(cwd, save = false) {
|
|
|
1073
1106
|
})] : []
|
|
1074
1107
|
]
|
|
1075
1108
|
});
|
|
1109
|
+
if (options.formats.cjs) {
|
|
1110
|
+
const distFiles = await FS3.readdir(distDir);
|
|
1111
|
+
const chunkFiles = distFiles.filter(
|
|
1112
|
+
(f) => f.endsWith(".js") && !f.endsWith(".d.ts") && (f.startsWith("chunk-") || f.includes("-") && !f.startsWith("package"))
|
|
1113
|
+
);
|
|
1114
|
+
if (chunkFiles.length > 0) {
|
|
1115
|
+
console.info(`
|
|
1116
|
+
\u26A0\uFE0F Code splitting detected - CommonJS build will bundle dynamic imports inline`);
|
|
1117
|
+
console.info(` ESM build: ${chunkFiles.length} chunk file(s) created for lazy loading`);
|
|
1118
|
+
console.info(` CJS build: Dynamic imports bundled inline (no chunks)`);
|
|
1119
|
+
console.info(` To get code splitting benefits, use ESM imports or remove "main" field
|
|
1120
|
+
`);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1076
1123
|
if (binEntryPoints.length > 0) {
|
|
1077
1124
|
const runtimeBanner = generateRuntimeBanner(pkg);
|
|
1078
1125
|
for (const binEntryName of binEntryNames) {
|
|
@@ -1178,6 +1225,18 @@ async function build2(cwd, save = false) {
|
|
|
1178
1225
|
await FS3.copyFile(srcPath, Path3.join(distDir, file));
|
|
1179
1226
|
}
|
|
1180
1227
|
}
|
|
1228
|
+
if (await fileExists(srcDir)) {
|
|
1229
|
+
const srcFiles = await FS3.readdir(srcDir);
|
|
1230
|
+
const ambientDtsFiles = srcFiles.filter((f) => f.endsWith(".d.ts"));
|
|
1231
|
+
if (ambientDtsFiles.length > 0) {
|
|
1232
|
+
console.info(` Copying ${ambientDtsFiles.length} ambient .d.ts file(s)...`);
|
|
1233
|
+
for (const dtsFile of ambientDtsFiles) {
|
|
1234
|
+
const srcPath = Path3.join(srcDir, dtsFile);
|
|
1235
|
+
const destPath = Path3.join(distSrcDir, dtsFile);
|
|
1236
|
+
await FS3.copyFile(srcPath, destPath);
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1181
1240
|
const commonFiles = ["README.md", "LICENSE", "CHANGELOG.md", "COPYING", "AUTHORS"];
|
|
1182
1241
|
if (pkg.files && Array.isArray(pkg.files)) {
|
|
1183
1242
|
for (const commonFile of commonFiles) {
|