Skip to content

Commit e6f1154

Browse files
authored
feat(cli): replace vite-lib config with direct tsdown integration (#381)
### TL;DR Replaced the Rust-based Vite lib config generation with a Node.js implementation using the `cac` CLI library. ### What changed? - Removed the Rust code that was generating a temporary Vite lib config file - Added a new `lib-bin.ts` file that implements the lib command functionality in Node.js - Updated `resolve-lib.ts` to point to the new Node.js implementation - Added `cac` as a dependency for command-line argument parsing - Created a simple test CLI file to demonstrate `cac` usage ### How to test? 1. Run `vite lib` command with various options 2. Verify that the command correctly processes arguments and passes them to tsdown 3. Check that the lib command correctly reads configuration from vite.config.ts ### Why make this change? This change simplifies the architecture by moving the lib command implementation from Rust to Node.js. Using `cac` for command-line parsing provides better flexibility and maintainability for the CLI interface. The Node.js implementation can directly interact with the tsdown API without needing to generate intermediate configuration files. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Moves `vite lib` to a Node-based implementation and removes the interim Vite config generation. > > - Adds `src/lib-bin.ts` using `cac` to implement `vite lib`, resolving `vite.config.ts`, forwarding flags, and calling `build` from `@voidzero-dev/vite-plus-core/lib` > - Removes Rust `write_vite_lib_config` path; simplifies `cli.rs` to call `lib` without generating `vite-lib.config.js` > - Updates `resolve-lib.ts` to run bundled `lib-bin.js` instead of tsdown’s `run.js` > - Refreshes help/flags and snapshots for `vite lib`; example outputs now show `index.mjs` > - Adds `cac` to workspace and lockfile > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 7a5dbf8. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 7f7bb67 commit e6f1154

11 files changed

Lines changed: 135 additions & 85 deletions

File tree

packages/cli/binding/src/cli.rs

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -419,13 +419,6 @@ pub async fn main<
419419
let workspace = Workspace::partial_load(cwd.clone())?;
420420
let lib_fn =
421421
options.map(|o| o.lib).expect("lib command requires CliOptions to be provided");
422-
let lib_config_path = workspace.cache_path().join("vite-lib.config.js");
423-
if write_vite_lib_config(&cwd, &lib_config_path).await? {
424-
args.extend_from_slice(&[
425-
"--config".to_string(),
426-
lib_config_path.as_path().to_string_lossy().into_owned(),
427-
]);
428-
}
429422
let summary = lib(lib_fn, &workspace, args).await?;
430423
workspace.unload().await?;
431424
summary
@@ -574,42 +567,6 @@ async fn read_vite_config_from_workspace_root<
574567
Ok(None)
575568
}
576569

