How to build Typescript library with high compatibility for users?

Viewed 1140

What I want to do

I want to create a library that can be used as JS developer and as Typescript developer (frontend, no nodejs). That means that JS developer can use the library as inline script: <script type="text/javascript" src="mylib.js">var myLib = new MyLib();</script> and Typescript developers can use the library via imports.

What I need

I want to develop this library in Typescript and that's why I need a (build) solution that meets the following requirements:

  1. The library should be developed in Typescript.
  2. The build should contain all declarations automatically. Typescript developers should be able to import parts of this library.
  3. For Javascript users the library should be used "the old-fashioned-way" as inline code in a <script>-Tag
  4. The builds should be generated automatically if npm run build is called.
  5. Generally the compatibility to older browsers of this library should be as high as possible.

What I tried so far

  • I created a typescript library and experimented with some settings in the tsconfig.json. The only way I found is to set the "module" attribute to "none", but then I can't use imports, exports in my code and have to merge all my Typescript files into one file. That would make the developement more difficult.
  • I looked on the repository e.g. of Konva.js, which does what I want to do. But I don't understand how it works. It seems the developer converts the code to umd and then uses rollup.js and at the end of the build there exists a javascript file as long as all Typescript code that is needed.

Comment

I'm looking for a solution for some days, but it's hard to find the perfect term that represents what I'm looking for. That's why I ask it here and hope someone can help me.

2 Answers

Browser does not understand typescript directly so that why using the typescript compiler we convert our typescript code to javascript. So when we build a typescript project or module we usually have a typescript configuration file tsconfig.json which a typescript compiler uses when compiling typescript to javascript.

enter image description here

This is only a snapshot of a few configurations in the tsconfig.json file. First, so you want to target most of the browser so what you will do set the target property to es5. Because most browsers older and new have very good support for it. Now your typescript compiler will emit javascript in the es5 version. There is the other property call outDir which will contain your outputted javascript code which you can import directly in your other javascript file in production or others can import it using tags.

In your package.json file, you can set the build script so it should run a typescript compiler to compile typescript code.

About point number 2, what you can do is you can specify the entry point of your typescript module like it can be main.ts or index.ts in package.json so when other typescript developer uses this library then there build tool would automatically get the import defined in the entry point of your library. So What would go in this entry point file is a question? It would contain export of your all the module of the library. In this way, all modules of your library would be available to other typescript users.

You can also check the konvasjs tsconfig file. what they are doing they are outputting their javascript files in the lib directory which is used in production. for development, they are working with normal typescript files.

I went deeper into package builder and found out: iife is the term I was looking for. A iife build allows to load a library directly via the script tag without anything else.

After hours of testing I found a perfect solution to build my library that fits my needs: rollup.js

The core npm packages are:

My solution creates a package with this structure:

|dist
|- js
|-- MyLibrary.js
|- es
|-- // ES files
|- package.json

The MyLibrary.js file can be imported easily within a <script> tag and the Typescript related files are in the "es" folder. The package automatically directs to the es/index.js that means Typescript developers should be able to use auto-complete for type suggestions in their IDE.

You can find a sample repository here: https://github.com/julianpoemp/rolltsup-sample

package.json:

{
  "name": "my-lib",
  "version": "0.0.1",
  "description": "",
  "main": "src/main.js",
  "dependencies": {
    "rollup": "^2.38.5"
  },
  "devDependencies": {
    "@rollup/plugin-commonjs": "^17.1.0",
    "@rollup/plugin-typescript": "^8.1.1",
    "rollup-plugin-generate-package-json": "^3.2.0",
    "tslib": "^2.1.0",
    "typescript": "^4.1.3"
  },
  "scripts": {
    "build": "rollup --config rollup.config.js && rollup --config rollup.config_es.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  }
}

rollup.config.js

import typescript from '@rollup/plugin-typescript';

// rollup.config.js
export default {
    input: 'src/index.ts',
    output: {
        file: 'dist/js/myLibrary.js',
        name: 'MyLibrary',
        format: 'iife'
    },
    plugins: [
        typescript({
            target: "ES5",
            declaration: true,
            outDir: "dist/js",
            rootDir: "src"
        })
    ]
};

rollup.config_es.js

 import typescript from '@rollup/plugin-typescript';
import generatePackageJson from 'rollup-plugin-generate-package-json'

// rollup.config.js
export default {
    input: 'src/index.ts',
    output: {
        dir: 'dist/es',
        name: 'MyLibrary',
        format: 'es'
    },
    plugins: [
        typescript({
            target: "ES5",
            declaration: true,
            outDir: "dist/es",
            rootDir: "src"
        }),
        generatePackageJson({
            outputFolder: "dist",
            baseContents: (pkg) => {
                pkg.main = "es/index.js";
                pkg.scripts = undefined;
                return pkg;
            }
        })
    ]
};

Related