Creating React NPM packages with ES2015
Usually, when you want to use some React components, you probably search for them on Npm, and it's fantastic that React is embracing the Npm ecosystem. Let's take a look at how you might want to prepare a React Npm package to be able to use it in your projects, publish on Npm, and share it with others.
With ECMAScript 2015, you can use a new JavaScript syntax and many cool, new features. There is no reason why you shouldn't use it when writing an Npm package. Of course, it's better to transpile it to the ES5 standard because some people will use only ES5 in their projects. However, you can write in ES2015 with the help of Babel, and you'll be able to transpile it to ES5 automatically. We also need to remember about tests and linting. That's all possible with the workflow and boilerplate, which will be described here. Of course, you'll be able to download it and build your own React Npm package upon it.
What we'll cover here:
- files and folders structure
- configuration for tests
- configuration for linting
- configuration for transpilation
Files and folders structure and relations
Let's take a look at the boilerplate, which we will describe here. You can find it here: react-npm-boilerplate. This is based on excellent work by the Kadira.io team. They've built a boilerplate for standard Npm packages called npm-base. The version for React has a couple of changes, but generally, this is almost the same. So when you want to prepare a standard Npm module, you can use npm-base
, and when you need to create the React component, take a look at react-npm-boilerplate
.
Let's get back to the file and folder structure. As you can see, in the react-npm-boilerplate
repository, we have some configuration files in the root directory. We'll talk about them later. For now, the essential files are index.js
and package.json
. As you probably know, package.json
is a standard Npm configuration file. In the index.js
file, we have the main export. It points to the dist
folder created after the prepublish
task has been run. It's configured in the scripts/prepublish.sh
file, and what it does is transpilation to ES5. It will place all transpiled files in the dist
folder. We'll talk about that later.
You will work in the src
folder. You can write your React component code there. If you look in the repo, you'll find an example component to make it simpler to start. Also, in the src
folder, we have the __tests__
folder. There are your tests which we'll cover later. For now, it's good to know where the test files are located.
You can find the ESLint configuration file in the root directory, which you can, of course, change and adjust to your needs. This is just the config that I used recently.
This is all about the file structure. In short, you need to work in the src
folder and then transpile with the prepublish
task into the dist
folder. You can run many tasks like testing and linting. It will take your files from the src
and __tests__
folders and process them.
Next, we'll take a closer look at the package.json
where all tasks configuration is.
Test configuration
Tests are crucial here. We want to be able to run automatic tests for our React component. We may even want to run them in the background with the --watch
flag so that our automated test cases will validate every change. Ok, but what exactly do we have here? We use awesome tools like Mocha and Enzyme to test React components. If you don't know them, you can read all about these projects on the Internet. They are projects which provide many valuable tools for testing. All test files should be located in the __tests__
folder. This is how it is configured. You can change it if you want in the package.json
file and some other places.
Test tasks are configured in the package.json
file. You can run them by:
npm test
- if you want to run tests and lintingnpm run testonly
- if you want to run only testsnpm run test-watch
if you want to run tests, watch all files and rerun the tests if something changes
Tests use Mocha runtime and Enzyme library. Sinon and Chai are also used here. You can find example test cases in the src/__tests__
folder. In the package.json
file, we have provided Mocha options. This is important because we can include paths for test files and all possibilities and environment configuration for Mocha, which should be provided. In our case, we want to pass some crucial setups before we run tests. Here we need the scripts/mocha_runner
file. You can open it and see what it's about. Because we need to test DOM in the Node command line environment, we should use the JSDOM library, which will emulate DOM for us. This is important because some tools from the Enzyme library need this configuration, such as the mount tool.
Everything you need to test your React component is configured in this boilerplate. You also have a test case for an example React component. There are three main tools used from Enzyme. You can see it in the src/__tests__/index.js
file.
When you finish your test cases, you can always run npm run testonly
in the console to check how it's going.
Linting configuration
For linting, we use ESLint, which is, in my opinion, the best JavaScript linter right now. ESLint configuration file is called .eslintrc
, and you'll find all rules there. You can, of course, modify it and adjust it for your needs. You'll find all possible configuration rules on the ESLint official website. In this boilerplate, I've provided rules which I usually use.
We also have some linting tasks configured here. They are:
lint
- run eslint command for src folderlint-fix
- fix all ESLint problemstest
- you can also run ESLint with tests
Transpilation configuration
You can also write your React components using ES2015. Then, when you are ready, you can transpile it to the ES5 standard. All files will land in the newly created dist
folder, and these files will be used as your main component files after publishing them to Npm.
The transpilation process is possible with Babel tools which are responsible for providing proper ES5 transpiled code. The configuration is quite simple. We use some of Babel's tools which are listed in the package.json
file. We also use a special runtime file - scripts/prepublish.sh
- which is attached as a prepublish Npm task. So whenever you run npm publish
or npm pack
, the prepublish
hook should be run, and all your files from the src
folder should be transpiled and copied into the dist
folder. You can, of course, run it by hand by npm run prepublish
.
The prepublish. sh
file is quite simple. You can open it and see how it looks. We have here the babel
command-line tool call, which takes some options. We provide a plugin for translation transformations by using the --plugin
flag. As a default, we use the transform-runtime
plugin. But if you need to, you can also use, for example, transform-es2015-modules-umd
, when you need a Universal Module Definition pattern in your transpiled ES5 files. Just remember to add this plugin to your package.json
dependencies. You will find its full name in the Npm repository. Of course, this is just an example, and you can find more transformation plugins on Babel's website. Next, we also need to pass output paths - here it is the dist
directory, and we also want to ignore the __tests__
folders.
This is all you need to transpile your files to ES5 format. Of course, you can read more about Babel and its configuration on their website.
Some closing words
This is a short and general description of an Npm package boilerplate designed to use with React when building React components with ES2015. It provides testing and linting configuration and also Babel transpilation. You can use it as a starting point when you decide to create React reusable components that you want to publish on Npm. This boilerplate is based on an awesome npm-base repository. Check it out too.
For more information about the topic, I encourage you to read about these tools:
- Babel
- ESLint
- Mocha
- Enzyme
- Chai
- Sinon
- JSDOM
Boilerplate described here:
Let me know what you think about it. Feel free to put your questions in the comments below. I'm also on Twitter.