Skip to content

karmaniverous/npm-package-template-ts

Repository files navigation

TypeScript NPM Package Template

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!

Code Authoring

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.

Inline Documentation

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!

CLI Generation

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:

  1. 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 called mycli.

  2. 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. So src/cli/mycli/index.ts will be compiled into dist/mycli.cli.mjs.

  3. The bin field in package.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

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.

IIFE Logging

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!

Formatting

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

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 Testing

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!

Bundling

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 in package.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 Build Warning

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!

Publishing

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.

Validating Your Package

Use this awesome utility to validate that the types in your package are actually accessible in key target development environments.

Git Hooks

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!

References

Coming Soon


See more great templates and other tools on my GitHub Profile!