
Building an npm Package
If you're a JavaScript developer, you've almost certainly used npm before. The Node Package Manager is a registry that allows developers to package up code and share it using a common set of commands - most commonlynpm install package-name
. Our own Node.js SDK is available on npm under@deepgram/sdk.
In this post, we'll create, publish, install, and use our first npm package. We'll then extend the functionality and end up with a more complex package that will let users queryThe Open Movie Database.
Our final class-based package code can be found athttps://github.com/deepgram-devs/npm-package.
Before We Start
You will need:
- Node.js installed on your machine -download it here.
- An npm account -get one here.
- An Open Movie Database API Key -get one here and be sure to use the verification link in the email with the key.
Create a new directory and open it in your code editor of choice.
Creating an npm Package
Create apackage.json
file and populate it with minimal information required for an npm package:
{"name":"@username/first-package","version":"0.0.1"}
Thename
must be unique across all of npm. To aid this, and help list packages with the same author, we can 'scope' packages to a user or organization. Replaceusername
with your npm username to scope it. Some other notes about choosing your package name:
- You cannot use uppercase letters.
- You can only use URL-safe characters.
- The maximum character length is 214.
Theversion
should followsemantic versioning, which isNUMBER.NUMBER.NUMBER
. Every time we publish an update to our package, the version must be different from previously-published versions.
If not specified, the default file for your project will beindex.js
. Create a file and open it in your code editor:
constvalue=42module.exports=value
This is a viable, though not terribly useful, npm package - it will always return a fixed value of42
. Themodule.exports
value can be anything - a fixed value, an object with multiple values, a function, a class, or any other data.
While fixed values may have limited use, they are useful in some contexts - theprofane-words
package I used in myautomatic profanity censoring post use a fixed array value to include a list of almsot 3000 profanities instead of me needing to include them a more manual way.
Publishing an npm Package
Open your terminal and navigate to your project directory and run the following commands:
npm loginnpm publish--access=public
You have now published your first ever npm package - congratulations! If you go tohttps://www.npmjs.com/package/@username/first-package you should see it. Reminder: if ever you are publishing again, you must increase the version inpackage.json
,or you will get an error.
Testing Your npm Package
Want to use your package locally to test it before publishing? Create a new file in your repository calledscratchpad.js
(you can call it anything - this is what I use) and open it on your code editor:
constfirstPackage=require('./index.js')console.log(firstPackage)// 42
Run this file withnode scratchpad.js
.
If you want to exclude this file from being downloaded by users when they install your package, add it to a.gitignore
file. Create one now and enter the filenames you want to be excluded (one per line):
scratchpad.js
Using Your npm Package
Create a brand new directory outside of this project. Navigate to it in a terminal, and type:
npm install @username/first-package
Create anindex.js
file to require and use the package:
constfirstPackage=require('@username/first-package')console.log(firstPackage)// 42
Exporting Functions
As mentioned above, you can export any JavaScript value or datatype in your package. Replace the content of yourindex.js
with the following:
constvalue=42functionsum(a,b){returna+b}module.exports={value,sum,}
This is exporting an object with both the fixed value and the function. Updatescratchpad.js
and then rerun it:
constfirstPackage=require('./index.js')console.log(firstPackage)// { value: 42, sum: [Function: sum] }console.log(firstPackage.sum(1,3))// 4
You may have seen object destructing when requiring packages. Here's how it looks:
const{sum}=require('./index.js')console.log(sum(1,3))// 4
This takes thesum
property in the object returned by our package and makes it available as a top-level variable calledsum
. This is what we do with ourDeepgram Node.js SDK:
const{Deepgram}=require('@deepgram/sdk')
Exporting Classes
Exporting one or more functions is quite a common behavior of npm packages, as is exporting a class. Here's what interacting with a class-based package looks like courtesy of the Deepgram Node.js SDK:
const{Deepgram}=require('@deepgram/sdk')constdeepgram=newDeepgram('DEEPGRAM_API_KEY')deepgram.transcription.preRecorded({url:'https://static.deepgram.com/examples/nasa-spacewalk-interview.wav',}).then((transcript)=>{console.log(transcript)})
Let's create our own exported class for the Open Movie Database. First, install theaxios
package that will help us make API calls. In your terminal:
npm install axios
Once you do this take a look atpackage.json
- thedependencies
section will be created for you. When users install your package, it will also install axios for them, along with axios' dependencies, and so on.
Replace the whole content ofindex.js
with the following:
constaxios=require('axios')classOpenMovieDatabase{constructor(apiKey){this.apiKey=apiKey}asyncget(parameters){try{const{data}=awaitaxios({method:'GET',url:'http://www.omdbapi.com',params:{apikey:this.apiKey,...parameters},})returndata}catch(error){console.log(error.response)throwerror.response.data}}}module.exports=OpenMovieDatabase
Replacescratchpad.js
with the following:
constOpenMovieDatabase=require('./index')constomdb=newOpenMovieDatabase('YOUR_KEY_HERE')omdb.get({t:'Inside Out'}).then((results)=>{console.log({results})}).catch((error)=>{console.log({error})})
Once the package is required, an instance needs to be created. Theconstructor
we define expects anapiKey
which is then stored in that instance. When using the package, we only need to provide the key once and then useomdb.get()
as many times as we want without needing to provide our key as it is automatically included in the API requestparams
. Nifty, right?
Before publishing this again, be sure to addnode_modules
to a new line in your.gitignore
.
Wrapping Up
This package lacks lots of features I would expect as a user:
- More robust error handling.
- Checking required parameters are provided and providing useful errors if not.
- Splitting the 'get' and 'search' requests.
Our final class-based package code can be found athttps://github.com/deepgram-devs/npm-package.
When putting together my first npm packages, I found most tutorials stopped at the most basic examples or assumed lots of additional knowledge. I hope this has provided more helpful context and helped you get your first package published. If it did - please let us know what you've published so we can celebrate together - we are@DeepgramDevs on Twitter ordevrel@deepgram.com via email.
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse