TypeScript Bundle
$ npx vovk bundle@draft --help
Usage: vovk bundle|b [options]
Generate TypeScript RPC and bundle it
Options:
--out, --out-dir <path> path to output directory for bundle
--include, --include-segments <segments...> include segments
--exclude, --exclude-segments <segments...> exclude segments
--prebundle-out-dir, --prebundle-out <path> path to output directory for prebundle
--keep-prebundle-dir do not delete prebundle directory after bundling
--schema, --schema-path <path> path to schema folder (default: .vovk-schema)
--config, --config-path <config> path to config file
--origin <url> set the origin URL for the generated client
--openapi, --openapi-spec <openapi_path_or_urls...> use OpenAPI mixins for client generation
--openapi-module-name, --openapi-get-module-name <names...> module name strategies corresponding to the index of --openapi option
--openapi-method-name, --openapi-get-method-name <names...> method name strategies corresponding to the index of --openapi option
--openapi-root-url <urls...> root URLs corresponding to the index of --openapi option
--openapi-mixin-name <names...> mixin names corresponding to the index of --openapi option
--openapi-fallback <paths...> save OpenAPI spec corresponding to the index of --openapi option to a local file and use it as a fallback if URL is not available
--log-level <level> set the log level
-h, --help display help for commandThe composed TypeScript RPC library can be bundled and published to NPM with pre-filled package.json and README.md files using the bundle command after setting up bundle.build function in the config file.
npx vovk bundleThe feature is library-agnostic, allowing you to plug in your preferred bundler of your choice, including one that’s invoked via child_process module. By the time being, tsdown is the only bundler that has been tested with Vovk.ts. If you’re using a different bundler, please share your experience on GitHub Discussions .
Internally, the bundling is performed by executing the following steps:
- It generates a client into the
tmp_prebundledirectory (configured withbundle.prebundleOutDir: string) using the tsBase template. - Calls
bundle.buildfunction to bundle the generated client to thedistdirectory (configured withbundle.outDir: string). - Generates
package.jsonandREADME.mdfiles from the packageJson and readme templates. - Deletes the
tmp_prebundledirectory (configured withbundle.keepPrebundleDir: boolean).
After bundling, the package can be published to NPM:
npm publish distConfiguring the bundle
The bundling can be configured by adding the bundle object in the config file:
/** @type {import('vovk').VovkConfig} */
const config = {
bundle: {
build: async ({ entry, outDir, prebundleDir }) => {
// plug in the bundler of your choice here
},
prebundleOutDir: 'tmp_prebundle', // default
keepPrebundleDir: false, // default
outDir: 'dist', // default
outputConfig: {
origin: 'https://example.com',
requires: {
readme: '.', // default
packageJson: '.', // default
myTemplate: './foo', // custom template
},
excludeSegments: [],
includeSegments: [],
package: {
// modifies package.json content
// by default uses values from the root package.json
name: 'my-api-bundle',
},
readme: {}, // modifies README.md content
samples: {}, // modifies README.md samples content
imports: {
fetcher: './src/my-fetcher',
},
reExports: {}, // modifies re-exports in the generated index.ts
},
},
};
export default config;build function (required)
The build function is an asynchronous function that takes an object with entry (index.ts file), outDir, and prebundleDir, resolved as absolute paths.
prebundleOutDir or --prebundle-out flag
The prebundleOutDir is the directory where the TypeScript client will be generated before bundling. It defaults to tmp_prebundle.
keepPrebundleDir or --keep-prebundle-dir flag
If set to true, the prebundleOutDir will not be deleted after bundling. This can be useful for debugging or other purposes. Defaults to false.
outputConfig
The outputConfig object accepts and overrides the same options as the outputConfig at the root of the config file.
Bundling with tsdown
Install tsdown as a development dependency:
npm install --save-dev tsdownAdd the following build function to the bundle object in the config file:
/** @type {import('vovk').VovkConfig} */
const config = {
bundle: {
build: async ({ entry, outDir }) => {
const { build } = await import('tsdown');
await build({
entry,
outDir,
dts: true,
format: ['cjs', 'esm'],
hash: false,
fixedExtension: true,
clean: true,
tsconfig: './tsconfig.bundle.json', // see Troubleshooting section
},
// ...
},
};
export default config;The resulting bundled package will have the following structure:
- package.json
- README.md
- index.cjs
- index.d.cts
- index.mjs
- index.d.mts
Troubleshooting
In some TypeScript module configuration cases, you might encounter the following errors when vovk bundle is executed:
[UNLOADABLE_DEPENDENCY] Error: Could not load lib/internal/methods/object.ts - No such file or directory (os error 2).or
[plugin rolldown-plugin-dts:generate]
RollupError: tmp_prebundle/index.ts(17,14): error TS2742: The inferred type of 'XxxRPC' cannot be named without a reference to '../node_modules/vovk/mjs/client/types'. This is likely not portable. A type annotation is necessary.It is recommended to create a separate tsconfig.bundle.json file for tsdown, optionally extending the root tsconfig.json:
/** @type {import('vovk').VovkConfig} */
const config = {
bundle: {
build: async ({ entry, outDir }) => {
const { build } = await import('tsdown');
await build({
// ...
tsconfig: './tsconfig.bundle.json',
});
},
// ...
},
};
export default config;Setting moduleResolution to bundler fixes the first error, and setting paths to the vovk/* module fixes the second error:
{
"compilerOptions": {
"moduleResolution": "bundler",
"paths": {
"vovk/*": ["./node_modules/vovk/*"],
},
}
}Using the Bundled Package
After publishing the bundled package to NPM, it can be installed and used in other projects like any other NPM package:
npm install my-api-bundleAnd imported in your TypeScript code:
import { UserRPC } from 'my-api-bundle';
await UserRPC.getUser({
params: { id: '123' }
});All features described in the TypeScript article are available to the bundled method, including client-side validation, custom options, queryKey method and more.
Schema is available under schema import as well as a property for every method individually:
import { schema, UserRPC } from 'my-api-bundle';
console.log(schema.segments[''].controllers.UserRPC.handlers.getUser.validation.params);
console.log(UserRPC.getUser.schema.validation.params);Note that the openapi object that’s usually available in the vovk-client/openapi isn’t bundled as it will bloat the package size. The schema module usually available in vovk-client/schema also isn’t present in order to keep the bundle flow simple by using only a single entry point.
The bundle methods can be used as LLM tools that will invoke corresponding HTTP endpoints when called.
import { UserRPC } from 'my-api-bundle';
import { createLLMTools } from 'vovk';
const { tools } = createLLMTools({
modules: { UserRPC },
});Roadmap
- ✨ Segmented bundle - create separate bundles for each segment.