TypeScript+React Primer

OverviewQuick setupTypeScript introReact introMoreAbout meLeave a comment

How to publish a npm package (properly)

To begin, set up an npm project in the usual way.

Write a module that you want to publish, probably using the ES6 export command to export things from it. You should also write some tests to test it; you could use a unit test framework such as jasmine, but the simplertime example package doesn’t.

Example

For Part 5 I made a simple time parser/formatter; now I’ve published it as the simplertime npm package. See the repo to see how it is set up, and try npm install simplertime to download the installed package to find out how it differs from the version published in the repo (in short: the tests are gone and package.json was modified by npm).

Main preparation steps (for JavaScript and TypeScript)

If it’s a TypeScript package…

When publishing TypeScript packages on npm, it’s polite to publish code that has been compiled to JavaScript so that people who are not using TypeScript can still use your package. By also including a .d.ts file (which contains type information), you don’t even need to publish the original TypeScript source code.

How to minify your code (optional)

Some npm packages offer minified or production versions, but this is not required; there is no standardized method in npm to offer separate “development” and “production” versions of your package, and developers using Webpack get their entire app minified (including npm packages) when they use webpack -p or the --optimize-minimize option. Still, some developers will appreciate having a minified version that they can refer to, e.g. via aliases (Webpack aliases or Parcel aliases.

TypeScript aliases don’t work for this purpose because if you tell TypeScript that A is an alias for B, then TypeScript loads B for type-checking purposes, but it generates code that still refers to A.

So, I made a brief page explaining how to minify your code.

How to verify that your package is set up correctly

It’s important to check, because you cannot change a package after publishing it (except after changing the version number to something new that you’ve never used before). And if you don’t check, you won’t know if the published version of your package actually works. So clearly, the smart policy is to check in advance.

But how? npmjs.com offers no good answer to this question.

Option 1: npm pack

You can run npm pack to get a preview of what your package will contain:

PS C:\Dev\simplertime> npm pack
npm notice
npm notice package: simplertime@1.0.0
npm notice === Tarball Contents ===
npm notice 950B  package.json
npm notice 1.1kB readme.md
npm notice 3.8kB dist/simplertime.d.ts
npm notice 6.3kB dist/simplertime.js
npm ...
npm notice === Tarball Details ===
npm notice name:          simplertime
npm notice version:       1.0.0
npm notice filename:      simplertime-1.0.0.tgz
npm notice package size:  6.2 kB
npm notice unpacked size: 24.2 kB
npm notice shasum:        e731092eea4a4e49be9912e4710348f41c2c9dc4
npm notice integrity:     sha512-6fxbApL17Dol9[...]WGtw70i6xv4mg==
npm notice total files:   7

From this you can see whether the intended files were included, but it doesn’t tell you if other settings are correct (e.g. main, typings, devDependencies).

You can improve this a bit by building and running unit tests at the same time. npm runs the prepare script before npm pack and before npm publish, so you’d want something like this in package.json:

"scripts": {
  ...
  "prepare": "npm run build && npm test"
}

I think the right way to ensure that your package is packaged correctly is to run your unit tests against it - the same tests that make sure your code works locally could also test the packaged code.

I was trying to write a custom script in my project that would automate this idea, but I hit a roadblock: the way module resolution works. Specifically, when you import a local code file you must import from ./, e.g. import {stuff} from "./yourModule", but when you import something from node_modules you must import from your_package_name. So even if your package has the same name as your module (e.g. simplertime has simplertime.ts), a single import command cannot work for both. Therefore, there’s no obvious way to write your tests in TypeScript so that they can run against either the local copy or a packaged version in node_modules.

I decided to solve this problem in a way that I hoped would help the whole community: by making a testing tool to test your package before publishing. It’s called testpack-cli. I tried other names, but names like testpack, testpackage, packtest, packagetest, checkpack, and checkpackage were already taken by random people publishing “test packages” to “check” if they could figure out how to use npm. Finally I settled on the name npm-testpack which seemed unused, but it turned out that someone had already taken npm-test-pack, which blocked me.

You use it like this:

  1. In a terminal: npm install --save-dev --global testpack-cli
  2. Run it with testpack
  3. Read the documentation if you need to configure it

Here’s what it does: it packs your package with npm pack, then creates a test folder with its own separate package.json file. In the test folder it installs your package, it installs your unit test framework (if you one of the common ones is listed as a dependency), and it adds your unit tests (identified by the test patterns test* *test.* *tests.* *test*/**). If you have a tsconfig.json file, that’s copied to the test folder too. And finally, whenever your tests import "./something" or "../src/something", the ./ or ../src/ prefix is stripped off.

Therefore, if your package is called pkg, you should ideally create a single “main” source file called pkg.js or pkg.ts which you import using import {...} from "./P" in your tests. The test folder’s copy will import "P" instead.

By default, the test folder is created as a sibling: if your package name is pkg then the test folder is ../pkg-testpack.

If your package is a TypeScript project, make sure that your tests in the test folder are importing the compiled JavaScript version, because your end-users might not be using TypeScript. One way to guarantee this is to exclude all .ts files from your package (if you do that, be sure source maps are disabled in your tsconfig.json.) Your tests should still be written in TypeScript to make sure your d.ts files work; use "declaration": true in tsconfig.json so they can access type information.

How to publish (finally!)

> npm adduser
Username: qwertie
Password:
Email: (this IS public) qwertie256@gmail.com
Logged in as qwertie on https://registry.npmjs.org/.

To update the package (publish a new version)