How to Release a Custom React Component, Hook or Effect as an npm Package

August 27, 2019
Written by
Joe Previte
Contributor
Opinions expressed by Twilio contributors are their own

ORXOra5m--S2QumnCfLwH_eCmlbMkYQ2BuIeSDbYT0KizCG2idnIgP6xz_EeIcmdwtq446pHDY5f3iNASDN16OD8cscswfAy4ARnnH3ScJxEfg9c3AVoACtMHV2fEW3c7UjABzsr

At my previous company, I was chatting with a coworker about getting more into open source. I told him I wanted to release an open source npm package. He suggested I try it with a custom React hook/effect I had written the month prior. It had the purpose of closing a dropdown menu or container when you clicked outside of it.

Together, we ambitiously tackled the goal and released a package called react-use-click-away 🎉 It isn’t a perfect package but it gave us that experience we were longing for.

While figuring out how to do all this, I realized it felt more intimidating than it should have. To solve that, I’m going to show you all the things you need to know in order to release your own custom React component, hook or effect as an npm package 😎 Let’s do it!

Things You Should Know

Before we jump in, there are a few things I want to make sure we define. Some things on which you might need a refresher:

What is a React component?

> Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called “props”) and return React elements describing what should appear on the screen. - Official React docs

What is a React hook?

> Hooks are functions that let you “hook into” React state and lifecycle features from function components. - Official React docs

What is a React effect?

> The Effect Hook, useEffect, adds the ability to perform side effects from a function component. - Official React docs

Now that all the bases are covered, let’s move forward assuming you have basic React experience and experience with Hooks.  - Intro to React Hooks Tutorial

Tutorial Prerequisites

As with any coding tutorial, we must make sure your machine has what it needs to accomplish the task. You should have the following installed on your computer or laptop:

Once you have all of that, you are ready to go!

Set Up Boilerplate using create-react-hook

create-react-hook is a “CLI for easily creating reusable react hooks..” This came as a recommendation from Dominik Kundel who has spent a lot of time releasing npm packages. It’s been great so far and will make this process much easier.

Open up your command line application and find a good place where you want to keep this project. For me, I have a directory called dev where I keep all my projects. Once you’re there, let’s use npx to use this package:

npx create-react-hook

(npx comes with npm 5.2+ and higher)

Once we’ve executed this command and run it locally, it will walk us through an interactive command prompt asking some questions about our package:

Package Name

We’re going to make this a “scoped package” so that we don’t have to worry about name conflicts. Go ahead and use the following: “@NPM-REGISTRY-USERNAME/react-use-the-things”

Replace “NPM-REGISTRY-USERNAME” with the username associated with your npmjs account so for me, that looks like @jsjoeio/react-use-the-things.

Package Description

You can put whatever you want here but I’m going to put “a package that gives you custom react things”

Author’s GitHub Handle

It should automatically grab this from the package name and show it in parentheses. If it does, you can hit return. If not, type in your GitHub handle without the “@” symbol.

GitHub Repo Path

We’re going to change the default option and write “GITHUB-USERNAME/react-use-the-things” so for mine, I’ll write “jsjoeio/react-use-the-things” and press return.

License

For now, we’ll go with the default MIT license but you can always change this later.

Package Manager

Since we didn’t ask you to install yarn earlier, we’re going to select “npm” using the up arrow key and pressing return.

Template

This CLI supports TypeScript, but we’ll stick with the regular JavaScript for now so make sure that default is selected and press return.

Populating package information for npm

Now that we’ve configured all our options, the create-react-hook will set everything up for us and then we’ll be able to start writing some code soon.

Create Repository on GitHub

Before we continue, head to GitHub to create a new repository and call it react-use-the-things.

Then, on your machine, cd into the project folder and paste the command from GitHub for pushing an existing repository from the command line:

cd react-use-the-things
git remote add origin https://github.com/jsjoeio/react-use-the-things.git
git push -u origin master

create-react-hook Boilerplate Overview

Now that we have our boilerplate set up and ready to go, let’s look at a brief overview of what it gave us:

Walking through each directory, here’s what we’re working with:

dist

