Simple math operations for testing publishing to the NPM registry from totaltypescript.
This repository contains hands-on practice set up for:
- A TypeScript project with the latest settings
- Prettier, which both formats your code and checks that it's formatted correctly
@arethetypeswrong/cli, which checks that your package exports are correcttsup, which compiles your TypeScript code to JavaScriptvitest, which runs your tests- GitHub Actions, which runs your CI process
- Changesets, which versions and publishes your package
Summary of creating the code repository and other setup from totaltypescript.
Expand to view details
- Initialize the repo
- Setup a .gitignore
- Create a new repository on GitHub
- Push to GitHub
Expand to view details
- Create a package.json file
- Add the license field
- Add a LICENSE file
- Add a README file
Expand to view details
-
Install TypeScript
npm install --save-dev typescript -
Setup a
tsconfig.jsonfile -
Configure your
tsconfig.jsonfor the DOM- If your code runs in the DOM (i.e. requires access to
document,window, orlocalStorageetc), skip this step. - If your code doesn't require access to DOM API's, add the following to your tsconfig.json (This prevents the DOM typings from being available in your code):
{ "compilerOptions": { /* other options */ "lib": ["es2022"] } } - If your code runs in the DOM (i.e. requires access to
-
Create a source file
/src/utils.ts
-
Create an index file
/src/index.ts
-
Set up a
buildscript"build": "tsc"
-
Add
distto.gitignore -
Set up a
CIscript"ci": "npm run build"
Expand to view details
-
Install Prettier
npm install --save-dev prettier
-
Set up a
.prettierrc{ "semi": true, "singleQuote": true, "trailingComma": "all", "printWidth": 80, "tabWidth": 2 } -
Set up a
formatscript"format": "prettier --write ."
-
Set up a
check-formatscript"check-format": "prettier --check ."
-
Adding to our
CIscript"ci": "npm run build && npm run check-format"
Expand to view details
@arethetypeswrong/cli is a tool that checks if your package exports are correct
-
Install
@arethetypeswrong/clinpm install --save-dev @arethetypeswrong/cli
-
Set up a
check-exportsscript"check-exports": "attw --pack ."
-
Setting
main
Add amainfield to your package.json with the following content:"main": "dist/index.js"
-
Fix the CJS warning
If you don't want to support CJS (which I recommend), change the check-exports script to:
"check-exports": "attw --pack . --ignore-rules=cjs-resolves-to-esm"
If you prefer to dual publish CJS and ESM, skip this step. -
Adding to our
CIscript"ci": "npm run build && npm run check-format && npm run check-exports"
Expand to view details
"If you want to publish both CJS and ESM code, you can use tsup. This is a tool built on top of esbuild that compiles your TypeScript code into both formats.
My personal recommendation would be to skip this step, and only ship ES Modules. This makes your setup significantly simpler, and avoids many of the pitfalls of dual publishing, like Dual Package Hazard". - totaltypescript
- Install
tsupnpm install --save-dev tsup
- Create a
tsup.config.tsfile - Change the
buildscript"build": "tsup"
- Add an
exportsfield in the package.json{ "exports": { "./package.json": "./package.json", ".": { "import": "./dist/index.js", "default": "./dist/index.cjs" } } } - Run `npm run check-exports'
Expand to view details
"We're no longer running tsc to compile our code. And tsup doesn't actually check our code for errors - it just turns it into JavaScript.This means that our ci script won't error if we have TypeScript errors in our code. Eek. Let's fix this." - totaltypescript
-
Add
noEmittotsconfig.json"compilerOptions": { "noEmit": true }
-
Remove unused fields from
tsconfig.json
These are no longer needed in our new 'linting' setup.outDir rootDir sourceMap declaration declarationMap -
Change
moduletoPreserve
ChangemoduletoPreservein the tsconfig.json."compilerOptions": { "module": "Preserve" }
We can start importing TS files without
.jsextensions with this setting, e.g.:
import { addition } from './utils' -
Add a
lintscript"lint": "tsc"
-
Add
lintto yourciscriptnpm run build && npm run check-format && npm run check-exports && npm run lint
Expand to view details
vitest is a modern test runner for ESM and TypeScript.
-
Install
vitestnpm install --save-dev vitest
-
Create a test
- Create a
src/utils.test.tsfile with the following content:import { add } from "./utils.js"; import { test, expect } from "vitest"; test("add", () => { expect(add(1, 2)).toBe(3); });
- Create a
-
Set up a
testscript- Add a
testscript in the package.json file
"test": "vitest run"
- Add a
-
Run the test script
npm test
-
Set up
devscript- This step runs tests in watch mode while developing. Add the following the package.json file.
"dev": "vitest"
- This step runs tests in watch mode while developing. Add the following the package.json file.
-
Adding to our
CIscript.- Add the
testscript to yourciscript
"ci": "npm run build && npm run check-format && npm run check-exports && npm run lint && npm run test"
- Add the
Expand to view details
- Create a
.github/workflows/ci.ymlfile- Refer to the file in the code repository.
- Testing our workflow
- Push the file to the repository.
- Workflow should run on push
Expand to view details
"Changesets is a tool that helps you version and publish your package. It's an incredible tool that I recommend to anyone publishing packages to npm." - totaltypescript
-
Install
@changesets/clinpm install --save-dev @changesets/cli
-
Initialize Changesets
- This will create a .changeset folder in your project, containing a config.json file. This is also where your changesets will live.
npx changeset init
-
Make changesets releases public
- Edit the
.changeset/config.jsonfile - Change the
accessfield topublic. Setting it to public allows publishing your package to npm."access": "public"
- Edit the
-
Set
committotrue- In
.changeset/config.json, change thecommitfield totrue - This will commit the changeset to your repository after versioning.
"commit": true
- In
-
Set up a
local-releasescript- This script will run your CI process and then publish your package to npm. This will be the command you run when you want to release a new version of your package from your local machine.
- Add a
local-releasescript to your package.json with the following content:"local-release": "changeset version && changeset publish"
-
Run
CIinprepublishOnly- This runs the CI process before publishing the package to NPM
- Add a prepublishOnly script to your package.json:
"prepublishOnly": "npm run ci"
-
Add a changeset
- Run the command to add a changeset:
npx changeset
- Mark the release as a
patch,minorormajorrelease - Give it a description e.g., "Initial release"
- This will create a new file in the
.changesetfolder with the changeset.
- Run the command to add a changeset:
-
Commit your changes
- Commit your changes to your repository
git add . git commit -m "Prepare for initial release"
- Commit your changes to your repository
-
Run the
local-releasescript- Run the command to release your package
- This will run your CI process, version your package, and publish it to npm.
npm run local-release
-
See your package on npm
- Go to
http://npmjs.com/package/<your package name>
- Further reading about Changesets
@weaponsforge
20250212