How to create a JavaScript library with TypeScript and Webpack

The following post is a conceptual guide on how to create a JavaScript library with commonly used web techknowledgies. Basic knowledge of NodeJS and NPM is assumed.

Requirements

  • The library shall have 3:rd party dependencies.
  • The 3:rd party dependencies shall not be bundled with the library.
  • The library shall be bundled as an UMD:
    • can be included directly in a web page
    • can be included/required as a module (AMD or commonjs)
  • The library shall include type definitions for eventual TypeScript consumers.

Setup

The library will be created with NodeJS, NPM, TypeScript and Webpack. In this example we will use React as a 3:rd party dependency.

First we create the library skeleton as a simple NPM package and install the dependencies:

npm init 
npm install --save-dev typescript webpack ts-loader 
npm install --save react @types/react

Implementation

Now we implement the library as a set of typescript modules which depend on both each other and React.

import * as React from "react";

export const ComponentA = (props: {}) => React.DOM.div({}, 'Component A');
import * as React from "react";
import { ComponentA } from "./comp-a";

export const ComponentB = (props: {}) => React.DOM.div({}, 'Component B and ', React.createElement(ComponentA, {}));
export * from "./comp-a";
export * from "./comp-b";

Building and bundling

It is time to build and bundle our library with the following webpack configuration.

module.exports = {
    resolve: { extensions: ['', '.js', '.ts', '.tsx'] },
    module: {
        loaders: [
            { test: /\.tsx?$/, loader: 'ts' },
        ]
    },
    externals: {
        "react": {
            root: "React",
            commonjs: "react",
            commonjs2: "react",
            amd: "react"
        }
    },
    entry: './src/index.ts',
    output: {
        path: __dirname + '/dist',
        filename: '[name].js',
        libraryTarget: "umd",
        library: 'mylib'
    }
};

The externals configuration above is what excludes React from the output bundle. It will instead introduce React as a dependency named “react” for all module systems and for the global environment it will be assumed to exist as a global variable called “React”.

The output bundle can now be created by invoking webpack:

webpack

The output can be found in the dist folder and can be consumed in other projects.

Type definitions

Unfortunately there is currently no simple way to generate a nice type definition file for our library. TypeScript has support for generation of a type definition files but these will not be bundled/flattened in the way we want by reflecting our bundling.

However the future looks promising with the following Proposal: Bundling TS module type definitions.

There are also some open source projects which try to help with this but they do not seem to work right out of the box for me. So unless you are creating a huge library I suggest hand writing the definition files as of now. The TypeScript handbook has a nice template for this: module.d.ts.

Full example

I have created a full example including usage of the library both as a module and with a global include. You can find it at https://github.com/Cooke/typescript-lib-example.