Creating a Shareable and Reusable Development Environment for Your Javascript Project

Building a custom development environment for a JavaScript project

Lakindu Hewawasam
Bits and Pieces

--

Reusability has become a go to for software developers. This is especially true when you’re part of an organization undertaking multiple projects. You might have to reuse certain design components, but more importantly, you’ll reuse coding standards that you’ve established. This can include rules like:

  1. File naming conventions
  2. Test configurations
  3. Linting rule sets
  4. Files to be generated — For example, if you create a React component, you’d likely need to create a test case definition file, a documentation and even a preview pane for that component to define its usage.

Manually ensuring that every component in your app adheres these guidelines is tiring. You’d have to manually set up linters, test frameworks and different shell scripts to create components with custom files.

Luckily for us, we can create reusable dev environments with Bit to overcome these issues!

To check out my dev environment, visit my Bit Scope

A Custom Dev Environment in Bit

What is a Dev Environment?

I’ve played around with Bit and Dev Environments over the past few months, and it’s pretty cool.

A Dev environment combines common tasks such as compiling, testing, linting, preview and cenralizes all configuration files in a single resuable component you can set on your components.

So in a nutshell, this dev environment provides your Bit component a runtime for it to work.

Note: A Bit Workspace isn’t language specific. You can create components of any platform — React, Vue.js, AWS Lambda, Express. The dev environment component essentially provides the runtime for your component.

How Does a Dev Environment Work?

Let’s dig deeper to find out how a dev environment works in Bit. To do so, let’s look at a scope I’m currently maintaining:

