How to Create a React NPM Package with Typescript
Photo by Kelly Sikkema on Unsplash
Npm packages allow us to create re-usable code modules that we can use in other applications. Often, while using React, I find myself repeating code and re-using the same logic. Creating an npm package means that this can be written once, and used anywhere.
This article will walk through how to create a React npm package with Typescript, and most importantly, how to get it published. We can then import this into any project, and use it to our heart’s content.
Prerequisites
- npm
- git (optional)
- npmjs.com account
Project Setup
Photo by Kelly Sikkema on Unsplash
We first want to create a new folder to house our package. Run the following, replacing <packagename>
with your chosen name:
mkdir <packagename> && cd <packagename>
Git Setup (optional)
From here, we can initialise a Git repository. While this is recommended, this step is optional. Run the following command:
git init
We now want to create a .gitignore
file to avoid committing certain directories.
Create a new file called .gitignore
with the following contents:
# .gitignore
node_modules
.vscode
NPM Setup
Now we can setup npm. Run the following to setup our npm package, leaving the defaults for each prompt except entry point
, for which we want to enter index.ts
:
npm init
The output should look like the following:
package name: (<packagename>)
version: (1.0.0)
description:
entry point: (index.js) index.ts
test command:
git repository:
keywords:
author:
license: (ISC)
This will create a basic package.json
file, which describes our npm package.
Setting up Typescript
With our npm package created, we want to install typescript:
npm install --save-dev typescript
This will install typescript as a dev dependency, which means it won’t be included in our final package, as it is not necessary once our code has built.
We now need to setup the typescript compiler:
npx tsc --init
This will create a tsconfig.json
file which contains any typescript compilation options.
Replace the contents of the file with the following:
{
"include": ["src"], /* Include only the src directory */
"compilerOptions": {
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
"module": "commonjs" /* Specify what module code is generated. */,
"declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */,
"outDir": "dist",
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
"strict": true /* Enable all strict type-checking options. */,
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}
This will ensure our typescript files are generated correctly for our package and in the right location.
Package.json Setup
We now want to make a few changes to package.json
.
Firstly, we want to only include our /dist
files in our package. Then, we want to include React as a peerDependency
.
We also want to create a build script to compile our code. F
inally, we need to export the correct files so we can import them from other projects.
Our package.json
file should look like the following:
{
"name": "<packagename>",
"version": "1.0.0",
"description": "",
"main": "dist/index.js", // Set compiled file as main
"files": [
"dist" // Only export dist directory
],
"exports": { // Setup exports with typing
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"scripts": {
"build": "tsc" // Build our project
},
"author": "",
"license": "ISC",
"devDependencies": {
"typescript": "^5.1.6"
},
"peerDependencies": {
"react": "^18.2.0" // Include react as a peer dependency
}
}
Write our Code
Photo by Kelly Sikkema on Unsplash
With all the setup done, we can now start writing the bulk of our application.
Create a new folder called src
. Within this folder, create a file called index.ts
. This will be the entry point for our package. From here, we can import functions from other files, as well as export anything we want to be available from our package.
For the purposes of this tutorial, we’ll create just a simple function to export. Add the following to index.ts
:
/* src/index.ts */
export const testPackage = () => {
return "Hello World!"
}
With that, our package is almost complete. We can now move on to publishing…
Publishing our Package
Photo by AbsolutVision on Unsplash
Publishing allows us and others to use our package within their applications. Fortunately, this is very simple. Firstly, we want to build the latest version of our package:
npm run build
This will compile and setup our code for publishing.
Next, run the following to push our code to the npm repository.
npm publish
If it asks you to sign in, follow the instructions to authenticate your terminal with npm.
And that’s it! We’ve published our first npm package.
Using our Package
We can install our package from any react project with:
npm i <packagename>
From here, we can use our new package within any component:
import { testPackage } from "<packagename>"
const test = () => {
console.log(testPackage());
return <></>
}
Extensions
Photo by Steve Johnson on Unsplash
To make package development easier, there are a couple things we can add to our package.json
to speed things up.
Build cleanup
Currently running npm run build
simply builds on top of everything already within the /dist
folder.
To clean this up, we can use the rimraf
package. This adds cross platform support for removing directories.
Install rimraf with:
npm install rimraf
We can then add this to our build step by replacing scripts in package.json
with :
"scripts": {
"clean": "rimraf dist",
"prebuild": "npm run clean",
"build": "tsc",
},
Not only does this add the clean command, calling our script ‘prebuild’ ensures that it gets run every time before build.
Running npm run build
, we can see that our /dist
folder is removed and replaced during the build process.
Automatic Publish Builds
Whenever we publish a new version of our package to npm, we want to be confident we’re publishing the latest version of our code.
As of now, we have to manually remember to build our code before running npm publish
.
Being someone who often forgets to build before publishing, it would be pretty useful to have this done automatically. Fortunately, we can use a technique from before, involving “pre-”.
Add the following lines to the scripts section of package.json
:
"preversion": "npm run build",
"version": "npm publish"
We can now run npm run version
to both build a new version of our code, and publish it to the npm registry.
Finishing Up
Using this as a starting point, we can now create packages for any code we re-use frequently. We can make anything from custom hooks to customisable re-usable components. Check out the full code for the sample package here: https://github.com/oflint-1/npm-package-tutorial