Sharing React components using Bit — a quick guide — Part One

Giorgos Sideris
Travelex Tech Blog
Published in
9 min readOct 31, 2018

Introduction

One of the long-standing problems developers face — in personal or work projects — is the effectiveness of code sharing and more specifically component sharing and collaborative work on these components.

Let’s examine the following scenario. We have a collection of base React components that have simple or little functionality, for example a Button component, that has different types of styling that can be used using the appropriate props. Ideally, we would like to use this component on every Front-End project in the company, or at least where it’s actually useful.

What would be the ideal sharing concept at this point? We want to easily plug in the aforementioned Button in a new React project, and use it as is. We also might want to use the component, but the requirements change in the meanwhile. In this case, we want to import the component, make some changes, tag those changes as an version update on the component, and update all occurrences of the component in various Front-End projects.

There are a few ways to create this kind of setup in our projects. We can create repositories for every component we create, and use them as npm packages. This, however, requires a lot of maintenance of the npm packages, and can be confusing and time-consuming for a large collection of components.

This is where Bit comes to solve these problems. Using bit we can create our own (private or public) scope to store our components. These components then can be imported using NPM/Yarn to use without changes, or via Bit to import locally and make changes.

First example of our `Button` React component stored on bitsrc.io and exported via Bit

Storing the components in our scope, we can also add examples, as above, and documentation using JSDoc. For this component, we added title, description, examples and properties in our main js file.

/**
* @render react
* @name Button
* @desc Button component with different styles
* @example
* <div><Button type="button"> Primary </Button>
* <Button styleName="secondary" type="button"> Secondary </Button>
* <Button styleName="tertiary" type="button"> Tertiary </Button>
* <Button styleName="outline" type="button"> Outline </Button>
* <Button styleName="link" type="button"> Link </Button></div>
* @property {string} classname - classname
* @property {boolean} fullWidth - makes button fullwidth on true
* @property {boolean} disabled - makes button disable on true
* @property {string} type - one of button, submit, reset
* @property {string} styleName - bione of primary, secondary, tertiary, outline, link
*/
Documentation created using JSDoc

But first of all, let’s take a step back and take a look at how we can install and use Bit in our project

Setting up Bit

  • Install bit globally by npm install bit-bin -g or with package manager of your choice (Yarn / Brew)
  • Go into the project directory and execute: bit init . This creates a bit.json file that is the configuration for the local bit workspace, and a .bitmap file that is used to map the paths of your tracked components and their dependent files.
  • Make sure you are registered in bitsrc.io and you have created the scope that you wish to store your components in. It can be public or private. In our case it’s private.
  • Ensure that you have access to this scope by authenticating through the Bit CLI: npm login --registry=https://node.bitsrc.io --scope=@bit . This will allow us to import components using the @bit prefix.

Configuring Bit

Let’s look now at how we would like our Bit configuration to be. We are going to change two basic configuration options: componentsDefaultDirectory and compiler.

componentsDefaultDirectory: This defines the default directory our newly locally imported components will be stored. In our case, all components are stored in src/components folder, so we set it as: src/components/{namespace}/{name}
Namespace and name are two variables we can use. For example the first component we created was tracked as global/button. The namespace is global and the name is Button. We use this default directory because of our components’ structure in our project, and we want to be consistent.

compiler: Bit uses compilers, which are environments — a special kind of extension, in order to build components. There are a few ready-to-use compilers in Bit’s envs scope. In our case we are going to use the webpack-css-modules compiler, since we are using webpack and css modules. To use this compiler and store it in our configuration as our default compiler we use the provided bit import command and we add the --compiler option, so bit import bit.envs/bundlers/webpack-css-modules --compiler
This command will import the compiler and change the bit.json file to document this as our default compiler.

Finally, our bit.json looks like this:

{  "env": {    "compiler": "bit.envs/bundlers/webpack-css-modules@0.0.8"  },  "dependencies": {    "bit.envs/bundlers/webpack-css-modules": "0.0.8"  },  "componentsDefaultDirectory": "src/components/{namespace}/{name}",  "packageManager": "npm"}

More configuration options can be found here.

Tracking components

In case we want to add a new component to our Bit repository, to enable it to be used across other projects, we can use the add command.

The component we want to track, located in the src/components folder in our project

We wish to track and export the Titles component in namespace global :

bit add src/components/Titles --id global/titles

We define the component’s directory, and the namespace/name of it with the --id flag.

Our component with all its files are tracked now. We can exclude files from tracking using the — exclude tag