577-
async fn write_vite_lib_config(
578-
workspace_root: &AbsolutePathBuf,
579-
lib_config_path: &AbsolutePathBuf,
580-
) -> Result<bool, Error> {
581-
let relative_vite_config_path =
582-
lib_config_path.strip_prefix(workspace_root).map_err(|e| Error::InvalidRelativePath {
583-
path: e.stripped_path.into(),
584-
reason: e.invalid_path_data_error.into(),
585-
})?;
586-
if let Some(relative_vite_config_path) = relative_vite_config_path {
587-
let relative_prefix = relative_vite_config_path
588-
.as_path()
589-
.components()
590-
.skip(1)
591-
.map(|_| "..".to_string())
592-
.collect::<Vec<_>>()
593-
.join("/");
594-
write(
595-
&lib_config_path,
596-
format!(
597-
r#"let config
598-
try {{
599-
const viteConfig = await import('{relative_prefix}/vite.config.ts')
600-
config = viteConfig.default.lib
601-
}} catch {{
602-
}}
603-
export default config
604-
"#
605-
),
606-
)
607-
.await?;
608-
return Ok(true);
609-
}
610-
Ok(false)
611-
}
612-
613570
#[cfg(test)]
614571
mod tests {
615572
use clap::Parser;

packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"dependencies": {
2828
"@voidzero-dev/vite-plus-core": "workspace:*",
2929
"@voidzero-dev/vite-plus-test": "workspace:*",
30+
"cac": "catalog:",
3031
"oxfmt": "catalog:",
3132
"oxlint": "catalog:",
3233
"oxlint-tsgolint": "catalog:"

packages/cli/snap-tests/command-helper/snap.txt

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,36 +26,34 @@ Options:
2626
-V, --version Print version
2727

2828
> vite lib -h # lib help message
29-
tsdown/<semver>
29+
vite lib
3030

3131
Usage:
32-
$ tsdown [...files]
32+
$ vite lib [...files]
3333

3434
Commands:
3535
[...files] Bundle files
36-
migrate Migrate from tsup to tsdown
3736

3837
For more info, run any command with the `--help` flag:
39-
$ tsdown --help
40-
$ tsdown migrate --help
38+
$ vite lib --help
4139

4240
Options:
43-
-c, --config <filename> Use a custom config file
4441
--config-loader <loader> Config loader to use: auto, native, unrun (default: auto)
4542
--no-config Disable config file (default: true)
4643
-f, --format <format> Bundle format: esm, cjs, iife, umd (default: esm)
4744
--clean Clean output directory, --no-clean to disable
4845
--external <module> Mark dependencies as external
4946
--minify Minify output
50-
--debug Enable debug mode
51-
--debug-logs [feat] Show debug logs
47+
--devtools Enable devtools integration
48+
--debug [feat] Show debug logs
5249
--target <target> Bundle target, e.g "es2015", "esnext"
5350
-l, --logLevel <level> Set log level: info, warn, error, silent
5451
--fail-on-warn Fail on warnings (default: true)
52+
--no-write Disable writing files to disk, incompatible with watch mode (default: true)
5553
-d, --out-dir <dir> Output directory (default: dist)
5654
--treeshake Tree-shake bundle (default: true)
5755
--sourcemap Generate source map (default: false)
58-
--shims Enable cjs and esm shims (default: false)
56+
--shims Enable cjs and esm shims (default: false)
5957
--platform <platform> Target platform (default: node)
6058
--dts Generate dts files
6159
--publint Enable publint (default: false)
@@ -66,16 +64,17 @@ Options:
6664
--from-vite [vitest] Reuse config from Vite or Vitest
6765
--report Size report (default: true)
6866
--env.* <value> Define compile-time env variables
67+
--env-file <file> Load environment variables from a file, when used together with --env, variables in --env take precedence
68+
--env-prefix <prefix> Prefix for env variables to inject into the bundle (default: VITE_LIB_,TSDOWN_)
6969
--on-success <command> Command to run on success
7070
--copy <dir> Copy files to output dir
7171
--public-dir <dir> Alias for --copy, deprecated
7272
--tsconfig <tsconfig> Set tsconfig path
7373
--unbundle Unbundle mode
7474
-W, --workspace [dir] Enable workspace mode
75-
-F, --filter <pattern> Filter workspace packages, e.g. /regex/ or substring
75+
-F, --filter <pattern> Filter configs (cwd or name), e.g. /pkg-name$/ or pkg-name
7676
--exports Generate export-related metadata for package.json (experimental)
7777
-h, --help Display this message
78-
-v, --version Display version number
7978

8079

8180
> vite fmt -h # fmt help message

packages/cli/snap-tests/command-lib-monorepo/packages/hello/tsdown.config.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
lib: {
3+
entry: 'src/index.ts',
4+
format: ['cjs'],
5+
},
6+
};

packages/cli/snap-tests/command-lib-monorepo/snap.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
> vite run hello#build # should build the library
22
~/packages/hello$ vite lib
3-
ℹ tsdown v<semver> powered by rolldown v<semver>
4-
ℹ Using tsdown config: <cwd>/packages/hello/tsdown.config.ts
53
ℹ entry: src/index.ts
64
ℹ Build start
75
ℹ dist/index.cjs <variable> kB │ gzip: <variable> kB
@@ -28,8 +26,6 @@ index.cjs
2826

2927
> vite run hello#build # should hit cache
3028
~/packages/hello$ vite lib (✓ cache hit, replaying)
31-
ℹ tsdown v<semver> powered by rolldown v<semver>
32-
ℹ Using tsdown config: <cwd>/packages/hello/tsdown.config.ts
3329
ℹ entry: src/index.ts
3430
ℹ Build start
3531
ℹ dist/index.cjs <variable> kB │ gzip: <variable> kB

packages/cli/snap-tests/command-lib/snap.txt

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,32 @@
11
> vite lib -h # should print the help message
2-
tsdown/<semver>
2+
vite lib
33

44
Usage:
5-
$ tsdown [...files]
5+
$ vite lib [...files]
66

77
Commands:
88
[...files] Bundle files
9-
migrate Migrate from tsup to tsdown
109

1110
For more info, run any command with the `--help` flag:
12-
$ tsdown --help
13-
$ tsdown migrate --help
11+
$ vite lib --help
1412

1513
Options:
16-
-c, --config <filename> Use a custom config file
1714
--config-loader <loader> Config loader to use: auto, native, unrun (default: auto)
1815
--no-config Disable config file (default: true)
1916
-f, --format <format> Bundle format: esm, cjs, iife, umd (default: esm)
2017
--clean Clean output directory, --no-clean to disable
2118
--external <module> Mark dependencies as external
2219
--minify Minify output
23-
--debug Enable debug mode
24-
--debug-logs [feat] Show debug logs
20+
--devtools Enable devtools integration
21+
--debug [feat] Show debug logs
2522
--target <target> Bundle target, e.g "es2015", "esnext"
2623
-l, --logLevel <level> Set log level: info, warn, error, silent
2724
--fail-on-warn Fail on warnings (default: true)
25+
--no-write Disable writing files to disk, incompatible with watch mode (default: true)
2826
-d, --out-dir <dir> Output directory (default: dist)
2927
--treeshake Tree-shake bundle (default: true)
3028
--sourcemap Generate source map (default: false)
31-
--shims Enable cjs and esm shims (default: false)
29+
--shims Enable cjs and esm shims (default: false)
3230
--platform <platform> Target platform (default: node)
3331
--dts Generate dts files
3432
--publint Enable publint (default: false)
@@ -39,21 +37,20 @@ Options:
3937
--from-vite [vitest] Reuse config from Vite or Vitest
4038
--report Size report (default: true)
4139
--env.* <value> Define compile-time env variables
40+
--env-file <file> Load environment variables from a file, when used together with --env, variables in --env take precedence
41+
--env-prefix <prefix> Prefix for env variables to inject into the bundle (default: VITE_LIB_,TSDOWN_)
4242
--on-success <command> Command to run on success
4343
--copy <dir> Copy files to output dir
4444
--public-dir <dir> Alias for --copy, deprecated
4545
--tsconfig <tsconfig> Set tsconfig path
4646
--unbundle Unbundle mode
4747
-W, --workspace [dir] Enable workspace mode
48-
-F, --filter <pattern> Filter workspace packages, e.g. /regex/ or substring
48+
-F, --filter <pattern> Filter configs (cwd or name), e.g. /pkg-name$/ or pkg-name
4949
--exports Generate export-related metadata for package.json (experimental)
5050
-h, --help Display this message
51-
-v, --version Display version number
5251

5352

5453
> vite lib src/index.ts # should build the library
55-
ℹ tsdown v<semver> powered by rolldown v<semver>
56-
ℹ Using tsdown config: <cwd>/node_modules/.vite/task-cache/vite-lib.config.js
5754
ℹ entry: src/index.ts
5855
ℹ Build start
5956
ℹ dist/index.mjs <variable> kB │ gzip: <variable> kB
@@ -66,8 +63,6 @@ index.mjs
6663

6764
> vite lib src/index.ts # should hit cache
6865
✓ cache hit, replaying
69-
ℹ tsdown v<semver> powered by rolldown v<semver>
70-
ℹ Using tsdown config: <cwd>/node_modules/.vite/task-cache/vite-lib.config.js
7166
ℹ entry: src/index.ts
7267
ℹ Build start
7368
ℹ dist/index.mjs <variable> kB │ gzip: <variable> kB

packages/cli/src/lib-bin.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#!/usr/bin/env node
2+
import module from 'node:module';
3+
4+
import { resolveConfig } from '@voidzero-dev/vite-plus-core';
5+
import { build, type UserConfig, globalLogger } from '@voidzero-dev/vite-plus-core/lib';
6+
import { cac } from 'cac';
7+
8+
const cli = cac('vite lib');
9+
cli.help();
10+
11+
const DEFAULT_ENV_PREFIXES = ['VITE_LIB_', 'TSDOWN_'];
12+
13+
cli
14+
.command('[...files]', 'Bundle files', {
15+
ignoreOptionDefaultValue: true,
16+
allowUnknownOptions: true,
17+
})
18+
// Only support config file in vite.config.ts
19+
// .option('-c, --config <filename>', 'Use a custom config file')
20+
.option('--config-loader <loader>', 'Config loader to use: auto, native, unrun', {
21+
default: 'auto',
22+
})
23+
.option('--no-config', 'Disable config file')
24+
.option('-f, --format <format>', 'Bundle format: esm, cjs, iife, umd', {
25+
default: 'esm',
26+
})
27+
.option('--clean', 'Clean output directory, --no-clean to disable')
28+
.option('--external <module>', 'Mark dependencies as external')
29+
.option('--minify', 'Minify output')
30+
.option('--devtools', 'Enable devtools integration')
31+
.option('--debug [feat]', 'Show debug logs')
32+
.option('--target <target>', 'Bundle target, e.g "es2015", "esnext"')
33+
.option('-l, --logLevel <level>', 'Set log level: info, warn, error, silent')
34+
.option('--fail-on-warn', 'Fail on warnings', { default: true })
35+
.option('--no-write', 'Disable writing files to disk, incompatible with watch mode')
36+
.option('-d, --out-dir <dir>', 'Output directory', { default: 'dist' })
37+
.option('--treeshake', 'Tree-shake bundle', { default: true })
38+
.option('--sourcemap', 'Generate source map', { default: false })
39+
.option('--shims', 'Enable cjs and esm shims', { default: false })
40+
.option('--platform <platform>', 'Target platform', {
41+
default: 'node',
42+
})
43+
.option('--dts', 'Generate dts files')
44+
.option('--publint', 'Enable publint', { default: false })
45+
.option('--attw', 'Enable Are the types wrong integration', {
46+
default: false,
47+
})
48+
.option('--unused', 'Enable unused dependencies check', { default: false })
49+
.option('-w, --watch [path]', 'Watch mode')
50+
.option('--ignore-watch <path>', 'Ignore custom paths in watch mode')
51+
.option('--from-vite [vitest]', 'Reuse config from Vite or Vitest')
52+
.option('--report', 'Size report', { default: true })
53+
.option('--env.* <value>', 'Define compile-time env variables')
54+
.option(
55+
'--env-file <file>',
56+
'Load environment variables from a file, when used together with --env, variables in --env take precedence',
57+
)
58+
.option('--env-prefix <prefix>', 'Prefix for env variables to inject into the bundle', {
59+
// support `TSDOWN_` for migration compatibility
60+
default: DEFAULT_ENV_PREFIXES,
61+
})
62+
.option('--on-success <command>', 'Command to run on success')
63+
.option('--copy <dir>', 'Copy files to output dir')
64+
.option('--public-dir <dir>', 'Alias for --copy, deprecated')
65+
.option('--tsconfig <tsconfig>', 'Set tsconfig path')
66+
.option('--unbundle', 'Unbundle mode')
67+
.option('-W, --workspace [dir]', 'Enable workspace mode')
68+
.option('-F, --filter <pattern>', 'Filter configs (cwd or name), e.g. /pkg-name$/ or pkg-name')
69+
.option('--exports', 'Generate export-related metadata for package.json (experimental)')
70+
.action(async (input: string[], flags: UserConfig) => {
71+
const viteConfig = await resolveConfig({ root: process.cwd() }, 'build');
72+
if (input.length > 0) flags.entry = input;
73+
// TODO: set default envPrefix after tsdown upgrade
74+
await build({
75+
...(viteConfig.lib as UserConfig),
76+
...flags,
77+
config: false,
78+
});
79+
});
80+
81+
export async function runCLI(): Promise<void> {
82+
cli.parse(process.argv, { run: false });
83+
84+
// TODO: enable debug after tsdown upgrade
85+
// enableDebug(cli.options)
86+
87+
try {
88+
await cli.runMatchedCommand();
89+
} catch (error: any) {
90+
globalLogger.error(String(error.stack || error.message));
91+
process.exit(1);
92+
}
93+
}
94+
95+
if (module.enableCompileCache) {
96+
module.enableCompileCache();
97+
}
98+
runCLI();

packages/cli/src/resolve-lib.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
* Used for: `vite-plus lib` command
99
*/
1010

11-
import { dirname, join } from 'node:path';
11+
import { join } from 'node:path';
1212

13-
import { DEFAULT_ENVS, resolve } from './utils.js';
13+
import { DEFAULT_ENVS } from './utils.js';
1414

1515
/**
1616
* Resolves the Tsdown binary path and environment variables.
@@ -26,12 +26,7 @@ export async function lib(): Promise<{
2626
envs: Record<string, string>;
2727
}> {
2828
// Resolve the bundled Tsdown CLI
29-
const binPath = join(
30-
dirname(resolve('@voidzero-dev/vite-plus-core/package.json')),
31-
'dist',
32-
'tsdown',
33-
'run.js',
34-
);
29+
const binPath = join(import.meta.dirname, 'lib-bin.js');
3530

3631
return {
3732
binPath,

pnpm-lock.yaml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)