This is our “distribution” directory - the one that we’re use when distributing our code to the open source community when they download our package. You’ll see various files in there, each of which target different module formats. Typically, you don’t publish this to GitHub because it’s usually generated as a result of the build step.

example

The author of this CLI tool included this directory which is a simple create-react-app project where we can test our project locally.

src

This is where we’ll be spending the majority of our time. We’ll be writing all our custom React code here.

Files in root

You’ll see some other files, some of which might be familiar like .eslintrc and others, which might look new like rollup.config.js. The gist is that our package will use Rollup for bundling

And Babel for transpiling. You can read more about the details of the CLI in the repo.

Create Our Custom React Component

The first custom React code we’re going to write is our React component. Navigate to the src directory and create a file called TwilioLogo.js. This will be a functional component that shows the Twilio logo.

Inside the file, add the following code:

import React from 'react'

export const TwilioLogo = ({ height = '120px' , width = '260px' }) => (
  <div>
    <img
      style={{ height, width }}
      src='https://www.twilio.com/marketing/bundles/company/img/logos/red/twilio-logo-red.png'
      alt='Twilio logo in red.'
    />
  </div>
)

In order for our package to include this, we need to update the index.js file in the src directory.


import { TwilioLogo } from './TwilioLogo'

export { TwilioLogo } 

Lucky for us, this package has already set up npm/yarn link so add we need to do is test it out.

In the example directory, open up the src/App.js file and replace it with this:

import React from 'react'

import { TwilioLogo }  from '@NPM-REGISTRY-USERNAME/react-use-the-things'

const App = () => {
  return (
    <div>
      <TwilioLogo
        height='240px'
        width='520px'
        customStyles={{ border: '1px solid black' }}
      />
    </div>
  )
}

export default App

In your browser, navigate to http://localhost:3000 and you should see something like this:

Working application running in the browser

Nicely done! We’ve created our first custom React component. 🕺🏼 Pat yourself on the back, dance a little maybe, take a quick break and then come back for the second piece 😎

Create Our Custom React Hook

To keep things simple, we’re going to write a very rewrite the counter example in the Introducing Hooks section of the React docs and make a custom useCounter hook. Create a new file called useCounter.js in the src directory and paste the following code:

import { useState } from 'react'

export function useCounter (initialCount) {
  return useState(initialCount)
}

Next, go to the src/index.js file and add our useCounter hook:

import { TwilioLogo } from './TwilioLogo'
import { useCounter } from './useCounter'

export { useCounter, TwilioLogo }

Head back to our /example directory and update App.js:

import React from 'react'

import { TwilioLogo, useCounter } from '@NPM-REGISTRY-USERNAME/react-use-the-things'

const App = () => {
  const [count, setCount] = useCounter(4)
  return (
    <div>
      <TwilioLogo
        height='240px'
        width='520px'
        customStyles={{ border: '1px solid black' }}
      />
      <p>Currently, the count is: {count}</p>
      <button onClick={() => setCount(count + 1)}>Add 1</button>
      <button onClick={() => setCount(count - 1)}>Subtract 1</button>
    </div>
  )
}

export default App

If we rerun npm start from the /example directory, we’ll see we our useCounter in action!

⅔ done so far - woot woot! 🙌 Onto the last part.

Create Our Custom React Effect

Similar to the previous steps, let’s write a custom React effect borrowing the example from the React docs. Create a new file in the src directory called useDocumentTitle.js and add the following code:

import { useEffect } from 'react'

export function useDocumentTitle (count) {
  useEffect(() => {
    // Check that the window and document are defined
    if (typeof window !== 'undefined' && document) {
    // Update the document title using the browser API
      document.title = `You clicked ${count} times`;
    }
  })
}

Update the index.js file to export our new useDocumentTitle:

import { TwilioLogo } from './TwilioLogo'
import { useCounter } from './useCounter'
import { useDocumentTitle } from './useDocumentTitle'

export { useCounter, TwilioLogo, useDocumentTitle }

Inside /example/App.js, let’s update our code to match this:

import React from 'react'

import { TwilioLogo, useCounter, useDocumentTitle } from '@jsjoeio/react-use-the-things'

