Create a Rich Visual Workspace for React Development with Bit Harmony

Nathan Sebhastian
Frontend Weekly
Published in
12 min readJun 9, 2021

IMPORTANT: Since Bit Harmony is still in its beta phase it is likely that some of the steps in this tutorial will no longer be relevant. If that happens, please check with the official docs.

Bit Harmony is a new version of Bit that offers a modern approach to develop component-based applications using JavaScript. The tool provides you with a rich visual workspace that organizes and showcases your components in action.

By using Bit Harmony, you will be able to:

  • Develop and test your components in isolation.
  • Display the rendered components individually and composed together with other components.
  • Auto-generate dependency graphs for each component, and for the entire workspace.
  • Create rich documentation using MDX: markdown with JSX and auto-generated props table.
  • Share components to your own Bit server or bit.dev.
Bit Harmony running on localhost

This tutorial will show you how to start developing React application using Bit Harmony.

Installing Bit locally

To use Bit Harmony, you need to install Bit Command Line tools. First, open your terminal and install Bit Version Manager (BVM) that will handle Bit installation and manage multiple versions of Bit for your computer. You can use either NPM or Yarn:

npm i -g @teambit/bvm
# or
yarn global add @teambit/bvm

Then, install Bit’s latest version using BVM:

bvm install

Once done, you can check if Bit is installed using bit --version command. If you already have a Bit legacy version installed on your machine, use the bbit command to run Bit's latest version and the bit command for Bit's legacy version.

With Bit installed, you are now ready to create a new Bit workspace.

Creating a new Bit workspace

You can initialize a new Bit workspace by using the bit init --harmony command in an empty folder. Let’s create a new folder called bit-harmony-example and initialize Bit there:

mkdir bit-harmony-example
cd bit-harmony-example
bit init --harmony

The init command will create the following files:

  1. workspace.jsonc - The Workspace configuration file (I will explain this after we try running the workspace).
  2. .bitmap - An auto-generated mapping between tracked components in the workspace and their physical location on the file system. The file-structure of your workspace is entirely up to you.
  3. .bit (directory) - Your local scope, where your workspace's component release versions are stored.

Once the initialize command finishes running, you can run the workspace UI by using the bit start command. Bit will start building the workspace and run the development server at localhost:3000

Running Bit development server

Open your browser and navigate to the development server. You will be greeted with an empty workspace view as follows:

Bit Harmony empty workspace view

The workspace will assist you with developing and examining your components, allowing you to take a step back and see all your components from a higher point of view.

Now that you can run Bit Harmony workspace locally, let’s take a step back and learn how to configure your workspace properly.

Configuring Bit workspace

The workspace.jsonc file generated by Bit earlier is used to write rules that apply to the workspace folder. The configuration is controlled through a series of JSON API exposed by Bit for you to modify as required.

For example, to configure the workspace name, you can change the name property of teambit.workspace/workspace object:

"teambit.workspace/workspace": {
"name": "nsebhastian-workspace"
}

When you use Bit workspace, you are also using Bit dependency resolver, which takes care of managing NPM packages and dependencies for all of your components.

The rules for dependency resolver are configured inside teambit.dependencies/dependency-resolver object. To change the package manager used by the workspace, you can adjust the packageManager property. During my test, I found several errors connected to the way pnpm works, so let’s use Yarn for this tutorial:

"teambit.dependencies/dependency-resolver": {
"packageManager": "teambit.dependencies/yarn",
"policy": {
"dependencies": {},
"peerDependencies": {
"react": "^16.13.1",
"react-dom": "^16.13.1"
}
}
}

Just below the packageManager property, you’ll see the policy property, which registers all dependencies used by the workspace:

"teambit.dependencies/dependency-resolver": {
"packageManager": "teambit.dependencies/yarn",
"policy": {
"dependencies": {},
"peerDependencies": {
"react": "^16.13.1",
"react-dom": "^16.13.1"
}
}

}

When you install new packages, you need to use the bit install command instead of yard add or pnpm install . Bit will handle running the package manager of your choice and register the package to the policy property.

For example, let’s install prop-types and classnames package, which we will use to create demo components later:

bit install prop-types classnames

The policy property will be populated with the new packages you’ve just installed:

