Sharing React Components Across Projects using Git Submodules
Tags: webdev, javascript, programming, tutorial
Published: 2024-02-26 10:03:49

Reusing components and code is a fundamental aspect of React projects, offering developers the ability to write code once and leverage it across different parts of an application. But as projects evolve and grow, the need of reusing components and functionality across various React projects becomes increasingly apparent.

There are a few ways and platforms that offer code sharing across projects (which I will mention later), however, in this post, we explore a simple concept of code-sharing between different React projects in a more private way by using Git submodules without relying on third-party platforms or tools.

Git submodules are a feature in Git that allows you to integrate external repositories as dependencies within your project, maintaining their independence and version control.

## Section 1: Setting up Git Submodules for Component Sharing

First, we'll need three different remote Git repositories. One will contain the code that we need to reuse - in this case a simple Button component, and the other two projects will be simple React apps with the Button from the shared repository.

Create three empty remote repositories using the version control tool of your choice (for example Github) named: first-app, second-app and component-library.

Then, clone the first-app and second-app locally and in each of its root directory run:

```
git submodule add <repository_url> <submodule_path>
```

where repository_url is the url of the repository you created that will contain the shared Button component, in this case component-library and submodule_path is the name of the directory that will contain the component-library repository, for this example, let's name it components.

## Section 2: Creating the shared component

Next clone the component-library repository and in the root directory of the component library add a new folder button with index.js file for the component code and button.css for the styling:

```
// index.js

import './button.css';

function Button() {
  return (
    <button className="button">
      This is a Button component from my
      Component library
    </button>
  );
}

export default Button;
```

```
// button.css

.button {
  background-color: #E8AA42;
  padding: 10px;
  border: 0;
  border-radius: 5px;
  box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
```

Then, commit and push the changes to the remote:

```
git add .
git commit -m "create button component"
git push
```

## Section 3: Using the Shared Components in the other React Project

Now that we built the shared component, let's use it in the two projects. 

First we need to create the apps. Since it is a simple idea, we'll be using create-react-app to create two of the different projects that will share code.

Clone the first-app locally and in its root directory run:

```
npx create-react-app .
```

Since we already setup the submodule, we need to update it to get the latest changes we did. 

```
git submodule update
```

To use the shared component, open the App.js file and import the Button component from the src/components/button folder. 

Start the application with npm run start and test the changes! You should be able to see the button component.

Repeat the same process with the second-app repository.

## Section 4: Managing Changes and Updates

Changes and updates can be done from any repository that uses the submodule or the submodule itself. But note that after some changes are made, you'll need to pull the changes in the repository where you'll need them before making other changes.

This is maybe one of the biggest disadvantages of using git submodules instead of code-sharing platforms, however the purpose of this post is to explain how to share code with minimum configuration while keeping your code in your private repositories without using third-party platforms. If this doesn't fit your situation you can use other tools and platforms such as Bit.de, Storybook alongside Chromatic, Styleguidist and others.

## Section 5: Testing shared components in isolation (Optional) 

If you also want to view and test the shared components in isolation, then you can do that by adding a little more configuration.

For this, we'll need to use a build tool that will create the environment where we'll test the shared components. There are a few options here, but this example will use Parcel as it's light and quick and easy to setup. You can also use any other build tool of your choice, whichever best fits your scenario.

First, open the component-library project and in the root directory, create the following package.json file:

```
{
  "name": "component-library",
  "source": "index.html",
  "scripts": {
    "start": "parcel",
    "build": "parcel build"
  },
  "devDependencies": {
    "parcel": "latest"
  }
}
```
󠄻󠄩󠄿
Then run the following to install parcel:

```
npm install --save-dev parcel
```

Next, since we're working with React projects we need to install react and react-dom:

```
npm install react react-dom
```

Create the entry index.html file and paste the following code:

```
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>My Component Library</title>
</head>
<body>
  <div id="app"></div>
  <script type="module" src="index.js"></script>
</body>
</html>
```

Create an index.js file and paste the following code:

```
import { createRoot } from "react-dom/client";
import { App } from "./App";

const container = document.getElementById("app");
const root = createRoot(container)
root.render(<App />);
```

And finally create the App.js file with the Button component that we want to test:

```
import Button from './button';

export function App() {
  return <Button />;
}

```

To run the application run: 

```
npm run start
```

and to build run:

```
npm run build
```

These commands will build the application and write the output in dist directory.

You can then open the local server on http://localhost:1234 and you should see the Button component.

While this post does not cover the details of deploying projects, once you have successfully set up the code-sharing mechanism, you can proceed with deploying and publishing the component library on your preferred server. By doing so, you gain the ability to preview and test the shared components at any time.

## Section 6: Alternatives

Some other alternatives that provide similars value are:

Bit.dev - a platform that facilitates component-driven development and component sharing across projects. It provides a centralized hub for developers to discover, share, and collaborate on reusable components. With Bit.dev, you can publish and version components, manage their dependencies, and integrate them into different projects, regardless of the framework or tooling being used. It offers features like component documentation, testing, and a package manager-like experience for sharing and consuming components.

Storybook - a popular open-source tool for developing UI components in isolation. It allows you to build and organize a library of components, view them in different states, and document their usage. Storybook supports various frameworks like React, Vue, Angular, and more.

Styleguidist - a documentation tool specifically designed for React component libraries. It helps you create living style guides and documentation by providing an interactive environment where you can showcase and test your components.

Chromatic - a tool that focuses on visual testing and UI review for component-driven development. It integrates with popular component frameworks like React, Angular, and Vue, and helps you catch UI bugs, perform visual regression testing, and collaborate with team members on component changes.

## Conclusion:

While Git submodules offer a straightforward approach to code sharing, it's important to note that this approach may not be suitable for every scenario. Like any other tools and platforms, it has its own set of advantages and disadvantages. Therefore, it is crucial to thoroughly research and evaluate your specific needs before deciding on the best option for your project.

Consider factors such as the complexity of your codebase, the scale of your projects, the level of collaboration required, and the desired level of control over dependencies. Additionally, take into account the learning curve, maintenance overhead, and compatibility with your existing development workflow.


You can find the examples of this tutorial here:
{% embed https://github.com/mitevskasara/library %}
{% embed https://github.com/mitevskasara/first-app %}
{% embed https://github.com/mitevskasara/second-app %}