@savvy-web/rslib-builder 0.13.0 → 0.13.1
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 +8 -21
- package/index.d.ts +15 -0
- package/index.js +47 -21
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,30 +4,17 @@
|
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
[](https://nodejs.org)
|
|
6
6
|
|
|
7
|
-
Build modern ESM Node.js libraries with minimal configuration. Handles
|
|
8
|
-
TypeScript declarations, package.json transformations, and PNPM workspace
|
|
9
|
-
resolution automatically.
|
|
7
|
+
Build modern ESM Node.js libraries with minimal configuration. Handles TypeScript declarations, package.json transformations, and PNPM workspace resolution automatically.
|
|
10
8
|
|
|
11
9
|
## Features
|
|
12
10
|
|
|
13
|
-
- **Zero-Config Entry Detection** - Auto-discovers
|
|
14
|
-
|
|
15
|
-
- **
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
- **
|
|
19
|
-
|
|
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
|
|
11
|
+
- **Zero-Config Entry Detection** - Auto-discovers entry points from package.json exports
|
|
12
|
+
- **10-100x Faster Types** - Uses tsgo (native TypeScript compiler) with API Extractor for bundled, clean public API declarations
|
|
13
|
+
- **Production-Ready Transforms** - Converts `.ts` exports to `.js`, resolves PNPM `catalog:` and `workspace:` references, generates files array
|
|
14
|
+
- **Bundled or Bundleless** - Choose single-file bundles per entry or bundleless mode that preserves your source file structure
|
|
15
|
+
- **Multi-Target Builds** - Separate dev (with source maps) and npm (optimized) outputs from a single configuration
|
|
16
|
+
- **Flexible Formats** - ESM, CJS, or dual format output with per-entry format overrides
|
|
17
|
+
- **TSDoc Validation** - Pre-build documentation validation with automatic public API discovery
|
|
31
18
|
|
|
32
19
|
## Installation
|
|
33
20
|
|
package/index.d.ts
CHANGED
|
@@ -421,6 +421,13 @@ export declare interface DtsPluginOptions {
|
|
|
421
421
|
* The API model is excluded from npm publish (not added to `files` array).
|
|
422
422
|
*/
|
|
423
423
|
apiModel?: ApiModelOptions | boolean;
|
|
424
|
+
/**
|
|
425
|
+
* Path prefix for emitted DTS files.
|
|
426
|
+
* Used in dual format builds to place declarations in format subdirectories
|
|
427
|
+
* (e.g., `esm/index.d.ts`, `cjs/index.d.cts`).
|
|
428
|
+
* Metadata files (api.json, tsdoc-metadata.json, tsconfig.json) are NOT prefixed.
|
|
429
|
+
*/
|
|
430
|
+
dtsPathPrefix?: string;
|
|
424
431
|
}
|
|
425
432
|
|
|
426
433
|
/**
|
|
@@ -647,6 +654,14 @@ export declare interface FilesArrayPluginOptions<TTarget extends string = string
|
|
|
647
654
|
* Passed to the `transformFiles` callback to allow target-specific transformations.
|
|
648
655
|
*/
|
|
649
656
|
target: TTarget;
|
|
657
|
+
/**
|
|
658
|
+
* Format directories to include in the files array.
|
|
659
|
+
* Used in dual format builds so npm's `files` field includes
|
|
660
|
+
* format directories (e.g., `["esm", "cjs"]`).
|
|
661
|
+
* Directory names are treated as recursive includes by npm,
|
|
662
|
+
* so individual files under these dirs are filtered out.
|
|
663
|
+
*/
|
|
664
|
+
formatDirs?: string[];
|
|
650
665
|
}
|
|
651
666
|
|
|
652
667
|
/**
|
package/index.js
CHANGED
|
@@ -1502,14 +1502,15 @@ function runTsgo(options) {
|
|
|
1502
1502
|
let outputPath = file.relativePath;
|
|
1503
1503
|
if (outputPath.startsWith("src/")) outputPath = outputPath.slice(4);
|
|
1504
1504
|
if (".d.ts" !== dtsExtension && outputPath.endsWith(".d.ts")) outputPath = outputPath.replace(/\.d\.ts$/, dtsExtension);
|
|
1505
|
-
const
|
|
1505
|
+
const prefixedPath = options.dtsPathPrefix ? `${options.dtsPathPrefix}/${outputPath}` : outputPath;
|
|
1506
|
+
const jsOutputPath = prefixedPath.replace(/\.d\.(ts|mts|cts)$/, ".js");
|
|
1506
1507
|
if (!context.compilation.assets[jsOutputPath]) continue;
|
|
1507
1508
|
let content = await readFile(file.path, "utf-8");
|
|
1508
1509
|
content = stripSourceMapComment(content);
|
|
1509
|
-
const source = new context.sources.OriginalSource(content,
|
|
1510
|
-
context.compilation.emitAsset(
|
|
1510
|
+
const source = new context.sources.OriginalSource(content, prefixedPath);
|
|
1511
|
+
context.compilation.emitAsset(prefixedPath, source);
|
|
1511
1512
|
emittedCount++;
|
|
1512
|
-
if (filesArray &&
|
|
1513
|
+
if (filesArray && prefixedPath.endsWith(".d.ts")) filesArray.add(prefixedPath);
|
|
1513
1514
|
}
|
|
1514
1515
|
core_logger.info(`${picocolors.dim(`[${envId}]`)} Emitted ${emittedCount} declaration file${1 === emittedCount ? "" : "s"} through asset pipeline`);
|
|
1515
1516
|
}
|
|
@@ -1597,12 +1598,13 @@ function runTsgo(options) {
|
|
|
1597
1598
|
let emittedCount = 0;
|
|
1598
1599
|
for (const [entryName, tempBundledPath] of bundledFiles){
|
|
1599
1600
|
const bundledFileName = `${entryName}${bundledDtsExtension}`;
|
|
1601
|
+
const prefixedBundledFileName = options.dtsPathPrefix ? `${options.dtsPathPrefix}/${bundledFileName}` : bundledFileName;
|
|
1600
1602
|
let content = await readFile(tempBundledPath, "utf-8");
|
|
1601
1603
|
content = stripSourceMapComment(content);
|
|
1602
|
-
const source = new context.sources.OriginalSource(content,
|
|
1603
|
-
context.compilation.emitAsset(
|
|
1604
|
+
const source = new context.sources.OriginalSource(content, prefixedBundledFileName);
|
|
1605
|
+
context.compilation.emitAsset(prefixedBundledFileName, source);
|
|
1604
1606
|
emittedCount++;
|
|
1605
|
-
if (filesArray) filesArray.add(
|
|
1607
|
+
if (filesArray) filesArray.add(prefixedBundledFileName);
|
|
1606
1608
|
}
|
|
1607
1609
|
core_logger.info(`${picocolors.dim(`[${envId}]`)} Emitted ${emittedCount} bundled declaration file${1 === emittedCount ? "" : "s"} through asset pipeline`);
|
|
1608
1610
|
}
|
|
@@ -1624,7 +1626,7 @@ function runTsgo(options) {
|
|
|
1624
1626
|
hasTsdocMetadata: !!tsdocMetadataPath,
|
|
1625
1627
|
hasTsconfig: !!state.parsedConfig && !!state.tsconfigPath,
|
|
1626
1628
|
cwd,
|
|
1627
|
-
distPath: `dist/${envId}`
|
|
1629
|
+
distPath: `dist/${options.buildTarget ?? envId}`
|
|
1628
1630
|
});
|
|
1629
1631
|
}
|
|
1630
1632
|
}
|
|
@@ -1654,14 +1656,16 @@ function runTsgo(options) {
|
|
|
1654
1656
|
}
|
|
1655
1657
|
if (options.bundle) for (const [entryName] of bundledFiles){
|
|
1656
1658
|
const bundledFileName = `${entryName}${bundledDtsExtension}`;
|
|
1657
|
-
const
|
|
1659
|
+
const prefixedBundledFileName = options.dtsPathPrefix ? `${options.dtsPathPrefix}/${bundledFileName}` : bundledFileName;
|
|
1660
|
+
const mapFileName = `${prefixedBundledFileName}.map`;
|
|
1658
1661
|
for (const file of dtsFiles){
|
|
1659
1662
|
if (file.relativePath.endsWith(".d.ts.map")) continue;
|
|
1660
1663
|
let outputPath = file.relativePath;
|
|
1661
1664
|
if (outputPath.startsWith("src/")) outputPath = outputPath.slice(4);
|
|
1662
1665
|
if (".d.ts" !== dtsExtension && outputPath.endsWith(".d.ts")) outputPath = outputPath.replace(/\.d\.ts$/, dtsExtension);
|
|
1663
|
-
const
|
|
1664
|
-
|
|
1666
|
+
const prefixedOutputPath = options.dtsPathPrefix ? `${options.dtsPathPrefix}/${outputPath}` : outputPath;
|
|
1667
|
+
const individualMapFileName = `${prefixedOutputPath}.map`;
|
|
1668
|
+
if (context.compilation.assets[individualMapFileName]) delete context.compilation.assets[individualMapFileName];
|
|
1665
1669
|
}
|
|
1666
1670
|
if (context.compilation.assets[mapFileName]) delete context.compilation.assets[mapFileName];
|
|
1667
1671
|
}
|
|
@@ -1830,6 +1834,7 @@ const FilesArrayPlugin = (options)=>({
|
|
|
1830
1834
|
const license = await TextAsset.create(context, "LICENSE", false);
|
|
1831
1835
|
if (license) filesArray.add(license.fileName);
|
|
1832
1836
|
for (const assetName of Object.keys(context.compilation.assets))if (!assetName.endsWith(".map") && !filesArray.has(assetName)) filesArray.add(assetName);
|
|
1837
|
+
if (options?.formatDirs) for (const dir of options.formatDirs)filesArray.add(dir);
|
|
1833
1838
|
if (options?.transformFiles) await options.transformFiles({
|
|
1834
1839
|
compilation: context.compilation,
|
|
1835
1840
|
filesArray,
|
|
@@ -1848,6 +1853,11 @@ const FilesArrayPlugin = (options)=>({
|
|
|
1848
1853
|
...previousFiles,
|
|
1849
1854
|
...Array.from(filesArray)
|
|
1850
1855
|
].sort());
|
|
1856
|
+
if (options?.formatDirs) {
|
|
1857
|
+
for (const file of [
|
|
1858
|
+
...allFiles
|
|
1859
|
+
])if (options.formatDirs.some((dir)=>file.startsWith(`${dir}/`))) allFiles.delete(file);
|
|
1860
|
+
}
|
|
1851
1861
|
if (0 === allFiles.size) delete packageJson.data.files;
|
|
1852
1862
|
else {
|
|
1853
1863
|
const newFiles = new Set([
|
|
@@ -2794,7 +2804,6 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2794
2804
|
const hasFormatOverrides = void 0 !== entryFormats && Object.keys(entryFormats).length > 0;
|
|
2795
2805
|
const collapseIndex = bundle || !(options.exportsAsIndexes ?? false);
|
|
2796
2806
|
const baseOutputDir = `dist/${target}`;
|
|
2797
|
-
const outputDir = isDualFormat ? `${baseOutputDir}/${primaryFormat}` : baseOutputDir;
|
|
2798
2807
|
const apiModelForTarget = "npm" === target ? options.apiModel : void 0;
|
|
2799
2808
|
const sourceMap = "dev" === target;
|
|
2800
2809
|
const externalsConfig = options.externals && options.externals.length > 0 ? {
|
|
@@ -2843,6 +2852,9 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2843
2852
|
target,
|
|
2844
2853
|
...options.transformFiles && {
|
|
2845
2854
|
transformFiles: options.transformFiles
|
|
2855
|
+
},
|
|
2856
|
+
...isDualFormat && {
|
|
2857
|
+
formatDirs: formats
|
|
2846
2858
|
}
|
|
2847
2859
|
}));
|
|
2848
2860
|
plugins.push(...options.plugins);
|
|
@@ -2859,11 +2871,14 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2859
2871
|
format: primaryFormat,
|
|
2860
2872
|
...void 0 !== apiModelForTarget && {
|
|
2861
2873
|
apiModel: apiModelForTarget
|
|
2874
|
+
},
|
|
2875
|
+
...isDualFormat && {
|
|
2876
|
+
dtsPathPrefix: primaryFormat
|
|
2862
2877
|
}
|
|
2863
2878
|
}));
|
|
2864
2879
|
const lib = {
|
|
2865
2880
|
id: isDualFormat ? `${target}-${primaryFormat}` : target,
|
|
2866
|
-
outBase: bundle ?
|
|
2881
|
+
outBase: bundle ? baseOutputDir : "src",
|
|
2867
2882
|
output: {
|
|
2868
2883
|
target: "node",
|
|
2869
2884
|
module: true,
|
|
@@ -2871,7 +2886,10 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2871
2886
|
sourceMap,
|
|
2872
2887
|
...bundlelessOutput,
|
|
2873
2888
|
distPath: {
|
|
2874
|
-
root:
|
|
2889
|
+
root: baseOutputDir,
|
|
2890
|
+
...isDualFormat && {
|
|
2891
|
+
js: primaryFormat
|
|
2892
|
+
}
|
|
2875
2893
|
},
|
|
2876
2894
|
copy: {
|
|
2877
2895
|
patterns: options.copyPatterns
|
|
@@ -2902,11 +2920,17 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2902
2920
|
if (hasRegularEntries) {
|
|
2903
2921
|
libConfigs.push(lib);
|
|
2904
2922
|
if (isDualFormat) for (const secondaryFormat of formats.slice(1)){
|
|
2905
|
-
const secondaryOutputDir = `${baseOutputDir}/${secondaryFormat}`;
|
|
2906
2923
|
const secondaryPlugins = [
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2924
|
+
{
|
|
2925
|
+
name: "strip-metadata-assets",
|
|
2926
|
+
setup (api) {
|
|
2927
|
+
api.processAssets({
|
|
2928
|
+
stage: "additional"
|
|
2929
|
+
}, (context)=>{
|
|
2930
|
+
for (const name of Object.keys(context.compilation.assets))if ("package.json" === name || "README.md" === name || "LICENSE" === name) delete context.compilation.assets[name];
|
|
2931
|
+
});
|
|
2932
|
+
}
|
|
2933
|
+
},
|
|
2910
2934
|
DtsPlugin({
|
|
2911
2935
|
...options.tsconfigPath && {
|
|
2912
2936
|
tsconfigPath: options.tsconfigPath
|
|
@@ -2917,19 +2941,21 @@ const VirtualEntryPlugin = (options)=>{
|
|
|
2917
2941
|
bundledPackages: options.dtsBundledPackages
|
|
2918
2942
|
},
|
|
2919
2943
|
buildTarget: target,
|
|
2920
|
-
format: secondaryFormat
|
|
2944
|
+
format: secondaryFormat,
|
|
2945
|
+
dtsPathPrefix: secondaryFormat
|
|
2921
2946
|
})
|
|
2922
2947
|
];
|
|
2923
2948
|
const secondaryLib = {
|
|
2924
2949
|
id: `${target}-${secondaryFormat}`,
|
|
2925
|
-
outBase: bundle ?
|
|
2950
|
+
outBase: bundle ? baseOutputDir : "src",
|
|
2926
2951
|
output: {
|
|
2927
2952
|
target: "node",
|
|
2928
2953
|
cleanDistPath: false,
|
|
2929
2954
|
sourceMap,
|
|
2930
2955
|
...bundlelessOutput,
|
|
2931
2956
|
distPath: {
|
|
2932
|
-
root:
|
|
2957
|
+
root: baseOutputDir,
|
|
2958
|
+
js: secondaryFormat
|
|
2933
2959
|
},
|
|
2934
2960
|
...externalsConfig
|
|
2935
2961
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@savvy-web/rslib-builder",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.1",
|
|
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": [
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"repository": {
|
|
27
27
|
"type": "git",
|
|
28
|
-
"url": "https://github.com/savvy-web/rslib-builder.git"
|
|
28
|
+
"url": "git+https://github.com/savvy-web/rslib-builder.git"
|
|
29
29
|
},
|
|
30
30
|
"license": "MIT",
|
|
31
31
|
"author": {
|