Share React Components Across Projects with Git Submodules

[object Object]
Sara MitevskaMay 17th, 2023
May 17th, 2023 7 minutes read
https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjApzvkK_mYuZosH01PTKLSHNciB3mQnZAE9JBjHwKQTbDldPlQqWkZQZHCMVZGFkJWUBDjAEbL9u-CNAO8AUzhLJ6OptRxprzgfbbA5rJWlyMuUrxm0GPJhuqCcl7bceHD9BAIIxfFSJ2-hDK0ChzOJzHpFlp3-VTABfKUCJ6vfJ2x8zhqQq1CSFO1hX6B/w640-h570/c0a4fdfe-fa8c-42fe-975e-a5c5c7b51cc1.webp
git submodules

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 two projects. First, we need to create the apps. For this simple idea, we'll demonstrate how to set up projects using different tools: Create React App, Vite, and Next.js.

To create the first project, clone the first-app repository locally and navigate to its root directory.

  1. Using Create React App:

    To create the first project using Create React App, in the project directory run:

    	npx create-react-app .
  2. Using Vite:

    If you prefer to use Vite, in the project directory run the following command:

    	npm create vite@latest . --template react
  3. Using Next.js:

    For a Next.js app, in the project directory run the following command:

    	npx create-next-app .

If you wish to use a different tool to build the app, please refer to their official documentation to get specific instructions on setting up your project.

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

  cd src/components
  git pull

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.deva 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.

Remember, choosing the right approach is essential for long-term productivity and success.

Github examples: