Use microbundle for a TypeScript npm module
For those looking to write a package and publish it to npm, TypeScript + microbundle is a low-friction way to build a high-quality library.
I’ve created a GitHub repository template with microbundle, TypeScript, ava and xo. You can find it at github.com/HugoDF/microbundle-ts-pkg/
Table of Contents
Why TypeScript?
TypeScript is a JavaScript superset that adds static types to it. Its other features also follow the ECMAScript specification (current and future) quite closely. For library authors this means you provide the consumers of your library, even those who don’t use TypeScript with more details around expected types and for some editors/IDEs that integrate with TypeScript (like Visual Studio Code) nicer auto-complete. TypeScript also serves as inline documentation that shouts at you when you pass something you shouldn’t, which will come handy when you rediscover your code a couple of months down the line.
Why microbundle?
Microbundle is a “zero-configuration bundler for tiny modules”. It’s a wrapper around rollup with sane defaults (including minification/compression), nice outputted size stats, multiple target formats (ES modules, CommonJS, UMD). Most of all in the scope of this post, it has TypeScript support out of the box (actually no configuration, not even a tsconfig.json
).
It’s ridiculously easy to set up and allows library authors to focus on building a great library rather than setting up the plumbing to be able to ship a JavaScript library from ES6/TypeScript or other compile-to-JS tool 🙂.
Zero-config bundling with microbundle
To start, we’ll have to create setup our package run npm init
and complete all the prompts.
Next run: npm i --save-dev microbundle
.
Let’s create a src and dist folder: mkdir src && mkdir dist
And add the first TypeScript file: touch src/index.ts
.
Let’s add a class to the index.ts so we’re not just compiling empty files:
echo "export class MyMainClass {}" >> src/index.ts
Microbundle looks at the package.json
"main"
and "source"
fields (compiled entry point and source entry point),
in our case that’s dist/index.js
(which doesn’t exist yet) and src/index.ts
.
Let’s edit it to have the following in the package.json
:
{
"main": "dist/index.js",
"source": "src/index.ts"
}
This means microbundle knows how to compile our library now, run: npx microbundle
(on versions of npm <5.x, you can also run ./node_modules/.bin/microbundle
).
This will compile your src/index.ts
to the dist
folder.
If you look at the contents of the dist
folder, you’ll see how much work microbundle does for you:
ls dist
index.d.ts index.js.map index.m.js.map index.umd.js.map
index.js index.m.js index.umd.js
Let’s explain what all these are:
index.js
is the CommonJS module. This is module type used by Node and it looks likeconst myModule = require('my-module')
index.m.js
is the ECMAScript Module, as defined in ES6, it looks likeimport MyModule from 'my-module'
index.umd.js
is the UMD moduleindex.d.ts
is TypeScript type declaration file
Then there’s a matching .map
file that maps back to the TypeScript source for each of the files.
Take a look inside index.js
:
cat dist/index.js
var n=function(){return function(){}}();exports.MyMainClass=n;
//# sourceMappingURL=index.js.map
Our class MyMainClass {}
statement was compiled to its ES5 equivalent and the export to a CommonJS export.
index.d.ts
is also interesting:
cat dist/index.d.ts
export declare class MyMainClass {
}
This allows a TypeScript project to assign the correct type information back to the package… which is a roundabout way of doing since a TypeScript project should be able to just import the .ts
file. The separate type declaration means that non-TypeScript projects can also understand the public API of the module (eg. code editors can do smart autocomplete on unseen npm packages).
microbundle can also watch for changes: npx microbundle watch
.
For ease of use we can put the watch and build tasks in the package.json
as npm scripts:
{
"scripts": {
"dev": "microbundle watch",
"build": "microbundle"
}
}
Publish the microbundle-built module to NPM
By leveraging microbundle we can publish the module as a CommonJS module (standard npm module), but also as an ES Module and a UMD module, to do this follow the guide at https://github.com/developit/microbundle#specifying-builds-in-packagejson.
tl;dr
"source": "src/index.ts"
"main": "dist/index.umd.js"
"module": "dist/index.modern.js"
"types": "dist/index.d.ts"
Other words, your package.json should look something like the following:
{
"// other": "fields",
"source": "src/index.ts",
"main": "dist/index.umd.js",
"module": "dist/index.modern.module.js",
"types": "dist/index.d.ts",
"// more": "fields"
}
With this package.json
you can publish to npm with npm publish
.
And if you enjoyed using microbundle, definitely keep using it but also give it a star on GitHub and let Jason Miller aka @_developit know you’re a fan on Twitter.
This whole post is available as a GitHub Template with microbundle, TypeScript, ava and xo. You can find it at github.com/HugoDF/microbundle-ts-pkg/
Cover Photo by Aaron Burden on Unsplash
Get The Jest Handbook (100 pages)
Take your JavaScript testing to the next level by learning the ins and outs of Jest, the top JavaScript testing library.
orJoin 1000s of developers learning about Enterprise-grade Node.js & JavaScript