const App = () => {
  const [count, setCount] = useCounter(4)
  useDocumentTitle(count)
  return (
    <div>
      <TwilioLogo
        height='240px'
        width='520px'
        customStyles={{ border: '1px solid black' }}
      />
      <p>Currently, the count is: {count}</p>
      <button onClick={() => setCount(count + 1)}>Add 1</button>
      <button onClick={() => setCount(count - 1)}>Subtract 1</button>
    </div>
  )
}

export default App

And if we run npm start again for our example, we’ll see useDocumentTitle in action:

Example React component

Hooray! We did it. 🎉 Nice work, team!

Publish Our Package to the npm Registry

Now that we’ve written a custom React component, hook and effect, we’re ready to publish it as a package on the npm registry.  We’ll do this in the following steps:

  1. Login with our npm credentials
  2. Check version
  3. Check your docs
  4. Publish package
  5. Test in a CodeSandbox

1. Login with npm credentials

From the root directory, run the command:


npm adduser

When prompted for your username and password, use the username and password associated with your account when you signed up on the npm registry. It will also ask for you email address, which will be displayed publicly.

2. Check Your Docs

Before you publish your package, make sure the README.md at the root of your directory is up to date. This is what the npm registry will use on the package homepage so it’s essential that yours is up to date. We’ll update the example in the README at the root using the /example/App.js code we used to test our package:

# @GITHUB-USERNAME/react-use-the-things

> a package that gives you custom React things

## Usage…

import React from 'react'

import { TwilioLogo, useCounter, useDocumentTitle } from '@GITHUB-USERNAME/react-use-the-things'

const App = () => {
  const [count, setCount] = useCounter(4)
  useDocumentTitle(count)
  return (
        <div>
          <TwilioLogo
            height='240px'
            width='520px'
            customStyles={{ border: '1px solid black' }}
        />
        <p>Currently, the count is: {count}</p>
        <button onClick={() => setCount(count + 1)}>Add 1</button>
        <button onClick={() => setCount(count - 1)}>Subtract 1</button>
        </div>
  )
}

## License

MIT © [@GITHUB-USERNAME](https://github.com/GITHUB-USERNAME)

3. Check the version

Since this is our first version - 1.0.0 - we don’t need to do anything. But if you do release a package and maintain it, you’ll need to update the version every time you make changes and want to re-publish the package. It’s recommended you use semantic versioning. Check out the npm version command. It will update the version and generate a Git Tag for you 😄

4. Publish Package

This might be the scariest part of this tutorial: publishing your package.

But it doesn’t have to be scary! Remember, we’re going to publish a scoped package so in reality, someone will only find it if they search the npm registry based on your GitHub handle.

Run the following command:

npm publish --access public

Because scoped packages are private/restricted by default, we have to pass the --access public flag. An alternative way to do this is by adding this to your package.json:

"publishConfig": {
  "access": "public"
 }

It costs money to host private packages, so we’re also doing it for that reason 😅

Now if you go to the npm registry website and look under your Packages, you’ll see your package:

Viewing packages on the npm website

And you’ll see that it’s there! Woah! 😱

Last thing you want to do is push to GitHub with git push origin master --tags. This will push the version tags. Super cool, right? 😎 You did it!

5. Test on CodeSandbox

Even though we verified everything works locally with npm/yarn link, it doesn’t hurt to also verify in “production” that it still works. Head over to CodeSandbox and create a new React sandbox. Then under dependencies, add your package:

Code sandbox user interface

Now, we can copy the example from our README and add it to the index.js file in our sandbox. Then we can open up the app in a new tab to see the document title update:

Hello CodeSandbox

 

Verified in a “production” environment - time to share it with all our friends! 🤓

What We Learned Today

If you’ve made it this far, give yourself a pat on the back. We learned a lot today about React and publishing npm packages. Let’s recap on everything we did:

  • Learned about React components, hooks and effects
  • Created our own custom React component, hook and effect using create-react-hook
  • Published on the npm registry

Hopefully now you can see releasing custom React packages on npm is not as intimidating as you previously thought. Lucky for us, we can stand on the shoulders of create-react-hook and npm/yarn link to achieve this quicker than on our own.

If you end up creating your own package, tweet me @jsjoeio and let me know :) Happy open-sourcing!