Create a Rich Visual Workspace for React Development with Bit Harmony
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.
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:
workspace.jsonc
- The Workspace configuration file (I will explain this after we try running the workspace)..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..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
Open your browser and navigate to the development server. You will be greeted with an empty workspace view as follows:
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:
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:
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:
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:
You can also see the result of the test in the workspace Tests Tab:
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:
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:
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: