@b9g/libuild 0.1.14 → 0.1.16
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 +15 -0
- package/package.json +1 -1
- package/src/libuild.cjs +67 -14
- package/src/libuild.js +67 -14
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.1.16] - 2025-01-14
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **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
|
|
9
|
+
- **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
|
|
10
|
+
- **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)
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Export validation** - Invalid export paths that don't point to src/ files are now properly validated and rejected with clear error messages
|
|
14
|
+
|
|
15
|
+
## [0.1.15] - 2025-01-14
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- **Support bin-only packages** - Packages with only bin/ executables and no src/ library code no longer crash. Main/module/types fields and "." export are now correctly omitted for bin-only packages, while bin exports are properly generated.
|
|
19
|
+
|
|
5
20
|
## [0.1.14] - 2025-01-14
|
|
6
21
|
|
|
7
22
|
### 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
|
}
|
|
@@ -215505,10 +215509,12 @@ async function generateExports(entries, mainEntry, options, existingExports = {}
|
|
|
215505
215509
|
exports2[key] = expandExistingExport(value);
|
|
215506
215510
|
}
|
|
215507
215511
|
}
|
|
215508
|
-
if (
|
|
215509
|
-
exports2["."]
|
|
215510
|
-
|
|
215511
|
-
|
|
215512
|
+
if (mainEntry) {
|
|
215513
|
+
if (!exports2["."]) {
|
|
215514
|
+
exports2["."] = await createExportEntry(mainEntry);
|
|
215515
|
+
} else {
|
|
215516
|
+
exports2["."] = expandExistingExport(exports2["."], mainEntry);
|
|
215517
|
+
}
|
|
215512
215518
|
}
|
|
215513
215519
|
for (const entry of entries) {
|
|
215514
215520
|
if (entry === "umd")
|
|
@@ -215883,15 +215889,17 @@ async function cleanPackageJSON(pkg, mainEntry, options, cwd, distDir) {
|
|
|
215883
215889
|
if (!cleaned.type) {
|
|
215884
215890
|
cleaned.type = "module";
|
|
215885
215891
|
}
|
|
215886
|
-
if (
|
|
215887
|
-
|
|
215888
|
-
|
|
215889
|
-
|
|
215890
|
-
|
|
215891
|
-
|
|
215892
|
-
|
|
215893
|
-
|
|
215894
|
-
|
|
215892
|
+
if (mainEntry) {
|
|
215893
|
+
if (options.formats.cjs) {
|
|
215894
|
+
cleaned.main = `src/${mainEntry}.cjs`;
|
|
215895
|
+
}
|
|
215896
|
+
cleaned.module = `src/${mainEntry}.js`;
|
|
215897
|
+
if (distDir) {
|
|
215898
|
+
const dtsPath = Path3.join(distDir, "src", `${mainEntry}.d.ts`);
|
|
215899
|
+
const exists = await fileExists(dtsPath);
|
|
215900
|
+
if (exists) {
|
|
215901
|
+
cleaned.types = `src/${mainEntry}.d.ts`;
|
|
215902
|
+
}
|
|
215895
215903
|
}
|
|
215896
215904
|
}
|
|
215897
215905
|
return cleaned;
|
|
@@ -215946,8 +215954,37 @@ async function build2(cwd, save = false) {
|
|
|
215946
215954
|
}
|
|
215947
215955
|
}
|
|
215948
215956
|
const binDir = Path3.join(cwd, "bin");
|
|
215949
|
-
const
|
|
215957
|
+
const allSrcFiles = await findEntrypoints(srcDir);
|
|
215950
215958
|
const binEntries = await findBinEntrypoints(binDir);
|
|
215959
|
+
let srcEntries;
|
|
215960
|
+
if (pkg.exports && typeof pkg.exports === "object") {
|
|
215961
|
+
const srcExportKeys = Object.keys(pkg.exports).filter((key) => {
|
|
215962
|
+
if (key === "." || key === "./package.json")
|
|
215963
|
+
return false;
|
|
215964
|
+
const val = pkg.exports[key];
|
|
215965
|
+
if (typeof val === "string")
|
|
215966
|
+
return val.includes("/src/");
|
|
215967
|
+
if (typeof val === "object" && val !== null) {
|
|
215968
|
+
return Object.values(val).some((v) => typeof v === "string" && v.includes("/src/"));
|
|
215969
|
+
}
|
|
215970
|
+
return false;
|
|
215971
|
+
});
|
|
215972
|
+
const dotExport = pkg.exports["."];
|
|
215973
|
+
let hasCustomMain = false;
|
|
215974
|
+
if (dotExport) {
|
|
215975
|
+
const importPath = typeof dotExport === "string" ? dotExport : dotExport.import || dotExport.default;
|
|
215976
|
+
if (importPath && !importPath.includes("/index.")) {
|
|
215977
|
+
hasCustomMain = true;
|
|
215978
|
+
}
|
|
215979
|
+
}
|
|
215980
|
+
if (srcExportKeys.length > 0 || hasCustomMain) {
|
|
215981
|
+
srcEntries = allSrcFiles;
|
|
215982
|
+
} else {
|
|
215983
|
+
srcEntries = allSrcFiles.includes("index") ? ["index"] : allSrcFiles;
|
|
215984
|
+
}
|
|
215985
|
+
} else {
|
|
215986
|
+
srcEntries = allSrcFiles;
|
|
215987
|
+
}
|
|
215951
215988
|
const allBinEntries = binEntries.map((entry) => ({ name: entry, source: "top-level" }));
|
|
215952
215989
|
const entries = [
|
|
215953
215990
|
...srcEntries,
|
|
@@ -216056,6 +216093,8 @@ async function build2(cwd, save = false) {
|
|
|
216056
216093
|
format: "esm",
|
|
216057
216094
|
outExtension: { ".js": ".js" },
|
|
216058
216095
|
bundle: true,
|
|
216096
|
+
splitting: true,
|
|
216097
|
+
// Enable code splitting for dynamic imports
|
|
216059
216098
|
minify: false,
|
|
216060
216099
|
sourcemap: false,
|
|
216061
216100
|
external: externalDeps,
|
|
@@ -216082,6 +216121,20 @@ async function build2(cwd, save = false) {
|
|
|
216082
216121
|
})] : []
|
|
216083
216122
|
]
|
|
216084
216123
|
});
|
|
216124
|
+
if (options.formats.cjs) {
|
|
216125
|
+
const distFiles = await FS3.readdir(distDir);
|
|
216126
|
+
const chunkFiles = distFiles.filter(
|
|
216127
|
+
(f) => f.endsWith(".js") && !f.endsWith(".d.ts") && (f.startsWith("chunk-") || f.includes("-") && !f.startsWith("package"))
|
|
216128
|
+
);
|
|
216129
|
+
if (chunkFiles.length > 0) {
|
|
216130
|
+
console.info(`
|
|
216131
|
+
\u26A0\uFE0F Code splitting detected - CommonJS build will bundle dynamic imports inline`);
|
|
216132
|
+
console.info(` ESM build: ${chunkFiles.length} chunk file(s) created for lazy loading`);
|
|
216133
|
+
console.info(` CJS build: Dynamic imports bundled inline (no chunks)`);
|
|
216134
|
+
console.info(` To get code splitting benefits, use ESM imports or remove "main" field
|
|
216135
|
+
`);
|
|
216136
|
+
}
|
|
216137
|
+
}
|
|
216085
216138
|
if (binEntryPoints.length > 0) {
|
|
216086
216139
|
const runtimeBanner = generateRuntimeBanner(pkg);
|
|
216087
216140
|
for (const binEntryName of binEntryNames) {
|
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
|
}
|
|
@@ -492,10 +496,12 @@ async function generateExports(entries, mainEntry, options, existingExports = {}
|
|
|
492
496
|
exports[key] = expandExistingExport(value);
|
|
493
497
|
}
|
|
494
498
|
}
|
|
495
|
-
if (
|
|
496
|
-
exports["."]
|
|
497
|
-
|
|
498
|
-
|
|
499
|
+
if (mainEntry) {
|
|
500
|
+
if (!exports["."]) {
|
|
501
|
+
exports["."] = await createExportEntry(mainEntry);
|
|
502
|
+
} else {
|
|
503
|
+
exports["."] = expandExistingExport(exports["."], mainEntry);
|
|
504
|
+
}
|
|
499
505
|
}
|
|
500
506
|
for (const entry of entries) {
|
|
501
507
|
if (entry === "umd")
|
|
@@ -870,15 +876,17 @@ async function cleanPackageJSON(pkg, mainEntry, options, cwd, distDir) {
|
|
|
870
876
|
if (!cleaned.type) {
|
|
871
877
|
cleaned.type = "module";
|
|
872
878
|
}
|
|
873
|
-
if (
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
879
|
+
if (mainEntry) {
|
|
880
|
+
if (options.formats.cjs) {
|
|
881
|
+
cleaned.main = `src/${mainEntry}.cjs`;
|
|
882
|
+
}
|
|
883
|
+
cleaned.module = `src/${mainEntry}.js`;
|
|
884
|
+
if (distDir) {
|
|
885
|
+
const dtsPath = Path3.join(distDir, "src", `${mainEntry}.d.ts`);
|
|
886
|
+
const exists = await fileExists(dtsPath);
|
|
887
|
+
if (exists) {
|
|
888
|
+
cleaned.types = `src/${mainEntry}.d.ts`;
|
|
889
|
+
}
|
|
882
890
|
}
|
|
883
891
|
}
|
|
884
892
|
return cleaned;
|
|
@@ -933,8 +941,37 @@ async function build2(cwd, save = false) {
|
|
|
933
941
|
}
|
|
934
942
|
}
|
|
935
943
|
const binDir = Path3.join(cwd, "bin");
|
|
936
|
-
const
|
|
944
|
+
const allSrcFiles = await findEntrypoints(srcDir);
|
|
937
945
|
const binEntries = await findBinEntrypoints(binDir);
|
|
946
|
+
let srcEntries;
|
|
947
|
+
if (pkg.exports && typeof pkg.exports === "object") {
|
|
948
|
+
const srcExportKeys = Object.keys(pkg.exports).filter((key) => {
|
|
949
|
+
if (key === "." || key === "./package.json")
|
|
950
|
+
return false;
|
|
951
|
+
const val = pkg.exports[key];
|
|
952
|
+
if (typeof val === "string")
|
|
953
|
+
return val.includes("/src/");
|
|
954
|
+
if (typeof val === "object" && val !== null) {
|
|
955
|
+
return Object.values(val).some((v) => typeof v === "string" && v.includes("/src/"));
|
|
956
|
+
}
|
|
957
|
+
return false;
|
|
958
|
+
});
|
|
959
|
+
const dotExport = pkg.exports["."];
|
|
960
|
+
let hasCustomMain = false;
|
|
961
|
+
if (dotExport) {
|
|
962
|
+
const importPath = typeof dotExport === "string" ? dotExport : dotExport.import || dotExport.default;
|
|
963
|
+
if (importPath && !importPath.includes("/index.")) {
|
|
964
|
+
hasCustomMain = true;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
if (srcExportKeys.length > 0 || hasCustomMain) {
|
|
968
|
+
srcEntries = allSrcFiles;
|
|
969
|
+
} else {
|
|
970
|
+
srcEntries = allSrcFiles.includes("index") ? ["index"] : allSrcFiles;
|
|
971
|
+
}
|
|
972
|
+
} else {
|
|
973
|
+
srcEntries = allSrcFiles;
|
|
974
|
+
}
|
|
938
975
|
const allBinEntries = binEntries.map((entry) => ({ name: entry, source: "top-level" }));
|
|
939
976
|
const entries = [
|
|
940
977
|
...srcEntries,
|
|
@@ -1043,6 +1080,8 @@ async function build2(cwd, save = false) {
|
|
|
1043
1080
|
format: "esm",
|
|
1044
1081
|
outExtension: { ".js": ".js" },
|
|
1045
1082
|
bundle: true,
|
|
1083
|
+
splitting: true,
|
|
1084
|
+
// Enable code splitting for dynamic imports
|
|
1046
1085
|
minify: false,
|
|
1047
1086
|
sourcemap: false,
|
|
1048
1087
|
external: externalDeps,
|
|
@@ -1069,6 +1108,20 @@ async function build2(cwd, save = false) {
|
|
|
1069
1108
|
})] : []
|
|
1070
1109
|
]
|
|
1071
1110
|
});
|
|
1111
|
+
if (options.formats.cjs) {
|
|
1112
|
+
const distFiles = await FS3.readdir(distDir);
|
|
1113
|
+
const chunkFiles = distFiles.filter(
|
|
1114
|
+
(f) => f.endsWith(".js") && !f.endsWith(".d.ts") && (f.startsWith("chunk-") || f.includes("-") && !f.startsWith("package"))
|
|
1115
|
+
);
|
|
1116
|
+
if (chunkFiles.length > 0) {
|
|
1117
|
+
console.info(`
|
|
1118
|
+
\u26A0\uFE0F Code splitting detected - CommonJS build will bundle dynamic imports inline`);
|
|
1119
|
+
console.info(` ESM build: ${chunkFiles.length} chunk file(s) created for lazy loading`);
|
|
1120
|
+
console.info(` CJS build: Dynamic imports bundled inline (no chunks)`);
|
|
1121
|
+
console.info(` To get code splitting benefits, use ESM imports or remove "main" field
|
|
1122
|
+
`);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1072
1125
|
if (binEntryPoints.length > 0) {
|
|
1073
1126
|
const runtimeBanner = generateRuntimeBanner(pkg);
|
|
1074
1127
|
for (const binEntryName of binEntryNames) {
|