@b9g/libuild 0.1.15 → 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 +10 -0
- package/package.json +1 -1
- package/src/libuild.cjs +50 -1
- package/src/libuild.js +50 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
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
|
+
|
|
5
15
|
## [0.1.15] - 2025-01-14
|
|
6
16
|
|
|
7
17
|
### 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
|
}
|
|
@@ -215950,8 +215954,37 @@ async function build2(cwd, save = false) {
|
|
|
215950
215954
|
}
|
|
215951
215955
|
}
|
|
215952
215956
|
const binDir = Path3.join(cwd, "bin");
|
|
215953
|
-
const
|
|
215957
|
+
const allSrcFiles = await findEntrypoints(srcDir);
|
|
215954
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
|
+
}
|
|
215955
215988
|
const allBinEntries = binEntries.map((entry) => ({ name: entry, source: "top-level" }));
|
|
215956
215989
|
const entries = [
|
|
215957
215990
|
...srcEntries,
|
|
@@ -216060,6 +216093,8 @@ async function build2(cwd, save = false) {
|
|
|
216060
216093
|
format: "esm",
|
|
216061
216094
|
outExtension: { ".js": ".js" },
|
|
216062
216095
|
bundle: true,
|
|
216096
|
+
splitting: true,
|
|
216097
|
+
// Enable code splitting for dynamic imports
|
|
216063
216098
|
minify: false,
|
|
216064
216099
|
sourcemap: false,
|
|
216065
216100
|
external: externalDeps,
|
|
@@ -216086,6 +216121,20 @@ async function build2(cwd, save = false) {
|
|
|
216086
216121
|
})] : []
|
|
216087
216122
|
]
|
|
216088
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
|
+
}
|
|
216089
216138
|
if (binEntryPoints.length > 0) {
|
|
216090
216139
|
const runtimeBanner = generateRuntimeBanner(pkg);
|
|
216091
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
|
}
|
|
@@ -937,8 +941,37 @@ async function build2(cwd, save = false) {
|
|
|
937
941
|
}
|
|
938
942
|
}
|
|
939
943
|
const binDir = Path3.join(cwd, "bin");
|
|
940
|
-
const
|
|
944
|
+
const allSrcFiles = await findEntrypoints(srcDir);
|
|
941
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
|
+
}
|
|
942
975
|
const allBinEntries = binEntries.map((entry) => ({ name: entry, source: "top-level" }));
|
|
943
976
|
const entries = [
|
|
944
977
|
...srcEntries,
|
|
@@ -1047,6 +1080,8 @@ async function build2(cwd, save = false) {
|
|
|
1047
1080
|
format: "esm",
|
|
1048
1081
|
outExtension: { ".js": ".js" },
|
|
1049
1082
|
bundle: true,
|
|
1083
|
+
splitting: true,
|
|
1084
|
+
// Enable code splitting for dynamic imports
|
|
1050
1085
|
minify: false,
|
|
1051
1086
|
sourcemap: false,
|
|
1052
1087
|
external: externalDeps,
|
|
@@ -1073,6 +1108,20 @@ async function build2(cwd, save = false) {
|
|
|
1073
1108
|
})] : []
|
|
1074
1109
|
]
|
|
1075
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
|
+
}
|
|
1076
1125
|
if (binEntryPoints.length > 0) {
|
|
1077
1126
|
const runtimeBanner = generateRuntimeBanner(pkg);
|
|
1078
1127
|
for (const binEntryName of binEntryNames) {
|