Skip to content

TypeScript Bundling — Complete Guide

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about TypeScript Bundling. We cover key concepts, practical examples, and best practices to help you master this topic.

Bundling TypeScript for production involves compiling TS to JS, resolving modules, treeshaking dead code, and optimizing output for browsers or Node.js — with modern tools like Vite, esbuild, and tsup making this faster than ever.

What You'll Learn

  • Vite with TypeScript configuration
  • Webpack with ts-loader
  • esbuild for ultra-fast compilation
  • tsup for TypeScript libraries
  • Tree-shaking and code splitting

Why It Matters

TypeScript's compiler (tsc) does not bundle modules. A bundler is required to produce a single output file (or set of files) that runs in browsers. Choosing the right bundler affects build speed, output size, and developer experience.

Real-World Use

DodaTech's Durga Antivirus Pro dashboard uses Vite for development (instant HMR) and esbuild for production (sub-second builds). The shared utility library uses tsup to generate both ESM and CJS outputs.

Learning Path

flowchart LR
  A[Linting] --> B[Bundling]
  B --> C[React Components]
  B --> D[You Are Here]
  C --> E[React Hooks]
  E --> F[React Events]

Vite

The fastest build tool for web projects:

npm create vite@latest my-app -- --template react-ts
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  build: {
    target: 'es2020',
    sourcemap: true,
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
        },
      },
    },
  },
});

Vite uses esbuild for transpilation (dev) and Rollup for production bundling. TypeScript is handled natively — no extra config needed.

Webpack

npm install --save-dev webpack webpack-cli ts-loader typescript
// webpack.config.js
const path = require('path');

module.exports = {
  entry: './src/index.ts',
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    clean: true,
  },
  devtool: 'source-map',
};

esbuild

npm install --save-dev esbuild
// build.js
const esbuild = require('esbuild');

esbuild.build({
  entryPoints: ['src/index.ts'],
  bundle: true,
  outfile: 'dist/bundle.js',
  platform: 'browser',
  target: 'es2020',
  sourcemap: true,
  minify: true,
  treeShaking: true,
}).catch(() => process.exit(1));

esbuild is 10-100x faster than traditional bundlers. It handles TypeScript natively.

tsup (for Libraries)

npm install --save-dev tsup
// package.json
{
  "scripts": {
    "build": "tsup src/index.ts --dts --sourcemap --format esm,cjs"
  }
}
// tsup.config.ts
import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  dts: true,
  sourcemap: true,
  clean: true,
  splitting: true,
});

tsup is built on esbuild with TypeScript declaration generation built in. Perfect for libraries.

Tree-Shaking

Tree-shaking eliminates unused exports from the final bundle:

// utils.ts
export function used() { return 1; }
export function unused() { return 2; } // Removed by tree-shaking

// app.ts
import { used } from './utils';

For tree-shaking to work:

  • Use ES module syntax (import/export)
  • Enable sideEffects: false in package.json
  • Use a bundler that supports tree-shaking (Rollup, esbuild, Webpack in production mode)

Code Splitting

// Dynamic import — creates a separate chunk
const AdminModule = await import('./admin/AdminPanel');

Vite/Rollup automatically splits dynamic imports into separate chunks. Webpack needs splitChunks configuration.

Common Mistakes

1. Not Setting the Correct target

Bundlers default to modern targets, but if you need IE11 support, configure target explicitly.

2. Forgetting sourceMap in Production

Source maps in production expose your source code. Disable them:

// Vite
build: { sourcemap: false }

3. Not Configuring TypeScript for the Bundler

{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "isolatedModules": true
  }
}

4. Using ts-loader When esbuild Is Available

ts-loader is 10x slower than esbuild-based alternatives. Use esbuild-loader or Vite.

5. Not Using .d.ts for Library Exports

If building a library, always generate type declarations:

tsup --dts

Practice Questions

  1. Why does TypeScript need a bundler? tsc compiles TS to JS but does not bundle multiple files. Bundlers combine modules, tree-shake, and optimize for production.

  2. What is tree-shaking? Eliminating unused exports from the final bundle, reducing file size.

  3. What is the advantage of esbuild over Webpack? Speed — esbuild is 10-100x faster, written in Go, and handles TypeScript natively.

  4. What does tsup add on top of esbuild? Automatic declaration generation (--dts), multiple output formats (ESM/CJS), and simpler configuration.

Challenge: Create a small TypeScript library with tsup that exports both ESM and CJS formats with type declarations. Publish the output and verify both import and require work.

FAQ

Can I use tsc as a bundler?

tsc cannot bundle multiple files into one. It compiles each file independently. Use a bundler for single-file output.

What is the difference between `tsc` and bundler compilation?

tsc checks types and transpiles. Bundlers resolve modules, tree-shake, and optimize. Use tsc for type checking, bundler for production output.

Does Vite use TypeScript's compiler?

No. Vite uses esbuild for transpilation (type-stripping only). Type checking is done by tsc --noEmit separately.

What is `isolatedModules`?

Required by esbuild and Babel — it ensures each file can be transpiled independently without type information.

How do I debug production bundles?

Use source maps (sourcemap: true in build config) and Chrome DevToolsk "DevTools" >}}. Disable Minification during debugging.

Mini Project: Build Configurations

// src/index.ts
export function add(a: number, b: number): number { return a + b; }
export function multiply(a: number, b: number): number { return a * b; }

// For library — tsup config
// tsup.config.ts
import { defineConfig } from 'tsup';
export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],
  dts: true,
  clean: true,
  splitting: false,
});
# Build library
npx tsup

# Output:
# dist/index.js       (CJS)
# dist/index.mjs      (ESM)
# dist/index.d.ts     (Types)
# dist/index.d.mts    (Types for ESM)

What's Next

You've completed Module 5: Tooling & Config. Now explore React with TypeScript:

Lesson Description
{{< ref "/programming-languages/typescript/35-linting-prettier" >}} Review linting
{{< ref "/programming-languages/typescript/37-react-components" >}} React components with TypeScript
{{< ref "/programming-languages/typescript/38-react-hooks" >}} Typed React hooks

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro