NPM Libraries
Many times, we find ourselves in the following exhausting situation: Copying code from project to project endlessly. Sometimes we even think about creating a library for it, but then we hesitate whether it’s worth spending our time on it. And most of the time, it is worth it!
Having your library in the infamous node_modules is not difficult. Just take a look:
Requirements
- Node and NPM installed
- NPM account and token
- Github account
- Goodwill
That’s it.
Step by Step
- Create an empty directory for your library. After all, it’s just a Node project.
- Navigate to the directory and run
yarn init -y
. - In the generated package.json, you’ll need to make a few changes:
- The
name
field is the name of your library and also how people will install it. So you have two options: be creative with the name or prefix it with your Github username, like@mococa/toastr
, for example. You can check if the name is availableby running yarn add LIBRARY NAMEby going to the NPM website and searching for the desired name. - The
version
field is important. It is recommended to start with version0.0.1
. When you want to make changes, you’ll need to update it. - You’ll need a few more fields that you might not be familiar with:
homepage
where you will put the link to your library’s Github repository or Github Pages.repository.url
where you will put the link to your library’s Github repository ending with .git.module
,types
,main
will be the entry points of your library.peerDependencies
where you will list the dependencies that you expect the users to have.devDependencies
dependencies to assist you.dependencies
dependencies to make your library work.
- The
- You may need to install a few libraries to be able to build your TypeScript project.
Without further ado, here’s an example of how it would look in your package.json:
{
"name": "my-awesome-library",
"version": "0.0.1",
"author": "YOUR LOVELY NAME",
"license": "MIT",
"homepage": "https://github.com/YOUR-GITHUB/REPO",
"repository": {
"url": "https://github.com/YOUR-GITHUB/REPO.git"
},
"main": "dist",
"module": "dist",
"types": "dist/index.d.ts",
"scripts": {
"build": "npx tsc --build tsconfig.json",
"watch": "tsc -w",
"prepublishOnly": "npm run build"
},
"devDependencies": {
"@types/node": "^16.14.0",
"ts-node": "^10.9.1",
"typescript": "^5.1.6"
},
"keywords": [
"my",
"first",
"lib",
"typescript"
]
}
Alright. After doing that, notice that in the build script, we are configuring it based on the tsconfig.json, so let’s create it:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["es2020", "dom"],
"declaration": true,
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noImplicitThis": true,
"alwaysStrict": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": false,
"inlineSourceMap": true,
"inlineSources": true,
"experimentalDecorators": true,
"strictPropertyInitialization": false,
"esModuleInterop": true,
"typeRoots": ["./node_modules/@types"],
"noEmit": false,
"outDir": "./dist"
},
"exclude": ["node_modules", "dist"]
}
Now let’s create a .gitignore
and a .npmignore
file. The .npmignore file is used to prevent unnecessary files from being sent to the user’s node_modules folder.
.npmignore:
*.ts
!*.d.ts
.github
Perfect.
Now, you’ll place your files in a folder (the convention is to name this folder lib
), such as /lib/file-that-does-something.ts
, and in that file, you put the logic. It’s important that any used types are declared if you want to export them as well (it’s always good to have the types of the libraries available).
Then, create a /lib/index.ts
file where you import and export everything as needed. What you export from this file will be usable by anyone who installs your library.
Example:
// lib/greet.ts
export interface GreetProps {
name: string;
}
export const greet = ({ name }: GreetProps) => {
console.log(`Hello, ${name} ! This is my library working`)
}
// lib/index.ts
import { greet, GreetProps } from './greet';
export { greet, GreetProps };
Testing
To test your library without having to publish it to NPM, you can use npm link
!
Now you can run yarn build
and then yarn link
.
After that, go to a different project to test and run yarn link my-awesome-library
, and in the blink of an eye, you have your library in the project to test. Perform the tests, and when you’re done, run yarn unlink my-awesome-library
, and then yarn unlink
in the library.
Publishing to NPM
Assuming you already have your NPM account and generated token (if you don’t have it and read this far, you deserve 7 gentle slaps), take the token and add it to the repository’s secrets: https://github.com/YOUR-GITHUB/REPOSITORY/settings/secrets/actions
Add something like NPM_TOKEN
.
Got it? Great. Let’s continue with the code.
Create a file .github/workflows/NPM.yml
.
In that file, add the following:
name: Publish to NPM
on:
release:
types: [created]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Node
uses: actions/setup-node@v2
with:
node-version: "16.14.0"
registry-url: "https://registry.npmjs.org"
- name: Install Dependencies
run: yarn install
- name: Build
run: yarn run build
- name: Publish package on NPM
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
What this is doing is: Every time there is a new Github release, we trigger an action to update the NPM library.
And that’s it! When everything goes well, you can use your public library.