Creating and publishing an NPM package can enhance your portfolio and allow you to share reusable code with the community. Recently I released my own first package, a manga web reader (github.com/Mangatsu/mangatsu-reader) that is still very much experimental. This guide will walk you through setting up a repository for a TypeScript project, as well as configuring the project with useful linting software, and finally how to build and publish your package to NPM.
As for npm packages, usually MIT (or ISC) is recommended for the straightforwardness and ease of use. Sometimes, depending on the use case, Apache 2.0 with patent grant or strong copyleft license like (A)GPL 3.0 might fit your needs as well. Be sure to remember to create the LICENSE
(or COPYING
) file!
npm init
.
mkdir name-of-the-package
cd name-of-the-package
npm init -y
package.json
file with default configurations.git init
and create .gitignore
filenpm install --save-dev typescript @types/node rimraf
tsconfig.json
file for your TypeScript configuration.
{
"compilerOptions": {
/* Language and Environment */
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"types": ["node", "react"],
"jsx": "react",
"useDefineForClassFields": true,
/* Modules */
"module": "ESNext",
"moduleResolution": "bundler",
"allowImportingTsExtensions": false,
"resolveJsonModule": true,
/* JavaScript Support */
"allowJs": false,
/* Emit */
"declaration": true,
"outDir": "./lib",
"declarationDir": "./lib",
/* Interop Constraints */
"isolatedModules": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
/* Type Checking */
"strict": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noFallthroughCasesInSwitch": true,
/* Completeness */
"skipLibCheck": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "lib"]
}
src
directory and outputs them into the lib
directory.npm install --save-dev prettier eslint prettier-eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
eslint.config.mjs
:
{
"semi": false,
"trailingComma": "all",
"singleQuote": false,
"tabWidth": 2,
"useTabs": false,
"printWidth": 120,
"endOfLine": "lf"
}
npm install --save-dev husky lint-staged
npx husky install
"lint-staged": {
"*.{ts,tsx,js,jsx}": "eslint --cache --fix",
"*.{ts,tsx,js,jsx,css,md}": "prettier --write"
}
"scripts": {
"prepare": "husky"
}
echo "npx lint-staged" > .husky/pre-commit
"scripts": {
"tsc": "tsc -p tsconfig.json",
"clean": "rimraf lib && rimraf build",
"build": "npm run clean && npm run tsc"
}
npm run build
will compile your TypeScript files from src to the lib directory."scripts": {
"copy-assets": "node -e \"require('fs').cpSync('./src/assets', './lib/assets', {recursive: true});\"",
}
"scripts": {
"build": "npm run clean && npm run tsc && npm run copy-assets"
}
npm login
{
"name": "name-of-the-package",
"version": "0.1.0",
"description": "",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
"type": "module",
"files": [
"lib/"
],
"repository": {
"type": "git",
"url": "github.com/<user,org>/<name-of-the-package>"
},
"keywords": [
"typescript"
],
"author": "Marko Kristian Leinikka",
"license": "MIT"
}
npm publish
. If it's your first time publishing, you can use npm publish --access public
to make it publicly accessible.You've now created a TypeScript NPM package with linting, formatting, pre-commit hooks, and a build process that handles asset copying. Whether you're publishing utility functions or a full-fledged library, this setup will help ensure a smooth workflow and quality code.
By following this guide, you should now be able to confidently publish your TypeScript packages to NPM and manage a clean, maintainable codebase.