A beginners guide to turning that little reusable piece of code into its own npm package. NOTE: This is a cross-post that originally appeared in JavaScript January . Background A while back while writing a React that hit a REST endpoint, I wrote a little utility to build a properly encoded Uri path. At the time, I didn’t think much about it. It did the job and I moved on. application Months later, while working on another project, I needed something similar. I set out to find it and copy the code, but I couldn’t remember where I originally wrote it. After a good deal of digging around — both on my local file system and on GitHub — I finally located it. I vowed that this would never happen again. Reduce As I mentioned, the utility builds a Uri path. For example, given a resource of and a userId of , it might return a path to a specific user resource as follows: . “user” “123” "/users/123" The casual reader might be saying, “Why can’t you just concatenate the to the end of the string and call it a day?” Maybe something like this. userId "/users/" const resource = 'users';const userId = '123';const path = `/${resource}/${userId}`; That would be fine if you could swear on your mother’s grave that the name of the resource or the userId did not contain any characters that needed to be Uri encoded — not only today, but forever. What if values weren't just numbers, but handles, like , , etc. And what if there was a handle such as ? This would produce a path of which is an invalid URL. userId "bob" "jim" "this&that" "/users/this&that" Or what if, for example, the user entered their as ? would end up being , which would likely return all users in XML format—not at all what we're expecting. userId "?format=xml" path "/users/?format=xml" We could solve the Uri encoding issue in the previous example like this. const resource = encodeURIComponent('users');const userId = encodeURIComponent('123');const path = `/${resource}/${userId}`; Perfect! It works. But…that’s a lot of effort each time you want to generate a path. This is why I came up with a utility that you hide away from your main logic and can re-use over and over. It incorporates the very useful, and often misunderstood, method, which takes an array of values and reduces them down to a single value. In our case, we take an array of strings and values, and reduce them to a single string. Array.reduce const buildUriPath = (strings, ...values) => (strings.reduce((partialUri, string, i) => (`${partialUri}${encodeURIComponent(values[i - 1])}${string}`))); Use it as shown here and all that work of encoding each variable is abstracted away. const resource = 'users';const userId = '123';const path = buildUriPath`/${resource}/${userId}`; Briefly, it takes two arrays: (the string constants ) and (the templated string values that need to be encoded ). It constructs and returns a single string . strings ['/', '/', ''] values ['users', '123'] "/users/123" OK, that’s not accurate. It is passed an array of strings, but what I’m calling an array of values, is actually a variable number of arguments. I’m using ES6 “rest” syntax to convert the arguments into an array of values. entirely When we reduce over strings, the zeroth element of the strings array is passed as partialUri and iteration starts with the first element, and so on. There are no parentheses behind the call to ? What is this witchcraft? This is called a Tagged Template Literal. It’s a special form of the ES6 template literal that we used above, but it allows us to process it with a function. buildUriPath Remember that we don’t call our code directly. It’s called by the JavaScript’s template literal function after parsing the template into separate elements. Fans of are already familiar with this syntax. It’s a very powerful addition to the ES6 specification. styled-components Reuse So now that I have a super-duper, handy-dandy function, let’s share it with the world so that _everyone_can use it. But the thing is... Even if no one else wanted to use this, I still want to be able to use it myself, over-and-over easily. We can do this by making an npm package. I’m rather keen on the name , so I hope that it’s available... and it is! buildUriPath build-uri-path Because we wrote our utility in ES6, but the world still relies on ES5, we’ll use Babel to transpile it for us. The complete source for everything described below can by found in my . GitHub repo GitHub First create a GitHub account (if you don’t already have one) and then create a blank repo. Clone it to your local drive and change into the directory. Execute to create a skeleton . Be sure to set the entry point to . This will add the following to your file, which instructs the consumer of your package what file to initially execute. npm init package.json lib/index.js package.json "main": "lib/index.js", Install Babel We will be writing our code in ES6, but the reality is that today’s browsers don’t fully support the syntax that we write in. Fortunately for us all, there is a utility called Babel that allows us to transpile ES6 source into ES5 distributable code. To install Babel, execute the following in a terminal of your choice. $ npm install -D babel-cli babel-preset-env You’ll also need to create a file. This tells Babel how to transpile. .babelrc {"presets": ["env"]} Get coding! Open you favorite editor and create a folder with an file. This will be where we place our function which will be exported as . src index.js buildUriPath default The entire source looks like this. const buildUriPath = (strings, ...values) => (strings.reduce((partialUri, string, i) => (`${partialUri}${encodeURIComponent(values[i - 1])}${string}`))); export default buildUriPath; Build Run and you should see Babel build a file. Peek inside of this file if you want to see the ES5 transpiled code. Notice that it is substantially more verbose than it’s ES6 source. This is the syntactic sugar that ES6 brings to the table. npm run build lib/index.js For larger packages consider using a packager such as , but for our small package, publishing ES5 code should be just fine. rollup.js Testing As a developer, you must prove to the world, and to yourself, that your code works under a wide variety of input values by writing lots of tests! They are also critical for . regression Testing is an entire article unto itself. You can read more about testing in the January 1st article “ ” JavaScript JavaScript January But really, what is a JavaScript test? You can, however, see that the tests pass for our package by running . npm test Continuous Integration You should really consider setting up Continuous Integration (CI) such as or . Tests will be run automatically on each push to your code repo. This will help ensure code quality when you have multiple source code contributors. CircleCI Travis Again, CI is beyond the scope of this article, but you can find a rather comprehensive explanation of . setting up Travis CI here Linting Setting up a linter, such as will also help you reduce errors by catching issues before you compile and test. You may want to consider using the popular ESLint configuration from . ESLint Airbnb Scripts We’ll need to add a few scripts to our file to automate things. Add a command to allow us to manually transpile our code. Add a hook so that we can be sure that the tests pass and our code is transpiled automatically whenever we execute . package.json build prepublishOnly npm publish Our scripts section looks like this. "scripts": {"prepublishOnly": "npm test && npm run build","build": "babel src --out-dir lib --ignore '**/*.test.js'","test": "eslint src && jest"}, TypeScript support If you really want to impress, you can optionally add a TypeScript type definition file (the so-called file) so that TypeScript users can have first class type support. d.ts Just create the file , in our case. The file would look like this. types/build-uri-path.d.ts declare module "build-uri-path" {function buildEncodedUri(strings: string[],...values: string[]): string;export default buildEncodedUri;} You also need to reference the file from within your file by adding the following line. package.json "types": "types/build-uri-path.d.ts", See the for complete details. TypeScript documentation And finally… Publish to npm All that’s left to do is publish to npm. But first you must be a user on the npm registry. If you don’t have an account, create one with . Once an npm user has been created, simply type . The script will run—which tests and builds—and if successful, you will have published your first npm package, my friend! npm adduser npm publish prepublish React Now anyone can use your shiny new package. So why don’t we be the first? I’ll use CodeSandbox to install and write a simple React app based on the Component Folder Pattern that uses it. build-uri-path The app hits a REST endpoint to fetch some data. I’m using the as my back end. The front end React app allow the user to type in a resource and an ID. As these are coming directly from an untrusted source (i.e. the user), they need to be encoded. Good thing there’s an npm package that will do just that! Star Wars API You can see the complete app, with source code, running on . CodeSandbox.io You can see the complete app, with source code, running on . CodeSandbox.io The file imports our function and uses it to build the path to send to the backend REST API. loadData.js buildUriPath import buildUriPath from 'build-uri-path';...const path = buildUriPath`/${resource}/${id}`; Conclusion You don’t have to write the next React to contribute a package to the Open Source community. If you see value in your work, then get it out there. Even if you are the only one who benefits, that’s reason enough. But you may be surprised. Others may find it useful, and your meager little package could be the next open source sensation! Thanks to Paul Bouzakis for helping with the TypeScript section and especially to Renato Selenica for fixing my mistaakes. ;) I work at American Express and write for the American Express Engineering Blog. Check out my other works and the works of my talented co-workers at AmericanExpress.io . You can also follow me on Twitter .
Share Your Thoughts