@savvy-web/rslib-builder 0.12.2 → 0.13.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 +23 -13
- package/index.d.ts +48 -2
- package/index.js +261 -76
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -10,23 +10,33 @@ resolution automatically.
|
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
- **Zero-Config Entry Detection** - Auto-discovers
|
|
14
|
-
|
|
15
|
-
- **10-100x Faster Types** - Uses tsgo (native
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
- **
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
- **Zero-Config Entry Detection** - Auto-discovers
|
|
14
|
+
entry points from package.json exports
|
|
15
|
+
- **10-100x Faster Types** - Uses tsgo (native
|
|
16
|
+
TypeScript compiler) with API Extractor for
|
|
17
|
+
bundled, clean public API declarations
|
|
18
|
+
- **Production-Ready Transforms** - Converts `.ts`
|
|
19
|
+
exports to `.js`, resolves PNPM `catalog:` and
|
|
20
|
+
`workspace:` references, generates files array
|
|
21
|
+
- **Bundled or Bundleless** - Choose single-file
|
|
22
|
+
bundles per entry or bundleless mode that
|
|
23
|
+
preserves your source file structure
|
|
24
|
+
- **Multi-Target Builds** - Separate dev (with
|
|
25
|
+
source maps) and npm (optimized) outputs from a
|
|
26
|
+
single configuration
|
|
27
|
+
- **Flexible Formats** - ESM, CJS, or dual format
|
|
28
|
+
output with per-entry format overrides
|
|
29
|
+
- **TSDoc Validation** - Pre-build documentation
|
|
30
|
+
validation with automatic public API discovery
|
|
25
31
|
|
|
26
32
|
## Installation
|
|
27
33
|
|
|
28
34
|
```bash
|
|
29
|
-
npm install --save-dev
|
|
35
|
+
npm install --save-dev \
|
|
36
|
+
@savvy-web/rslib-builder \
|
|
37
|
+
@rslib/core \
|
|
38
|
+
@microsoft/api-extractor \
|
|
39
|
+
@typescript/native-preview
|
|
30
40
|
```
|
|
31
41
|
|
|
32
42
|
## Quick Start
|
package/index.d.ts
CHANGED
|
@@ -1238,9 +1238,42 @@ export declare interface NodeLibraryBuilderOptions {
|
|
|
1238
1238
|
* - `"esm"` → `"type": "module"`
|
|
1239
1239
|
* - `"cjs"` → `"type": "commonjs"`
|
|
1240
1240
|
*
|
|
1241
|
+
* When an array is provided, the package is built in both formats.
|
|
1242
|
+
* The first format in the array is the primary format (determines `type` field).
|
|
1243
|
+
* Each format outputs to its own subdirectory (`dist/{target}/esm/`, `dist/{target}/cjs/`).
|
|
1244
|
+
*
|
|
1241
1245
|
* @defaultValue `"esm"`
|
|
1246
|
+
*
|
|
1247
|
+
* @example
|
|
1248
|
+
* Dual format output:
|
|
1249
|
+
* ```typescript
|
|
1250
|
+
* NodeLibraryBuilder.create({
|
|
1251
|
+
* format: ['esm', 'cjs'],
|
|
1252
|
+
* })
|
|
1253
|
+
* ```
|
|
1242
1254
|
*/
|
|
1243
|
-
format?: LibraryFormat;
|
|
1255
|
+
format?: LibraryFormat | LibraryFormat[];
|
|
1256
|
+
/**
|
|
1257
|
+
* Per-entry format overrides.
|
|
1258
|
+
* Maps export paths (matching package.json exports keys like `"./markdownlint"`)
|
|
1259
|
+
* to a specific format. Entries not listed inherit the top-level `format`.
|
|
1260
|
+
*
|
|
1261
|
+
* @remarks
|
|
1262
|
+
* When both `entryFormats` and array `format` are used, `entryFormats` takes precedence.
|
|
1263
|
+
* An entry with a specific format override will only be built in that format,
|
|
1264
|
+
* even if the global format is dual.
|
|
1265
|
+
*
|
|
1266
|
+
* @example
|
|
1267
|
+
* ```typescript
|
|
1268
|
+
* NodeLibraryBuilder.create({
|
|
1269
|
+
* format: 'esm',
|
|
1270
|
+
* entryFormats: {
|
|
1271
|
+
* './markdownlint': 'cjs',
|
|
1272
|
+
* },
|
|
1273
|
+
* })
|
|
1274
|
+
* ```
|
|
1275
|
+
*/
|
|
1276
|
+
entryFormats?: Record<string, LibraryFormat>;
|
|
1244
1277
|
/**
|
|
1245
1278
|
* Additional entry points bundled with custom output names.
|
|
1246
1279
|
* These entries bypass type generation and package.json exports
|
|
@@ -2081,6 +2114,18 @@ export declare interface PackageJsonTransformPluginOptions {
|
|
|
2081
2114
|
* ```
|
|
2082
2115
|
*/
|
|
2083
2116
|
transform?: (pkg: PackageJson) => PackageJson;
|
|
2117
|
+
/**
|
|
2118
|
+
* Per-entry format overrides for export conditions.
|
|
2119
|
+
* Maps export paths to their format (e.g., `{ "./markdownlint": "cjs" }`).
|
|
2120
|
+
* Entries not listed inherit the top-level `format`.
|
|
2121
|
+
*/
|
|
2122
|
+
entryFormats?: Record<string, LibraryFormat>;
|
|
2123
|
+
/**
|
|
2124
|
+
* Whether the build uses dual format (both ESM and CJS).
|
|
2125
|
+
* When true, exports get both `import` and `require` conditions
|
|
2126
|
+
* with format directory prefixes.
|
|
2127
|
+
*/
|
|
2128
|
+
dualFormat?: boolean;
|
|
2084
2129
|
}
|
|
2085
2130
|
|
|
2086
2131
|
/**
|
|
@@ -3124,7 +3169,8 @@ export declare class TsconfigResolver {
|
|
|
3124
3169
|
source: string;
|
|
3125
3170
|
/**
|
|
3126
3171
|
* Output format for this entry.
|
|
3127
|
-
* If not specified, inherits from
|
|
3172
|
+
* If not specified, inherits from the primary format
|
|
3173
|
+
* (first element when `format` is an array, or the single format value).
|
|
3128
3174
|
*/
|
|
3129
3175
|
format?: LibraryFormat;
|
|
3130
3176
|
}
|
package/index.js
CHANGED
|
@@ -465,28 +465,24 @@ const AutoEntryPlugin = (options)=>{
|
|
|
465
465
|
tracedEntries[relPath] = `./${relPath}`;
|
|
466
466
|
}
|
|
467
467
|
log.global.info(`bundleless: traced ${Object.keys(tracedEntries).length} files from ${entrySourcePaths.length} entries`);
|
|
468
|
-
|
|
469
|
-
lib.source = {
|
|
470
|
-
...lib.source,
|
|
471
|
-
entry: tracedEntries
|
|
472
|
-
};
|
|
473
|
-
});
|
|
474
|
-
} else environments.forEach(([_env, lib])=>{
|
|
475
|
-
lib.source = {
|
|
468
|
+
for (const [, lib] of environments)lib.source = {
|
|
476
469
|
...lib.source,
|
|
477
|
-
entry:
|
|
478
|
-
...lib.source?.entry,
|
|
479
|
-
...entries
|
|
480
|
-
}
|
|
470
|
+
entry: tracedEntries
|
|
481
471
|
};
|
|
482
|
-
})
|
|
472
|
+
} else for (const [, lib] of environments)lib.source = {
|
|
473
|
+
...lib.source,
|
|
474
|
+
entry: {
|
|
475
|
+
...lib.source?.entry,
|
|
476
|
+
...entries
|
|
477
|
+
}
|
|
478
|
+
};
|
|
483
479
|
const state = buildStateMap.get(api);
|
|
484
480
|
if (state && !state.hasLoggedEntries) {
|
|
485
481
|
state.hasLoggedEntries = true;
|
|
486
|
-
|
|
482
|
+
for (const [env] of environments){
|
|
487
483
|
const log = createEnvLogger(env);
|
|
488
484
|
log.entries("auto-detected entries", entries);
|
|
489
|
-
}
|
|
485
|
+
}
|
|
490
486
|
}
|
|
491
487
|
}
|
|
492
488
|
} catch (error) {
|
|
@@ -977,8 +973,7 @@ class TsDocConfigBuilder {
|
|
|
977
973
|
}));
|
|
978
974
|
}
|
|
979
975
|
static shouldPersist(persistConfig) {
|
|
980
|
-
|
|
981
|
-
return true;
|
|
976
|
+
return false !== persistConfig;
|
|
982
977
|
}
|
|
983
978
|
static getConfigPath(persistConfig, cwd) {
|
|
984
979
|
if ("string" == typeof persistConfig) return isAbsolute(persistConfig) ? persistConfig : join(cwd, persistConfig);
|
|
@@ -1156,7 +1151,8 @@ async function bundleDtsFiles(options) {
|
|
|
1156
1151
|
} catch {}
|
|
1157
1152
|
}
|
|
1158
1153
|
}
|
|
1159
|
-
const
|
|
1154
|
+
const dtsExtension = "cjs" === options.format ? ".d.cts" : ".d.ts";
|
|
1155
|
+
const outputFileName = `${entryName}${dtsExtension}`;
|
|
1160
1156
|
const tempBundledPath = join(tempOutputDir, outputFileName);
|
|
1161
1157
|
const isMainEntry = "index" === entryName || 1 === entryPoints.size;
|
|
1162
1158
|
const generateApiModel = apiModelEnabled;
|
|
@@ -1293,7 +1289,7 @@ async function bundleDtsFiles(options) {
|
|
|
1293
1289
|
};
|
|
1294
1290
|
}
|
|
1295
1291
|
function stripSourceMapComment(content) {
|
|
1296
|
-
return content.replace(/\/\/# sourceMappingURL=\S+\.d\.ts\.map\s*$/gm, "").trim();
|
|
1292
|
+
return content.replace(/\/\/# sourceMappingURL=\S+\.d\.c?ts\.map\s*$/gm, "").trim();
|
|
1297
1293
|
}
|
|
1298
1294
|
function mergeApiModels(options) {
|
|
1299
1295
|
const { perEntryModels, packageName, exportPaths } = options;
|
|
@@ -1573,6 +1569,9 @@ function runTsgo(options) {
|
|
|
1573
1569
|
},
|
|
1574
1570
|
...void 0 !== options.apiModel && {
|
|
1575
1571
|
apiModel: options.apiModel
|
|
1572
|
+
},
|
|
1573
|
+
...options.format && {
|
|
1574
|
+
format: options.format
|
|
1576
1575
|
}
|
|
1577
1576
|
});
|
|
1578
1577
|
let apiModelPath;
|
|
@@ -1593,10 +1592,11 @@ function runTsgo(options) {
|
|
|
1593
1592
|
await writeFile(mergedPath, JSON.stringify(mergedModel, null, 2), "utf-8");
|
|
1594
1593
|
apiModelPath = mergedPath;
|
|
1595
1594
|
}
|
|
1595
|
+
const bundledDtsExtension = "cjs" === options.format ? ".d.cts" : ".d.ts";
|
|
1596
1596
|
if (options.bundle) {
|
|
1597
1597
|
let emittedCount = 0;
|
|
1598
1598
|
for (const [entryName, tempBundledPath] of bundledFiles){
|
|
1599
|
-
const bundledFileName = `${entryName}
|
|
1599
|
+
const bundledFileName = `${entryName}${bundledDtsExtension}`;
|
|
1600
1600
|
let content = await readFile(tempBundledPath, "utf-8");
|
|
1601
1601
|
content = stripSourceMapComment(content);
|
|
1602
1602
|
const source = new context.sources.OriginalSource(content, bundledFileName);
|
|
@@ -1653,7 +1653,7 @@ function runTsgo(options) {
|
|
|
1653
1653
|
core_logger.info(`${picocolors.dim(`[${envId}]`)} Emitted resolved tsconfig: tsconfig.json (excluded from npm publish)`);
|
|
1654
1654
|
}
|
|
1655
1655
|
if (options.bundle) for (const [entryName] of bundledFiles){
|
|
1656
|
-
const bundledFileName = `${entryName}
|
|
1656
|
+
const bundledFileName = `${entryName}${bundledDtsExtension}`;
|
|
1657
1657
|
const mapFileName = `${bundledFileName}.map`;
|
|
1658
1658
|
for (const file of dtsFiles){
|
|
1659
1659
|
if (file.relativePath.endsWith(".d.ts.map")) continue;
|
|
@@ -1679,7 +1679,7 @@ function runTsgo(options) {
|
|
|
1679
1679
|
stage: "summarize"
|
|
1680
1680
|
}, async (compiler)=>{
|
|
1681
1681
|
const assetsToDelete = [];
|
|
1682
|
-
for(const assetName in compiler.compilation.assets)if (assetName.endsWith(".d.ts")) {
|
|
1682
|
+
for(const assetName in compiler.compilation.assets)if (assetName.endsWith(".d.ts") || assetName.endsWith(".d.cts")) {
|
|
1683
1683
|
const asset = compiler.compilation.assets[assetName];
|
|
1684
1684
|
const content = asset.source().toString();
|
|
1685
1685
|
const strippedContent = stripSourceMapComment(content);
|
|
@@ -1687,7 +1687,7 @@ function runTsgo(options) {
|
|
|
1687
1687
|
const source = new compiler.sources.OriginalSource(strippedContent, assetName);
|
|
1688
1688
|
compiler.compilation.assets[assetName] = source;
|
|
1689
1689
|
}
|
|
1690
|
-
} else if (assetName.endsWith(".d.ts.map")) assetsToDelete.push(assetName);
|
|
1690
|
+
} else if (assetName.endsWith(".d.ts.map") || assetName.endsWith(".d.cts.map")) assetsToDelete.push(assetName);
|
|
1691
1691
|
for (const assetName of assetsToDelete)delete compiler.compilation.assets[assetName];
|
|
1692
1692
|
});
|
|
1693
1693
|
api.onCloseBuild(async ()=>{
|
|
@@ -2118,7 +2118,7 @@ function createTypePath(jsPath, collapseIndex = true) {
|
|
|
2118
2118
|
if (jsPath.endsWith(".js")) return `${jsPath.slice(0, -3)}.d.ts`;
|
|
2119
2119
|
return `${jsPath}.d.ts`;
|
|
2120
2120
|
}
|
|
2121
|
-
function transformPackageBin(bin
|
|
2121
|
+
function transformPackageBin(bin) {
|
|
2122
2122
|
if ("string" == typeof bin) {
|
|
2123
2123
|
if (bin.endsWith(".ts") || bin.endsWith(".tsx")) return "./bin/cli.js";
|
|
2124
2124
|
return bin;
|
|
@@ -2184,7 +2184,7 @@ function applyRslibTransformations(packageJson, originalPackageJson, processTSEx
|
|
|
2184
2184
|
};
|
|
2185
2185
|
if (processedManifest.exports) processedManifest.exports = transformPackageExports(processedManifest.exports, processTSExports, void 0, entrypoints, exportToOutputMap, bundle ?? false);
|
|
2186
2186
|
if (processedManifest.bin) {
|
|
2187
|
-
const transformedBin = transformPackageBin(processedManifest.bin
|
|
2187
|
+
const transformedBin = transformPackageBin(processedManifest.bin);
|
|
2188
2188
|
if (transformedBin) processedManifest.bin = transformedBin;
|
|
2189
2189
|
}
|
|
2190
2190
|
if (originalPackageJson.typesVersions) {
|
|
@@ -2207,15 +2207,51 @@ async function applyPnpmTransformations(packageJson, dir = process.cwd(), catalo
|
|
|
2207
2207
|
const workspaceCatalog = catalog ?? createWorkspaceCatalog();
|
|
2208
2208
|
return workspaceCatalog.resolvePackageJson(packageJson, dir);
|
|
2209
2209
|
}
|
|
2210
|
-
async function buildPackageJson(packageJson, isProduction = false, processTSExports = true, entrypoints, exportToOutputMap, bundle, transform) {
|
|
2210
|
+
async function buildPackageJson(packageJson, isProduction = false, processTSExports = true, entrypoints, exportToOutputMap, bundle, transform, formatConditions) {
|
|
2211
2211
|
let result;
|
|
2212
2212
|
if (isProduction) {
|
|
2213
2213
|
const pnpmTransformed = await applyPnpmTransformations(packageJson);
|
|
2214
2214
|
result = applyRslibTransformations(pnpmTransformed, packageJson, processTSExports, entrypoints, exportToOutputMap, bundle);
|
|
2215
2215
|
} else result = applyRslibTransformations(packageJson, packageJson, processTSExports, entrypoints, exportToOutputMap, bundle);
|
|
2216
|
+
if (formatConditions && result.exports) result.exports = applyFormatConditions(result.exports, formatConditions);
|
|
2216
2217
|
if (transform) result = transform(result);
|
|
2217
2218
|
return result;
|
|
2218
2219
|
}
|
|
2220
|
+
function toCjsPath(jsPath) {
|
|
2221
|
+
if (jsPath.endsWith(".js")) return `${jsPath.slice(0, -3)}.cjs`;
|
|
2222
|
+
return jsPath;
|
|
2223
|
+
}
|
|
2224
|
+
function toCtsTypePath(dtsPath) {
|
|
2225
|
+
if (dtsPath.endsWith(".d.ts")) return `${dtsPath.slice(0, -5)}.d.cts`;
|
|
2226
|
+
return dtsPath;
|
|
2227
|
+
}
|
|
2228
|
+
function addFormatDirPrefix(path, format) {
|
|
2229
|
+
if (path.startsWith("./")) return `./${format}/${path.slice(2)}`;
|
|
2230
|
+
return `./${format}/${path}`;
|
|
2231
|
+
}
|
|
2232
|
+
function applyFormatConditions(exports, options) {
|
|
2233
|
+
if (!exports || "object" != typeof exports || Array.isArray(exports)) return exports;
|
|
2234
|
+
const { format = "esm", entryFormats, dualFormat } = options;
|
|
2235
|
+
const result = {};
|
|
2236
|
+
for (const [key, value] of Object.entries(exports))if (value && "object" == typeof value && !Array.isArray(value)) {
|
|
2237
|
+
const condObj = value;
|
|
2238
|
+
if ("string" == typeof condObj.types && "string" == typeof condObj.import) {
|
|
2239
|
+
const entryFormat = entryFormats?.[key] ?? format;
|
|
2240
|
+
const hasExplicitOverride = void 0 !== entryFormats && key in entryFormats;
|
|
2241
|
+
if (dualFormat && !hasExplicitOverride) result[key] = {
|
|
2242
|
+
types: addFormatDirPrefix(condObj.types, "esm"),
|
|
2243
|
+
import: addFormatDirPrefix(condObj.import, "esm"),
|
|
2244
|
+
require: addFormatDirPrefix(toCjsPath(condObj.import), "cjs")
|
|
2245
|
+
};
|
|
2246
|
+
else if ("cjs" === entryFormat) result[key] = {
|
|
2247
|
+
types: toCtsTypePath(condObj.types),
|
|
2248
|
+
require: toCjsPath(condObj.import)
|
|
2249
|
+
};
|
|
2250
|
+
else result[key] = value;
|
|
2251
|
+
} else result[key] = value;
|
|
2252
|
+
} else result[key] = value;
|
|
2253
|
+
return result;
|
|
2254
|
+
}
|
|
2219
2255
|
const PackageJsonTransformPlugin = (options = {})=>({
|
|
2220
2256
|
name: "package-json-processor",
|
|
2221
2257
|
setup (api) {
|
|
@@ -2243,7 +2279,19 @@ const PackageJsonTransformPlugin = (options = {})=>({
|
|
|
2243
2279
|
const isProduction = "dev" !== envId;
|
|
2244
2280
|
const entrypoints = api.useExposed("entrypoints");
|
|
2245
2281
|
const exportToOutputMap = api.useExposed("exportToOutputMap");
|
|
2246
|
-
|
|
2282
|
+
let formatConditions;
|
|
2283
|
+
if (options.entryFormats || options.dualFormat) formatConditions = {
|
|
2284
|
+
...options.format && {
|
|
2285
|
+
format: options.format
|
|
2286
|
+
},
|
|
2287
|
+
...options.entryFormats && {
|
|
2288
|
+
entryFormats: options.entryFormats
|
|
2289
|
+
},
|
|
2290
|
+
...options.dualFormat && {
|
|
2291
|
+
dualFormat: options.dualFormat
|
|
2292
|
+
}
|
|
2293
|
+
};
|
|
2294
|
+
const processedPackageJson = await buildPackageJson(packageJson.data, isProduction, options.processTSExports, entrypoints, exportToOutputMap, options.bundle, options.transform, formatConditions);
|
|
2247
2295
|
packageJson.data = processedPackageJson;
|
|
2248
2296
|
if (options.forcePrivate) packageJson.data.private = true;
|
|
2249
2297
|
if (options.format) packageJson.data.type = "esm" === options.format ? "module" : "commonjs";
|
|
@@ -2251,7 +2299,7 @@ const PackageJsonTransformPlugin = (options = {})=>({
|
|
|
2251
2299
|
if (useRollupTypes && packageJson.data.exports && "object" == typeof packageJson.data.exports) {
|
|
2252
2300
|
const exports = packageJson.data.exports;
|
|
2253
2301
|
delete exports["./api-extractor"];
|
|
2254
|
-
for (const
|
|
2302
|
+
for (const value of Object.values(exports))if (value && "object" == typeof value && "types" in value) value.types = "./index.d.ts";
|
|
2255
2303
|
}
|
|
2256
2304
|
packageJson.update();
|
|
2257
2305
|
});
|
|
@@ -2684,6 +2732,9 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2684
2732
|
},
|
|
2685
2733
|
...void 0 !== options.virtualEntries && {
|
|
2686
2734
|
virtualEntries: options.virtualEntries
|
|
2735
|
+
},
|
|
2736
|
+
...void 0 !== options.entryFormats && {
|
|
2737
|
+
entryFormats: options.entryFormats
|
|
2687
2738
|
}
|
|
2688
2739
|
};
|
|
2689
2740
|
return merged;
|
|
@@ -2698,6 +2749,7 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2698
2749
|
}
|
|
2699
2750
|
static async createSingleTarget(target, opts) {
|
|
2700
2751
|
const options = NodeLibraryBuilder.mergeOptions(opts);
|
|
2752
|
+
const bundle = options.bundle ?? true;
|
|
2701
2753
|
const VERSION = await packageJsonVersion();
|
|
2702
2754
|
const plugins = [];
|
|
2703
2755
|
const apiModelConfig = "object" == typeof options.apiModel ? options.apiModel : {};
|
|
@@ -2714,7 +2766,7 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2714
2766
|
};
|
|
2715
2767
|
plugins.push(TsDocLintPlugin({
|
|
2716
2768
|
...lintOptions,
|
|
2717
|
-
|
|
2769
|
+
...!bundle && {
|
|
2718
2770
|
perEntry: true
|
|
2719
2771
|
}
|
|
2720
2772
|
}));
|
|
@@ -2723,7 +2775,7 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2723
2775
|
...null != options.exportsAsIndexes && {
|
|
2724
2776
|
exportsAsIndexes: options.exportsAsIndexes
|
|
2725
2777
|
},
|
|
2726
|
-
|
|
2778
|
+
...!bundle && {
|
|
2727
2779
|
bundleless: true
|
|
2728
2780
|
}
|
|
2729
2781
|
}));
|
|
@@ -2732,27 +2784,31 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2732
2784
|
target,
|
|
2733
2785
|
pkg
|
|
2734
2786
|
}) : void 0;
|
|
2735
|
-
const
|
|
2736
|
-
const
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
}
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
}
|
|
2752
|
-
|
|
2753
|
-
|
|
2787
|
+
const formatOption = options.format ?? "esm";
|
|
2788
|
+
const formats = Array.isArray(formatOption) ? formatOption : [
|
|
2789
|
+
formatOption
|
|
2790
|
+
];
|
|
2791
|
+
const primaryFormat = formats[0] ?? "esm";
|
|
2792
|
+
const isDualFormat = formats.length > 1;
|
|
2793
|
+
const entryFormats = options.entryFormats;
|
|
2794
|
+
const hasFormatOverrides = void 0 !== entryFormats && Object.keys(entryFormats).length > 0;
|
|
2795
|
+
const collapseIndex = bundle || !(options.exportsAsIndexes ?? false);
|
|
2796
|
+
const baseOutputDir = `dist/${target}`;
|
|
2797
|
+
const outputDir = isDualFormat ? `${baseOutputDir}/${primaryFormat}` : baseOutputDir;
|
|
2798
|
+
const apiModelForTarget = "npm" === target ? options.apiModel : void 0;
|
|
2799
|
+
const sourceMap = "dev" === target;
|
|
2800
|
+
const externalsConfig = options.externals && options.externals.length > 0 ? {
|
|
2801
|
+
externals: options.externals
|
|
2802
|
+
} : {};
|
|
2803
|
+
const bundlelessOutput = bundle ? {} : {
|
|
2804
|
+
legalComments: "inline"
|
|
2805
|
+
};
|
|
2806
|
+
const sourceDefine = {
|
|
2807
|
+
"process.env.__PACKAGE_VERSION__": JSON.stringify(VERSION),
|
|
2808
|
+
...options.define
|
|
2809
|
+
};
|
|
2754
2810
|
let entry = options.entry;
|
|
2755
|
-
if (
|
|
2811
|
+
if (!bundle && !entry) {
|
|
2756
2812
|
const cwd = process.cwd();
|
|
2757
2813
|
const packageJsonPath = join(cwd, "package.json");
|
|
2758
2814
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
@@ -2768,49 +2824,65 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2768
2824
|
}
|
|
2769
2825
|
entry = tracedEntries;
|
|
2770
2826
|
}
|
|
2771
|
-
|
|
2827
|
+
plugins.push(PackageJsonTransformPlugin({
|
|
2828
|
+
forcePrivate: "dev" === target,
|
|
2829
|
+
bundle: collapseIndex,
|
|
2830
|
+
target,
|
|
2831
|
+
format: primaryFormat,
|
|
2832
|
+
...transformFn && {
|
|
2833
|
+
transform: transformFn
|
|
2834
|
+
},
|
|
2835
|
+
...hasFormatOverrides && {
|
|
2836
|
+
entryFormats
|
|
2837
|
+
},
|
|
2838
|
+
...isDualFormat && {
|
|
2839
|
+
dualFormat: true
|
|
2840
|
+
}
|
|
2841
|
+
}));
|
|
2842
|
+
plugins.push(FilesArrayPlugin({
|
|
2843
|
+
target,
|
|
2844
|
+
...options.transformFiles && {
|
|
2845
|
+
transformFiles: options.transformFiles
|
|
2846
|
+
}
|
|
2847
|
+
}));
|
|
2848
|
+
plugins.push(...options.plugins);
|
|
2772
2849
|
plugins.push(DtsPlugin({
|
|
2773
2850
|
...options.tsconfigPath && {
|
|
2774
2851
|
tsconfigPath: options.tsconfigPath
|
|
2775
2852
|
},
|
|
2776
2853
|
abortOnError: true,
|
|
2777
|
-
bundle
|
|
2854
|
+
bundle,
|
|
2778
2855
|
...options.dtsBundledPackages && {
|
|
2779
2856
|
bundledPackages: options.dtsBundledPackages
|
|
2780
2857
|
},
|
|
2781
2858
|
buildTarget: target,
|
|
2782
|
-
format:
|
|
2859
|
+
format: primaryFormat,
|
|
2783
2860
|
...void 0 !== apiModelForTarget && {
|
|
2784
2861
|
apiModel: apiModelForTarget
|
|
2785
2862
|
}
|
|
2786
2863
|
}));
|
|
2787
2864
|
const lib = {
|
|
2788
|
-
id: target,
|
|
2789
|
-
outBase:
|
|
2865
|
+
id: isDualFormat ? `${target}-${primaryFormat}` : target,
|
|
2866
|
+
outBase: bundle ? outputDir : "src",
|
|
2790
2867
|
output: {
|
|
2791
2868
|
target: "node",
|
|
2792
2869
|
module: true,
|
|
2793
2870
|
cleanDistPath: true,
|
|
2794
|
-
sourceMap
|
|
2795
|
-
|
|
2796
|
-
...false === options.bundle && {
|
|
2797
|
-
legalComments: "inline"
|
|
2798
|
-
},
|
|
2871
|
+
sourceMap,
|
|
2872
|
+
...bundlelessOutput,
|
|
2799
2873
|
distPath: {
|
|
2800
2874
|
root: outputDir
|
|
2801
2875
|
},
|
|
2802
2876
|
copy: {
|
|
2803
2877
|
patterns: options.copyPatterns
|
|
2804
2878
|
},
|
|
2805
|
-
...
|
|
2806
|
-
externals: options.externals
|
|
2807
|
-
}
|
|
2879
|
+
...externalsConfig
|
|
2808
2880
|
},
|
|
2809
|
-
format:
|
|
2881
|
+
format: primaryFormat,
|
|
2810
2882
|
experiments: {
|
|
2811
|
-
advancedEsm: "esm" ===
|
|
2883
|
+
advancedEsm: "esm" === primaryFormat
|
|
2812
2884
|
},
|
|
2813
|
-
bundle
|
|
2885
|
+
bundle,
|
|
2814
2886
|
plugins,
|
|
2815
2887
|
source: {
|
|
2816
2888
|
...options.tsconfigPath && {
|
|
@@ -2819,10 +2891,7 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2819
2891
|
...entry && {
|
|
2820
2892
|
entry
|
|
2821
2893
|
},
|
|
2822
|
-
define:
|
|
2823
|
-
"process.env.__PACKAGE_VERSION__": JSON.stringify(VERSION),
|
|
2824
|
-
...options.define
|
|
2825
|
-
}
|
|
2894
|
+
define: sourceDefine
|
|
2826
2895
|
}
|
|
2827
2896
|
};
|
|
2828
2897
|
const hasRegularEntries = void 0 !== options.entry || NodeLibraryBuilder.packageHasExports();
|
|
@@ -2830,11 +2899,129 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2830
2899
|
const hasVirtualEntries = Object.keys(virtualEntries).length > 0;
|
|
2831
2900
|
if (!hasRegularEntries && !hasVirtualEntries) throw new Error("No entry points configured. Provide package.json exports, explicit entry option, or virtualEntries.");
|
|
2832
2901
|
const libConfigs = [];
|
|
2833
|
-
if (hasRegularEntries)
|
|
2902
|
+
if (hasRegularEntries) {
|
|
2903
|
+
libConfigs.push(lib);
|
|
2904
|
+
if (isDualFormat) for (const secondaryFormat of formats.slice(1)){
|
|
2905
|
+
const secondaryOutputDir = `${baseOutputDir}/${secondaryFormat}`;
|
|
2906
|
+
const secondaryPlugins = [
|
|
2907
|
+
FilesArrayPlugin({
|
|
2908
|
+
target
|
|
2909
|
+
}),
|
|
2910
|
+
DtsPlugin({
|
|
2911
|
+
...options.tsconfigPath && {
|
|
2912
|
+
tsconfigPath: options.tsconfigPath
|
|
2913
|
+
},
|
|
2914
|
+
abortOnError: true,
|
|
2915
|
+
bundle,
|
|
2916
|
+
...options.dtsBundledPackages && {
|
|
2917
|
+
bundledPackages: options.dtsBundledPackages
|
|
2918
|
+
},
|
|
2919
|
+
buildTarget: target,
|
|
2920
|
+
format: secondaryFormat
|
|
2921
|
+
})
|
|
2922
|
+
];
|
|
2923
|
+
const secondaryLib = {
|
|
2924
|
+
id: `${target}-${secondaryFormat}`,
|
|
2925
|
+
outBase: bundle ? secondaryOutputDir : "src",
|
|
2926
|
+
output: {
|
|
2927
|
+
target: "node",
|
|
2928
|
+
cleanDistPath: false,
|
|
2929
|
+
sourceMap,
|
|
2930
|
+
...bundlelessOutput,
|
|
2931
|
+
distPath: {
|
|
2932
|
+
root: secondaryOutputDir
|
|
2933
|
+
},
|
|
2934
|
+
...externalsConfig
|
|
2935
|
+
},
|
|
2936
|
+
format: secondaryFormat,
|
|
2937
|
+
experiments: {
|
|
2938
|
+
advancedEsm: "esm" === secondaryFormat
|
|
2939
|
+
},
|
|
2940
|
+
bundle,
|
|
2941
|
+
plugins: secondaryPlugins,
|
|
2942
|
+
source: {
|
|
2943
|
+
...options.tsconfigPath && {
|
|
2944
|
+
tsconfigPath: options.tsconfigPath
|
|
2945
|
+
},
|
|
2946
|
+
...entry && {
|
|
2947
|
+
entry
|
|
2948
|
+
},
|
|
2949
|
+
define: sourceDefine
|
|
2950
|
+
}
|
|
2951
|
+
};
|
|
2952
|
+
libConfigs.push(secondaryLib);
|
|
2953
|
+
}
|
|
2954
|
+
if (hasFormatOverrides && !isDualFormat) {
|
|
2955
|
+
const cwd = process.cwd();
|
|
2956
|
+
const packageJsonPath = join(cwd, "package.json");
|
|
2957
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
2958
|
+
const { entries: extractedEntries, exportPaths } = new EntryExtractor().extract(packageJson);
|
|
2959
|
+
const overridesByFormat = new Map();
|
|
2960
|
+
for (const [entryName, sourcePath] of Object.entries(extractedEntries)){
|
|
2961
|
+
const exportPath = exportPaths[entryName];
|
|
2962
|
+
if (exportPath && entryFormats?.[exportPath] && entryFormats[exportPath] !== primaryFormat) {
|
|
2963
|
+
const overrideFormat = entryFormats[exportPath];
|
|
2964
|
+
let formatEntries = overridesByFormat.get(overrideFormat);
|
|
2965
|
+
if (!formatEntries) {
|
|
2966
|
+
formatEntries = {};
|
|
2967
|
+
overridesByFormat.set(overrideFormat, formatEntries);
|
|
2968
|
+
}
|
|
2969
|
+
formatEntries[entryName] = sourcePath;
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
for (const [overrideFormat, overrideEntries] of overridesByFormat){
|
|
2973
|
+
const overridePlugins = [
|
|
2974
|
+
FilesArrayPlugin({
|
|
2975
|
+
target
|
|
2976
|
+
}),
|
|
2977
|
+
DtsPlugin({
|
|
2978
|
+
...options.tsconfigPath && {
|
|
2979
|
+
tsconfigPath: options.tsconfigPath
|
|
2980
|
+
},
|
|
2981
|
+
abortOnError: true,
|
|
2982
|
+
bundle,
|
|
2983
|
+
...options.dtsBundledPackages && {
|
|
2984
|
+
bundledPackages: options.dtsBundledPackages
|
|
2985
|
+
},
|
|
2986
|
+
buildTarget: target,
|
|
2987
|
+
format: overrideFormat
|
|
2988
|
+
})
|
|
2989
|
+
];
|
|
2990
|
+
const overrideLib = {
|
|
2991
|
+
id: `${target}-${overrideFormat}`,
|
|
2992
|
+
outBase: bundle ? baseOutputDir : "src",
|
|
2993
|
+
output: {
|
|
2994
|
+
target: "node",
|
|
2995
|
+
cleanDistPath: false,
|
|
2996
|
+
sourceMap,
|
|
2997
|
+
...bundlelessOutput,
|
|
2998
|
+
distPath: {
|
|
2999
|
+
root: baseOutputDir
|
|
3000
|
+
},
|
|
3001
|
+
...externalsConfig
|
|
3002
|
+
},
|
|
3003
|
+
format: overrideFormat,
|
|
3004
|
+
experiments: {
|
|
3005
|
+
advancedEsm: "esm" === overrideFormat
|
|
3006
|
+
},
|
|
3007
|
+
bundle,
|
|
3008
|
+
plugins: overridePlugins,
|
|
3009
|
+
source: {
|
|
3010
|
+
entry: overrideEntries,
|
|
3011
|
+
...options.tsconfigPath && {
|
|
3012
|
+
tsconfigPath: options.tsconfigPath
|
|
3013
|
+
},
|
|
3014
|
+
define: sourceDefine
|
|
3015
|
+
}
|
|
3016
|
+
};
|
|
3017
|
+
libConfigs.push(overrideLib);
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
2834
3021
|
if (hasVirtualEntries) {
|
|
2835
3022
|
const virtualByFormat = new Map();
|
|
2836
3023
|
for (const [outputName, config] of Object.entries(virtualEntries)){
|
|
2837
|
-
const entryFormat = config.format ??
|
|
3024
|
+
const entryFormat = config.format ?? primaryFormat;
|
|
2838
3025
|
let formatMap = virtualByFormat.get(entryFormat);
|
|
2839
3026
|
if (!formatMap) {
|
|
2840
3027
|
formatMap = new Map();
|
|
@@ -2855,11 +3042,9 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2855
3042
|
cleanDistPath: false,
|
|
2856
3043
|
sourceMap: false,
|
|
2857
3044
|
distPath: {
|
|
2858
|
-
root:
|
|
3045
|
+
root: baseOutputDir
|
|
2859
3046
|
},
|
|
2860
|
-
...
|
|
2861
|
-
externals: options.externals
|
|
2862
|
-
}
|
|
3047
|
+
...externalsConfig
|
|
2863
3048
|
},
|
|
2864
3049
|
source: {
|
|
2865
3050
|
entry: entryMap
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@savvy-web/rslib-builder",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "RSlib-based build system for Node.js libraries with automatic package.json transformation, TypeScript declaration bundling, and multi-target support",
|
|
6
6
|
"keywords": [
|
|
@@ -63,8 +63,8 @@
|
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"@microsoft/api-extractor": "^7.56.3",
|
|
65
65
|
"@rslib/core": "^0.19.5",
|
|
66
|
-
"@types/node": "^25.2.
|
|
67
|
-
"@typescript/native-preview": "
|
|
66
|
+
"@types/node": "^25.2.3",
|
|
67
|
+
"@typescript/native-preview": "7.0.0-dev.20260210.1",
|
|
68
68
|
"typescript": "^5.9.3"
|
|
69
69
|
},
|
|
70
70
|
"peerDependenciesMeta": {
|