Now, we want to see the current status of our bit project and we can do that by using bit status . Components that have been changed will show up here.

Bit shows the component we tracked

If we want to see all the components in our local scope, including the ones we didn’t change, we can use bit list .

Another useful command is bit show <namespace>/<name> which displays all the relevant information about a specific component.

Our component is now successfully tracked, let’s take a look at the changes in our local .bitmap file:

Bit tracks our component’s files

If we wanted to track all our components with a single command in the same namespace we could use this: bit add src/components/* --namespace global

This would track every folder in src/components directory as a separate component. Namespace would be global and name would be the name of the corresponding folder.

Tagging and exporting components

When we make changes in a tracked component, we can tag these changes, as a new version for our components. Let’s look at an example:

We will add documentation to our main file as described above with JSDoc formatting.

Note: to correctly render a component on the remote Bit workspace and display the example, we need to export our react class as default.

Added documentation to the component

Now that we made the change, let’s tag the Titles component with a new version. Since we just created this component, this is going to be the initial version of it. We run again bit status and we see that our component is listed under modified. We can tag it by using bit tag

Different options for tagging:

  • bit tag --all tags all components by bumping the previous version (eg. a component with previous version 1.0.0, after this will have a version of 1.0.1.
  • bit tag <namespace>/<name> , same as above but for a specific component
  • --major : use this to bump major version
  • --minor : use this to bump minor version
  • --patch : use this to bump patch version (default)
  • bit tag <namespace>/<name> <version> . Tag a specific component to a specified version.

We are going to use the last option for our first tagging of this component:

Successfully tagged our component’s version as 1.0.0

Now, our component is tracked and tagged and is ready to be exported to our remote workspace to be used by other developers. The component will be exported in an isolated environment, with all its dependencies automatically tracked, so that it can be used in any React project. Let’s export it!

Our component is now exported successfully, and can be imported using npm/yarn and bit for making changes to it.

Note: using the --eject flag, when exporting will eject this component from our local workspace and import it as an external dependency. Warning: this doesn’t change the import statements we already use, we have to change these by hand.

Our component is exported on our remote scope and example and documentation look valid.

In our project, I created a custom script called tag-export that tags all components and exports them to our scope, we can run it using yarn tag-export .

Importing components

We covered a simple case of tracking, tagging and exporting a component to our remote workspace. Now, we want to import and use this component on another project. Going to the component’s specific page on bitsrc.io we see three options for importing a component, which leads us to two different cases:

Importing a component using npm or yarn

This is the case where we want to use the component as is, without making any changes to it, and adding it as an external dependency.

  • npm i @bit/<username>.<scope>.<namespace>.<name>
  • yarn add @bit/<username>.<scope>.<namespace>.<name>

The component will be added on our node_modules folder and can be used as an external dependency. We created an empty react project and imported it.

Then we import it in the app by: import Title from '@bit/<username>.<scope>.global.titles'; and then we use it.

Our Title component is successfully imported and renders as expected.

Importing a component using Bit

Let’s try now to import a component using Bit, to make local changes, tag the new version and export it while ejecting it. This will examine if Bit can allow us to perform the ideal scenario we defined in the Introduction of this article.

We import it using: bit import <username>.<scope>/<namespace>/<name> Notice that @bit is not needed to import as opposed to npm/yarn

The component is imported into the directory we specified in our bit.json file

That’s it! Our component is successfully imported and we can start making changes! 🙏

Note: We can still use the previous import declaration import Title from '@bit/<username>.<scope>.global.titles'; because bit import created a symbolic link from the corresponding node_modules folder to the actual folder we are editing now :)

Important Note: in order to avoid linting errors when importing a component via bit (webpack compiler builds components in UMD format, to be able to be used anywhere), we need to eject our react app and add this to our package.json to avoid eslint complains:

"eslintIgnore": [  "src/components/*/*/dist",  "src/components/*/*/node_modules"],

Titles component is now imported and we can make changes to it (to preview changes use bit build)

Following the instructions above: we make the changes we want in the component and we build it to preview it. If changes satisfy us, we can tag a new version for the component and export it using the--eject flag. After that our component will again be used as an external dependency.

Updating the component in other places it is used

After exporting the new version with the required changes, any project that uses the component and we need to update its version, we simply need to run

npm install

or

bit install

and the component will be updated in our project if there is a new version available

Summary

This article covers most basic functionalities of bit and provides use cases and examples of a Front-End React project that shares components with other React projects. Next up, global css modules, theming, testing :)

Go to Part Two, exporting a component containing all our Sass variables!

--

--