Bundle a TypeScript library with Bili

egoist profile image EGOIST ・3 min read

Bili is a bundler built on the top of Rollup, it can be really convenient if you wanna bundle your library in multiple formats, nowadays it's pretty common to build a JavaScript library that works in CommonJS, UMD and ES Modules.

Bili also works with TypeScript seamlessly, this post will walk you through creating a simple TypeScript library.

Get Started

Let's get started by creating a new project to learn how to use TypeScript with Bili:

mkdir my-lib
cd my-lib
yarn init -y # Create a package.json
yarn add bili --dev

Next install TypeScript related dependencies:

yarn add typescript rollup-plugin-typescript2 --dev

We will use rollup-plugin-typescript2 instead of the official rollup-plugin-typescript because the latter does not perform type-checking during compilation.

Now Bili will automatically use rollup-plugin-typescript2 if you're building a .ts file.

TypeScript Config

To let TypeScript perform proper type-checking, a tsconfig.json is necessary, you can create one by running the TypeScript compiler with --init flag:

yarn tsc --init

Feel free to tweak the options in tsconfig.json to suit your needs.

Bundle in Multiple Formats

We will create a src/index.ts in my-lib:

# Create src/index.ts
mkdir src
echo "export default 42" > src/index.ts
# Bundle it in CommonJS and ESM format
# Omit `--format <format>` to bundle in CommonJS only
yarn bili src/index.ts --format cjs --format esm

Then src/index.ts will be bundled to dist/index.js:

'use strict';

var index = 42;

module.exports = index;

And dist/index.mjs:

var index = 42;

export default index;

It's recommended to add dist (generated by Bili) and .rpt2_cache (generated by rollup-plugin-typescript2) in .gitignore file.

Generate Declaration Files

To generate corresponding .d.ts files for files in src folder, first you need to enable compilerOptions.declaration in your tsconfig.json:

  "compilerOptions": {
    "declaration": true

Then create bili.config.ts to configure TypeScript to include src folder only:

import { Config } from 'bili'

const config: Config = {
  plugins: {
    typescript2: {
      // Override the config in `tsconfig.json`
      tsconfigOverride: {
        include: ['src']

  // Let's take this opportunity to move the CLI flags here as well
  input: 'src/index.ts',
  output: {
    format: ['cjs', 'esm']

export default config

Note that we didn't set include: ['src'] in tsconfig.json directly, because in most cases your editor like VS Code will use that file by default and you don't want other files like ./my-lib/test/index.test.ts to be excluded.

Finally let's run yarn bili and the declaration file will be generated to dist/index.d.ts:

declare const _default: 42;
export default _default;

Configure package.json

  "name": "my-lib",
  "main": "dist/index.js",
  "module": "dist/index.mjs"
  "types": "dist/index.d.ts",
  "files": ["dist"],
  "scripts": {
    "build": "bili",
    "prepublishOnly": "npm run build"

Now you can publish it on npm and the types can be found when others are using it.

Check out https://github.com/egoist/objql for a simple real-world TypeScript library.

Related Links


Editor guide
renoirb profile image
Renoir Boulanger

This is amazing!
Code changed a lot since last time I imported it.
TypeScript definitions and typings annotations are also nice.

While experimenting with the version bump, I realized maybe I misunderstood how to make different bundles not just by format, but by target runtime (e.g. Jest test runner, browser, etc).

I'm experimenting github.com/renoirb/experiments-201... this in this reproduction repository, and opened a ticket.

I will contribute documentation once I've understood how to do it properly. I must be missing something.

frank1e0927 profile image


steveohoh profile image

Amazing work