Writing great TypeScript is only half the battle! You also need to instrument it, format it, lint it, test it, bundle it, and publish it!
Getting all of these pieces to work gracefully together is not trivial, especially given that a bunch of popular tools have recently released major versions that don't always play well together.
This template is designed to help you get all of these pieces working together in harmony, right out of the box, so you can focus on your code. It includes fully-configured support for:
✅ Code authoring with TypeScript.
✅ Inline documentation with TSDoc.
✅ CLI generation with Commander.
✅ Logging with tslog.
✅ Code formatting with Prettier.
✅ Linting with ESLint.
✅ Unit testing with Mocha & Chai.
✅ Bundling with Rollup.
✅ Publishing with ReleaseIt.
✅ Git hooks with Lefthook.
✅ Recommended extensions & settings wherever appropriate.
After cloning a repository that uses this template, be sure to run:
npm i
npx lefthook install
Also, type @recommended
into the VSCode Extensions sidebar and install the recommended extensions!
You want to write straight TS code without having to jump through weird hoops like adding a .js
extension to your TS imports. (Click here to dive into that hole. 🙄)
Long story short: you can. Just write your code in the src
directory and import it as you would any other module. The bundling process will take care of the rest.
This template uses TSDoc for inline documentation. TSDoc is similar to JSDoc, but is way less verbose as it can take advantage of TypeScript's type system. It also has better support for documenting generics and other TypeScript-specific features.
TSdoc comments are automatically included in your bundled code, so you can use them to document your code for IntelliSense in JavaScript as well as TypeScript.
The template also includes linting support for your TSDoc comments to keep you out of trouble. Just run npm run lint
to check your comments along with the rest of your code, and be sure to check out the great TSDoc documentation for more details!
This template uses Commander to generate a CLI for your package.
Given that your underlying library is solid, wrapping it into a CLI is fairly straightforward. Just follow these steps:
-
All of your CLI-specific code should live in the
src/cli
directory, but can import code from across your package as required. Each subdirectory here is the root of a CLI command. You can have as many as you want, but this template includes a single example calledmycli
. -
The
index.ts
file in each named CLI subdirectory will be picked up by the bundler and compiled into a CLI command with the same name as the subdirectory. Sosrc/cli/mycli/index.ts
will be compiled intodist/mycli.cli.mjs
. -
The
bin
field inpackage.json
must specifically reference each of these compiled CLI commands. On installation, you can then execute your CLI command like this:
> npx mycli # if installed localy
> mycli # if installed globally
# this is what you get...
Usage: mycli [options] [command]
My CLI tool
Options:
-h, --help display help for command
Commands:
foo [options] Foos your bar.
help [command] display help for command
Providing a detailed tutorial on Commander is really out of scope for this README, but this repo demonstrates a simple example with a single subcommand abstracted into a separate dependency.
You can build on this example to create a MUCH more complex CLI! See the Commander documentation for more details.
Logging is provided by tslog. Just import & use the pre-configured logger, like this:
import { logger } from './util/logger';
logger.debug('This is a debug message!');
By default, logs are suppressed when LOG_LEVEL
is either invalid or undefined. For example, the test script uses cross-env
to enable debug logging during unit testing like this:
cross-env LOG_LEVEL=debug nyc mocha
See the logger
module for more details of this implementation, and the tslog documentation for tons of configuration options.
tslog appears not to play nicely with IIFE modules, so I've added a rollup.config.ts
replacement rule that replaces the tslog
logger with console
for all IIFE builds.
If you plan to build IIFE modules, you should avoid the silly
and fatal
log levels, as these do not exist on console
!
This is a bit of a hack, but it works. If you have a better solution, please submit a PR!
Code formatting is provided by Prettier.
Just run npm run lint
to lint & format your code, or npm run lint:fix
to resolve any issues automatically if possible.
The Prettier extension is included in the template's VSCode workspace recommendations, and the template contains related workspace settings, so be sure to install recommended extensions when prompted!
Linting services are provided by ESLint.
Just run npm run lint
to lint your code, or npm run lint:fix
to resolve any issues automatically if possible. These commands also run Prettier to identify & fix formatting issues.
The ESLint extension is included in the template's VSCode workspace recommendations, and the template contains related workspace settings, so be sure to install recommended extensions when prompted!
Unit test support is provided by Mocha, using the Chai assertion library.
Any file containing .test.
in its name (e.g. foo.test.ts
) will be treated as a test file and executed by Mocha. See .mocharc.json
for configuration details.
Just run npm test
to execute your tests.
Test coverage reporting is provided by nyc
and runs every time you execute your tests. If you execute your tests from the command line, you will see a coverage report at the bottom of the run. You can also see a prettier version of this report by opening coverage/index.html
in your browser.
The Mocha Test Explorer Extension is a great way to execute & debug your Mocha tests! It's included in the template's VSCode workspace recommendations, and the template contains related workspace settings, so be sure to install recommended extensions when prompted!
This template uses Rollup to bundle your code. See the References section for more detailed notes. It creates several kinds of outputs:
- ESM, for import into most TS/JS code.
- IIFE (Immediately Invoked Function Expression), for direct browser import.
- CJS, for lulz.
- Type definition files to support TypeScript imports and power IntelliSense in Javascript.
- CLI commands for execution from your command line. See the CLI Generation section for details. Don't forget to update the
bin
field inpackage.json
!
Type declarations are properly bundled and should be available no matter how your package is imported.
Just run npm run build
to bundle your code, and the output will be in the dist
directory.
See rollup.config.ts
for details. If you don't need all of the output types listed above, it should be fairly straightforward to modify this file to suit your needs.
Incremental builds are turned on in this template. This will save you some build time, but @rollup/plugin-typescript
will emit the following warning at build time:
(!) [plugin typescript] @rollup/plugin-typescript: outputToFilesystem option is defaulting to true.
This is a known issue and should have no negative effect on your build. If you can figure out how to suppress this warning, please submit a PR!
This template uses ReleaseIt to create a release on GitHub and publish your package to NPM.
Just run npm run release
and the following will happen:
- ESLint will lint your code.
- Mocha will execute your tests and NYC will assess code coverage. Open
coverage/index.html
to see the results. - Rollup will bundle your code.
- ReleaseIt will create a release on GitHub and publish your package to NPM.
See the release-it
section in package.json
for details.
Use this awesome utility to validate that the types in your package are actually accessible in key target development environments.
This template assumes you will be using something like Git Flow with a strong Git branch naming convention.
The template uses Lefthook to perform two services:
-
It will prevent you from committing to a branch with an invalid name. See the
branch-naming-policy
script for details. -
If your branch name begins with a standard-format issue number (e.g. GH-1) it will prefix your commit message with the issue number. This is a great way to keep your commits organized and linked to the issues they address! See the
add-issue
script for details.
To activate this functionality, be sure to run npx lefthook install
after cloning the repository & installing dependencies!
-
TypeScript and NPM package.json exports the 2024 way. Note that this snippet is wrong; it should read the types may need to be
.d.cts
. That's how this template is implemented. Also note that we're just using a second (and third)rollup
type declarations target instead of employing rollup-plugin-copy as suggested in the article.
- DotEnv support with
get-dotenv
See more great templates and other tools on my GitHub Profile!