"policy": {
"dependencies": {
"prop-types": "15.7.2",
"classnames": "2.2.6"
},

"peerDependencies": {
"react": "16.13.1",
"react-dom": "16.13.1"
}

Finally, you need to set the environment applied to the components managed by Bit workspace. This is set through the teambit.workspace/variants object, which allows you to apply different environments to different folders inside the workspace.

For example, you’re going to use React environment to render React components, so you need to set the variants rules as follows:

"teambit.workspace/variants": {
"*": {
"teambit.react/react": { }
}

}

The “*” symbol means the environment is applied to all components in the workspace. You just need to uncomment “teambit.react/react”: { } on your configuration file.

That will be enough for the completion of this tutorial. If you’d like to learn more about Bit workspace configuration, you can check out its full documentation.

But for now, let’s start developing new React components and test the visual workspace.

Developing React components with Bit Harmony

Bit provides you with a way to generate components using the command line, so you don’t need to create your components manually. First, use the bit templates command to look for available component templates:

$ bit templates
the following template(s) are available
teambit.react/react
react-button (a basic react button)
react-component (a generic react component)
react-button-jsx (a basic react button in jsx)
react-component-jsx (a generic react component in jsx)
react-env (customize the base React env with your configs and tools)

teambit.harmony/node
node-env (customize the base Node env with your configs and tools)
teambit.harmony/aspect
aspect (extend Bit capabilities)
teambit.react/react-native
react-native-env (customize the base React Native env with your configs and tools)

As you can see from the output above, Bit has several templates for React components. The one with -jsx suffix will generate .jsx files while the others will generate .tsx files. I will use .jsx extensions to simplify the tutorial.

You can use one of the templates by using bit create command. The syntax is as follows:

bit create template-name component-name --path --namespace

The --path parameter allows you to change the folder where the component is created, while the --namespace parameter will generate a namespace to group your components together. It’s recommended to group your components together by their type, such as ui for UI components and hooks for custom hooks.

This tutorial will focus on creating React UI components, so let’s start by developing a simple button component that has two different CSS styles based on the variant prop it receives.

A repo for the project can be found here.

Create a new <Button> component by using the react-button-jsx template as follows:

bit create react-button-jsx button --path components --namespace ui

Bit will generate all required files for the component as follows:

components
└── ui
└── button
├── button.composition.jsx
├── button.docs.mdx
├── button.jsx
├── button.spec.jsx
└── index.js

The index.js file serves as the main entry point where Bit will look for the component. It simply exports the component:

export { Button } from './button';

Your component code is stored inside button.jsx file:

import React from 'react';export const Button = ( {children, ...rest} ) => {
return <button {...rest}>{children}</button>
};

The button.docs.mdx is used for the visual workspace documentation, while the button.composition.jsx holds the various compositions for the component. Finally button.spec.jsx is for writing test scripts for the component.

You will learn more about documenting, creating compositions and testing later. For now, let’s focus on creating the button component.

Open the button.jsx file and write the following content:

import React from 'react';
import cs from 'classnames';
import PropTypes from "prop-types";
const styles = require('./button.module.scss');export const Button = ({ variant, disabled, children, ...rest }) => (
<button
className={cs(styles.base, styles[variant])}
disabled={disabled}
{...rest}
>
{children}
</button>
);
Button.propTypes = {
/**
* button variant style
*/
variant: PropTypes.oneOf(["primary", "secondary"]),
/**
* disabled attribute
*/
disabled: PropTypes.bool,
};
Button.defaultProps = {
variant: "primary",
disabled: false,
};

The <Button> style is based on the button.module.scss file, so let’s write a simple styling for the component as follows:

.base {
cursor: pointer;
color: white;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
background: #0C7DF7;
&:disabled {
border-color: #a5a5a5;
background-color: #a5a5a5;
cursor: not-allowed;
}
}
.secondary {
background: #DB7093;
}

Now that your component is ready, it’s time to add some documentation for the component. Open button.docs.mdx file and write a simple documentation for the component as follows:

---
description: A styled-components button.
labels: ["react", "styled", "button"]
---
import { Button } from './button';### UX Guidelines- Place buttons where you expect to find them. Do not force users to "hunt for buttons".
- Do not use generic labels for your buttons. Use verbs that clearly explain the button's function.
- Size buttons in proportion to their importance.
### Using the 'button' component```jsx live
<Button variant="primary" onClick={() => alert("Clicked!")}>
Click here
</Button>
```
### Disabling the 'button' component```jsx live
<Button disabled>Click here</Button>
```

Bit will parse the Markdown code to generate documentation for your components. Bit allows the following frontmatter properties for your Markdown file:

  • displayName string overrides the component name.
  • description string overrides the component description/abstract.
  • labels string[] overrides the component labels/tags.

You can also add Bit’s live playground to see the rendered component using the live keyword in your code block:

```jsx live
<Button disabled>Click here</Button>
```

Now that you have the <Button> component ready, run the bit start command again. The documentation is available for you in the Overview Tab:

component documentation inside Bit Harmony workspace

Next to the Overview Tab, you have the Compositions Tab, which allows you to test various potential usages for the components imported to the application. Each composition is a standard usage of a component (requiring no special syntax) that is exported with a name.

Let’s create three compositions for the Button component in button.composition.jsx file by writing the following content:

import React from "react";
import { Button } from "./button";
export const PrimaryButton = () => {
return (
<Button variant="primary" onClick={() => alert("Clicked!")}>
Primary Button
</Button>
);
};
export const SecondaryButton = () => {
return (
<Button variant="secondary" onClick={() => alert("Clicked!")}>
Secondary Button
</Button>
);
};
export const DisabledButton = () => {
return (
<Button disabled variant="primary">
Disabled Button
</Button>
);
};

You’ll see the compositions rendered both in the Overview Tab and the Compositions Tab:

Button Compositions Tab

The compositions tab will render each of your compositions on a separate page. You can also open a new browser to view just the components without the workspace by clicking on the new tab icon on the most right side:

Opening compositions in a new tab

Testing React components with Bit

Bit helps you to test React components in isolation. All you need to do is to provide a file with the following pattern:

  • *.spec.[ts|tsx|js|jsx]
  • *.test.[ts|tsx|js|jsx]

Bit React environment will use Jest to test React components by default, but you will need @testing-library/react package too, so let’s install that first:

bit install @testing-library/react

Once installed, head to the button/ folder to open button.spec.jsx file and write a simple test script as shown below:

import React from 'react';
import { render } from '@testing-library/react';
import { Button } from './button';
describe('Button', () => {
it('should render a test button', () => {
const { getByText } = render(<Button>test button</Button>);
const testButton = getByText(/test button/i);
expect(testButton).toBeInTheDocument();
});
});

Nothing too fancy with the test script. It only renders the button component and gets a button with the text “test button”, expecting it to be in the document. Run the test using bit test command:

Running bit test command

You can also see the result of the test in the workspace Tests Tab:

Button component test result

And that’s how you can test your components with Bit Harmony. Let’s look at the final Tab in our development workspace: the Dependencies Tab

Bit Harmony Dependencies Tab

The Dependencies Tab from the workspace shows any dependencies that your component has. The dependency graph generated will only show dependencies between components, so dependency to any Node modules like react and react-dom won’t be displayed in this view.

Since the <Button> component doesn’t import any other component from the workspace, there’s no dependency in its dependency graph:

Bit dependency graph view

To see the dependency graph in action, you need to create a new component that imports another component from the workspace. Let’s create a <Jumbotron> component that will import the <Button> component.

To create a new component, you need to use the bit create command again :

bit create react-component-jsx jumbotron --path components --namespace ui

Then write the following code in jumbotron.jsx file:

import React from "react";
import cs from "classnames";
import PropTypes from "prop-types";
import { Button } from "@my-scope/ui.button";const styles = require("./jumbotron.module.scss");export const Jumbotron = ({ title, description, ...rest }) => (
<div className={cs(styles.jumbotron)}>
<h1>{title}</h1>
<p>{description}</p>
<Button {...rest}>Confirm</Button>
</div>
);
Jumbotron.propTypes = {
/**
* post title
*/
title: PropTypes.string.isRequired,
/**
* date
*/
description: PropTypes.string.isRequired,
};

Next, create the jumbotron.module.scss file with the following content:

.jumbotron {
padding: 4rem 2rem;
padding-right: 60px;
padding-left: 60px;
border-radius: 6px;
color: #000;
background-color: #E9ECEF;
}

The documentation for <Jumbotron> component will be as follows:

---
description: A styled-components card.
labels: ['react', 'styled', 'jumbotron']
---
import { Jumbotron } from './jumbotron';### UX GuidelinesThe card component is available for use### Using the 'Jumbotron' component```jsx live
<Jumbotron
title="Hello World"
description="This is a jumbotron. You can use it to draw extra attention for some special content or information" />
```

Finally, adjust the test script in jumbotron.spec.jsx file as follows:

import React from "react";
import { render } from "@testing-library/react";
import { Jumbotron } from "./jumbotron";
describe("jumbotron", () => {
it("should render with the correct text", () => {
const { getByText } = render(
<Jumbotron
title="Hello World"
description="This is a jumbotron. You can use it to draw extra attention for some special content or information"
/>
);
const rendered = getByText("Hello World");
expect(rendered).toBeTruthy();
});
});

Now run the workspace again with bit start and head over to the Dependencies Tab of the jumbotron component. You’ll see the button component listed as the dependency of jumbotron component:

Bit dependency graph in action

The Dependencies Tab allows you to get a better perspective on which components your current component relies on.

Conclusion

Although it’s still in the Beta version, Bit Harmony offers a rich visual workspace that allows you to be more productive with your component development.

By combining Bit workspace with Bit CLI tool, you will have both a rich visual workspace for local development and a system to distribute components from a design library or a project into a standalone reusable package and utilize it across different projects.

For more information, check out Bit Harmony documentation.

Share components between projects using Bit

After you finished developing your components, you can also share your components to bit.dev or your own Bit server. Once shared, you can reuse those components in another project by installing them through your favorite package manager or Bit CLI tool.

Here are some examples of sharing components using Bit:

--

--

Nathan Sebhastian
Frontend Weekly

Web Developer and Writer. Sharing what I learn on productivity and success.