# Adopting Monorepo With Micro Experiences

Source: https://dev.arcxp.com/micro-experiences/adopting-monorepo-with-micro-experiences/

Adopting monorepo with Micro Experiences

With the new capabilities of Micro Experience (MX) in Arc XP come new challenges. One of them is how to manage and maintain multiple bundles and share Components to minimize duplicate code and keep complexity low. 

## Mono Repo

While the idea with Micro Experiences is, that you can split your code by experiences, the reality is that there are still some components that are needed on all Micro Experiences, and thus have to be included in each bundle. 

While you can keep the code for all your Micro Experiences in one Repo and write custom `fusion zip` commands to build your individual Bundles, we would instead recommend a new Mono Repo structure instead. Clearly splitting the individual Micro Experiences and Shared Components. 

An Example structure could be: 

- DirectoryYour-Mono-Repo  
  - Directory**Shared-Components/**
    - Directorymy\_footer/
      - …
    - Directorypromo-carousel/
      - …
  - Directory**MX-A**
    - Directorycomponents  
      - Directorychains/
        - …
      - Directoryfeatures/
        - …
      - Directorylayouts/
        - …
      - Directoryoutput-types/
        - …
    - Directorycontent  
      - Directorysources/
        - …
    - environment
    - package.json
    - properties
    - Directoryresources/
      - …
  - Directory**MX-B**
    - Directorycomponents  
      - Directorychains/
        - …
      - Directoryfeatures/
        - …
      - Directorylayouts/
        - …
      - Directoryoutput-types/
        - …
    - Directorycontent  
      - Directorysources/
        - …
    - environment
    - package.json
    - properties
    - Directoryresources/
      - …
  - package.json

Where all Components that are shared, are in “Shared Components” and are imported by MX-A and MX-B individually. This keeps the individual Micro Experiences separated, while it minimizes complexity and improves code quality.

## Utilizing private Packages

Once you have set up your Repo to split shared Components from the MX-specific Components, the next step is to decouple your Shared Components completely by making them into private packages.

- DirectoryYour-Mono-Repo/  
  - DirectoryShared-Components  
    - Directory**my\_footer**
      - package.json
      - Directorysrc  
        - index.jsx
  - DirectoryMX-A  
    - package.json
    - …
  - DirectoryMX-B  
    - package.json
    - …
  - package.json

For that, each Component should turn into it’s own package with versioning, which will be imported through the `package.json` in the individual Micro Experiences. 

Even though the packages are within the same Mono Repo, they need to be imported the same way other private packages are imported. [Using Private NPM Repository in your bundle](https://dev.arcxp.com/pagebuilder-engine/developer-docs/using-private-npm-repository-in-your-bundle/) provides guidance on the necessary steps.

### Component Shell

Shared Components should be included following the [Feature API Implementation](https://dev.arcxp.com/pagebuilder-engine/developer-docs/feature-api/) and [Chain API Implementation](https://dev.arcxp.com/pagebuilder-engine/developer-docs/chain-api/) rules. Shared Components are imported as regular packages and installed in `/node_modules` , so they still need to have their Shell of Feature or Chain Components. 

Shell feature, chain, layout, content source can be as simple as

```js
export * from from 'your-private-shared-component-footer'
```

if you don’t have any customizations per specific experience.

Or you can extend your shared component with any difference in implementation between Micro Experiences, for example: alternative labels or props.

An example shell could be:

Your-Mono-Repo/MX-A/components/features/global/footer/default.jsx

```jsx
import React from 'react'
import { useFusionContext } from "fusion:context"
import { useContent } from "fusion:content"
import SharedFooter from 'your-private-shared-component-footer'

const Footer = () => {
  const { arcSite } = useFusionContext()
  const footerContent = useContent({
    source: 'site-service',
    query: { hierarchy: 'footer' }
  })

  return <SharedFooter site={arcSite} content={footerContent}/>
}

export default Footer

Footer.label = 'Footer - MX A'
```

Best way to ensure a seamless development with Shared Components is to use [NPM linking](https://docs.npmjs.com/cli/v9/commands/npm-link) (or whichever tool you use), which allows you to directly link the local code as the imported packages. Most monorepo tools automate this step when running a specific project’s `run` command.

> **Note:**
> 
> Your shared components needs to not import and depend on PageBuilder Engine exported methods like `fusion:content`, `fusion:context`, `fusion:environment`, `fusion:properties`. Importing them may cause circular dependency issues in the build process. The right way to do this is to design your shared components that received these methods as props. And in your shell component, you can import and use these props to pass them to your shared component package safely.

### Local Development

When working with multiple bundles, you need to run each bundle one at a time. You can not run multiple bundles at the same time. Most of the monorepo tools have a way to define `run` commands that automatically runs the npm commands inside that specific project’s package folder. But essentially what they do is `cd MX-A && npx fusion start` command.

## Release Strategy

Use Mono Repo Build Tools, such as [moonrepo](https://moonrepo.dev/) or [Nx](https://nx.dev/), to handle the packaging of Shared Components and their releases.

Versioning is an important factor for these packages and how they are included in the Micro Experiences. Should each bundle automatically receive minor updates or should they be frozen on an older version until it has been reviewed and tested by Micro Experience team?

> **Caution:**
> 
> Be aware that releases on individual Micro Experiences are deployed independently from each other and are static post deployment. That means, that even though bundles import the same packages, depending when they were deployed, they might have different versions installed. 
> 
> Therefore, on changes on Shared Components be aware that multiple versions could be live at the same time and they need to be compatible.
