TypeScript Package Deployment with TravisCI
TypeScript is a really cool solution. Having the ability to actually build your code and test it is like making your cake and eating it too. Of course this introduces the problem of “it compiled fine on my computer”. There are many different solutions to this (portable development environments, cross platform tooling, etc.) however, I prefer to use continuous integration & deployment to help solve this problem. CI/D is really easy (and free for open source projects) through Travis CI.
The end result gives us a cool page for library documentation:
It also gives us publishing to NPM:
And it gives us releases on GitHub:
At a high level, we want our CI solution to:
- Build & test our code.
- Generate & Deploy TypeDoc documentation
- Publish to NPM package
- Add new GitHub release.
First we are going to want a few files:
package.json— NodeJS Package Manager configuration file.
tsconfig.json— TypeScript configuration.
.travis.yml— TravisCI configuration
.nojekyll— Empty file. Prevents GitHub from using Jekyll when we go to deploy our TypeDoc site.
.gitignore— Ignore files from being pushed to Git(Hub).
dev/src/index.ts— Library entry point
dev/test/index.ts— Some tests
.npmignore— Similar to
.gitignorebut to ignore files from being served in the package.
I’ve been preferring putting my
test files within a
dev folder so that when typescript does a build, it maps directly from the
dist directory. Then they are the same depth in the file structure, which can make other things easier.
Next we are going to want a few
shx— cross platform shell commands
typedoc— TypeScript documentation generation
npm-run-all— Easily run multiple NPM scripts sequentially or in parallel.
@types/mocha— Testing framework.
Install these by using
npm install --save-dev <PACKAGE> .
Next we want to add some scripts to our
package.json . I like to use NPM scripts as their own build tool for backend services so tailor to taste if you use things such as Gulp or Grunt.
We want to add some scripts to our
setup— Installs packages (and any other setup).
build— Runs the TypeScript compiler.
test— Builds code and runs tests.
test-only— Runs the test. (I typically like my main test script to build then run the test).
typedoc— Generate the TypeDoc content.
posttypedoc— Copy the
.nojekyllfile into the docs folder.
The most non-trivial part of this entire process is the
posttypedoc and why we need to copy the
.nojekyll file. In essence, TypeDoc likes to generate files with weird names. These weird names conflict with how GitHub Page’s Jekyll operates on the generated content. By copying this file into our
docs folder and deploying our
docs folder, we are telling GitHub to not use Jekyll and instead serve unmodified content.
This is an example of the
scripts for my general JS/TS utility library: rlib:
"setup": "npm install",
"build-watch": "tsc --watch",
"test-only": "mocha dist/test/",
"pretest": "npm run build",
"test": "npm run test-only",
"clean": "shx rm -rf node_modules/ dist/ docs/",
"typedoc": "typedoc --out ./docs --mode modules --tsconfig ./tsconfig.json ./dev/src/",
"posttypedoc": "shx cp .nojekyll docs/.nojekyll"
In order to properly serve our code and types, we must define a
Next, we have the NPM ignore file.
We want to make sure we explicitly do not include the generated docs or the source code. We also don’t want to include a zipped version of our distributed code that we will be deploying to GitHub releases later.
// npm pack
Finally we have our Travis CI config.
before_script section, we want to:
- Setup our project (
npm run setup)
- Build our project (
npm run build)
In this sections, things are collapsed after being ran. This is a good place for setup. The
script section is where you will want your actual testing:
- Run tests (
npm run test-only)
Before we go to deploy our code, we want to build our deployment. Specifically we want a
- Build documentation (
npm run typedoc)
Finally we can deploy. TravisCI has many deployment providers. The most important to me are the GitHub Pages, npm and GitHub Releases providers.
.travis.yml is set up to deploy typedoc, as well as publish the zipped NPM package to GitHub releases.
- npm run setup
- npm run build
- npm run test-only
- npm run typedoc
- npm pack
- provider: pages
- provider: releases
- provider: npm
To get your
$GITHUB_TOKEN you will need to go to https://github.com/settings/tokens and enable repo access.
To get your
$NPM_TOKEN you will need to run
npm login and copy the key in your
The final workflow ends up such that pushes to
master branch are built and tested, but new GitHub tags are deployed. Make sure to remember to keep that changelog up to date and increment your semver properly!
For an idea of how all this integrates together take a look at my personal JS/TS util library rlib. It implements a similar workflow.