If you look closely, you’ll see a component called [my-react-env](https://bit.cloud/dummyorg/fsd/envs/my-react-env). This is essentially a React Dev Environment that I created. As you can see, the other React components: entities/blog/ui/, entities/blog and everything else use the my-react-env as shown in the dependency graph above.

This means that every component in my scope uses the my-react-env as the starting point. So, whenever I create a component, I tell Bit to use the my-react-env as the environment for my component. By doing so, the newly created component will inherit all the dependencies, linting configurations, test configurations I've added onto the env.

If you observe the environment closely, you’ll notice that it has these set of files. These files essentially help build up the “boilerplate” that your components will inherit.

For example, if you open up the env.jsonc file, you'll see a bunch of dependencies:

This is similar to a package.json file in a basic React project. So, when you create a React component using this env, the new React component will have all of these packages accessible to it.

Likewise, you have different files:

  1. eslintrc.js: You can customize this file to add your custom ESLint rules apart from the native ruleset defined by Bit
  2. jest.config.js: You can customize this file to modify the behavior of Jest for all the components that use this env.
  3. prettier.config.js: You can customize this file as you would on a normal Prettier config file to help modify the formatting behavior done by Prettier.
  4. tsconfig.js: You can customize this file to modify the TypeScript behavior.
  5. webpack.config.ts: You can customize this file to modify bundling behavior through Webpack.

Generally, you wouldn’t have to modify any of these files as every environment you create natively inherits configuration files from Bit.

But, if you have a use case that isn’t offered natively, you can customize the file to achieve this behavior.

After you’ve configured your env, all you’d have to do is create a component using that env and you’re good to go!

How To Create a Dev Environment with Bit?

The dev environment immediately addresses all of the pain points we discussed in the start. So, why don’t we build on ourselves and see it in action?

Step 01: Pre-requisites

Let’s first install Bit. To do so, run the following command:

npx @teambit/bvm install

To verify your installation, run the following command:

bit --version

If you’ve installed Bit successfully, you should see the output shown below:

Next, you’ll have to create an account on Bit Cloud. Bit Cloud will let you host your dev environment in a remote scope. This will let you use the environment in any project you’re working on.

After you’ve created an account on Bit Cloud, you can create a scope.

The scope is where any Bit component you create will be hosted. This lets other developers consume and collaborate on it. So if you host your dev environment on a Public scope, the whole world can use it as a runtime in their component.

For this article, I’ve created a scope — dev. After you've created the scope, we can start building the dev environment.

Step 02: Creating a Bit Workspace

Next, you’ll have to create a Bit workspace. This can be accomplished using the command:

mkdir workspace && cd workspace && bit init

Next, navigate to your workspace.jsonc and update the defaultScope entry with the following - <<YOUR BIT USERNAME>>.<<YOUR SCOPE NAME>>. In my case, it'd look like this:

This ensures that all components that I create in this workspace will by default be maintained in the specified scope.

Note: You’ve got to understand that a Bit workspace isn’t tied to any development environment.

In fact, you’ll only have a bare directory structure:

Your Bit workspace is only a temporary space for development. You can dispose your workspace once you’ve exported your components to the Bit scope, and later create a new workspace and resume working.

So, in reality, you need “dev environments” to build components.

Step 03: Building a React Developer Environment

And that’s where Step 03 comes into the picture. Let’s create a custom environment to showcase this. Since React is prominently used in the industry, let’s create a React Dev Environment.

This can be done using the command:

bit create react-env envs/react --aspect teambit.react/react-env && bit install --add-missing-deps

After you’ve run the command, you’ll see the output:

If you get this output, you’ve successfully created your custom React environment by extending the base React env offered by Bit — teambit.react/react-env.

Launch your Bit server to explore the env using the command:

bit start

Next, visit “localhost:3000” and you should see your env:

You’ll see the same files we discussed earlier.

Step 04: Customizing the Environment

Next, let’s customize this new environment to make it ours! Let’s say that we want the following requirements:

  1. The environment should support MUI
  2. The environment should disallow Camel Case variables

To support MUI, you can simple add the MUI libraries to your env.jsonc as follows:

{
/**
* standardize your component dependencies.
* @see https://bit.dev/docs/react-env/dependencies
**/
"policy": {
/**
* peer dependencies for components using that env.
*/
"peers": [
{
"name": "@mui/material",
"version": "^5.15.5",
"supportedRange": "^5.15.5"
},
{
"name": "@emotion/react",
"version": "^11.11.3",
"supportedRange": "^11.11.3"
},
{
"name": "@emotion/styled",
"version": "^11.11.0",
"supportedRange": "^11.11.0"
},
// rest of your dependencies
]
},
// remaining config
}

Next, run the command:

bit install --add-missing-deps

This will install the dependencies that you’ve just defined in your env onto your workspace.

Next, lets update the ESLint ruleset to disallow Camel Case variables. To do so, open your eslintrc.js file and update it as follows:

/**
* @see https://bit.dev/reference/eslint/eslint-config
*/
module.exports = {
extends: [require.resolve('@teambit/react.react-env/config/eslintrc')],
rules: {
camelcase: ["error", { "properties": "never" }],
},
};

And you’re done!

Step 05: Sharing the Environment

Next, let’s host the environment on Bit Cloud and start using it as a foundation for our components!

To do so, run the following commands:

bit tag && bit export

This should trigger a build in Bit’s CI — Ripple CI.

Ripple CI will build your component and any other dependants of it. It builds all components up the tree and ensures that all components using your base component work as expected!

For an in-depth guide on Ripple CI, check out this article:

If you visit your scope, you should see the dev environment component available:

Step 06: Consuming the environment

Next, let’s demo this environment by creating a component off of it. Let’s create a React component using our environment:

bit create react sample/button --env dummyorg.dev/envs/react

You should see the output:

As you can see, the env property uses the custom env we just created. This means our component can actually run on MUI.

Let’s implement this button using MUI Button. Open up your button.tsx and update it as follows:

import { Button as MUIButton, ButtonProps as MUIButtonProps } from '@mui/material';

export type ButtonProps = {
} & MUIButtonProps;

export function Button({ children, variant = 'contained', ...rest }: ButtonProps) {
return (
<MUIButton
variant={variant}
{...rest}
>
{children}
</MUIButton>
);
}

As you can see, we’ve incorporated MUI to our component without any errors! This is because the env we created offers MUI to this component!

Now, anyone that has used MUI knows that we need to hook up an MUI Theme Provider for the components to work off of MUI.

So, when we write a composition for our component, we don’t want to include the ThemeProvider every single time. That's tedious. Instead, open your env, and open the mounter.tsx file:

This file lets you handle what will happen when the component mounts on the Bit Preview pane. By default, it’ll look something like this:

Now, you can customize the implementation of MyReactProvider to use the MUI Theme Provider as follows:

import React from 'react';
import { createMounter } from '@teambit/react.mounter';
import { ThemeProvider, createTheme } from '@mui/material';

/**
* provide your component compositions (preview) with the context they need to run.
* for example, a router, a theme, a data provider, etc.
* components added here as providers, should be listed as host-dependencies in your host-dependencies.ts file.
* @see https://bit.dev/docs/react-env/component-previews#composition-providers
*/
export function MyReactProvider({ children }: { children: React.ReactNode }) {
return <ThemeProvider
theme={createTheme()}
>
{children}
</ThemeProvider>
}

As you can see, the Mounter now uses the default theme offered by MUI. Next, navigate back to your Bit server to see your new Button:

As you can see, the component now uses the MUI Default Theme behavior that we defined in our env earlier.

Now, let’s ship this button to the remote scope as well using the command:

bit tag && bit export

You can check out your Ripple CI and you’ll see the components now being built:

Your env is also building again because we updated the mounter. Since the button depends on the env, Ripple builds both of them!

And finally, you can check out your own dependency graph and see that your env is being used by the button:

Wrapping Up

And there we have it! You now have a reusable dev environment with custom Linter, Jest, TypeScript, Webpack configurations as well as individual library bundling.

Now, all that’s left is to use your environment in all components that you create!

Plus, you can create tons of other dev environments such as your very own Node.js, Angular, Vue.js, React Native (to say the least).

Try it out and let me know what you think! If you want to use my env, check out my Bit Scope.

Thank you for reading!

Learn More

--

--