#Shared components for multiple Astro websites in monorepo setup

1 messages · Page 1 of 1 (latest)

ionic sedge
#

How do can I setup a monorepo for multiple Astro websites that share "$lib/components/*"?

round nightBOT
#

Hi @ionic sedge. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

To set up a monorepo for multiple Astro websites that share components, you can use workspaces and import aliases. Here's how you can approach this:

Setting up a monorepo with shared components

Astro supports workspaces within your project, which allows you to develop components alongside multiple Astro sites.

1. Structure your monorepo

Create a directory structure like this:

my-monorepo/
├── package.json
├── packages/
│   └── shared-components/
│       ├── index.js
│       ├── package.json
│       └── components/
│           └── ... your shared components
├── site-one/
│   └── ... Astro project files
└── site-two/
    └── ... Astro project files

2. Configure workspaces

In your root package.json, define your workspaces:

{
  "name": "my-monorepo",
  "workspaces": ["site-*", "packages/*"]
}

3. Set up the shared components package

In your packages/shared-components/package.json:

{
  "name": "@myorg/shared-components",
  "version": "1.0.0",
  "main": "index.js"
}

4. Configure import aliases in each Astro site

For each Astro site, set up import aliases in the tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "$lib/components/*": ["../packages/shared-components/components/*"]
    }
  }
}

This allows you to import shared components using the $lib/components/* path as requested Import aliases.

5. Add dependencies to each Astro site

In each Astro site's package.json, add the shared components as a dependency:

{
  "dependencies": {
    "@myorg/shared-components": "workspace:*"
  }
}

6. Configure Vite in Astro

#

When working with Astro in a monorepo, you might need to add the shared dependencies to the vite.ssr.noExternal configuration to ensure they're properly bundled:

// astro.config.mjs
import { defineConfig } from 'astro/config';

export default defineConfig({
  vite: {
    ssr: {
      noExternal: ['@myorg/shared-components']
    }
  }
});

This helps avoid issues with dependencies in a monorepo setup as mentioned in the troubleshooting guide.

7. Using shared components

Now you can import and use your shared components in any Astro site:

---
import SharedComponent from '$lib/components/SharedComponent.astro';
---

<SharedComponent />

This approach allows you to maintain a single source of truth for your components while using them across multiple Astro websites in your monorepo.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@ionic sedge Kapa.ai is still learning and improving, please let me know how I did by reacting below.

ionic sedge
#

@round night In shared components I want to import src/data/consts.ts that is unique for each site (i.e. my-sites/site-a/src/data/consts.ts). How to do that?

round nightBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

I understand you want to import site-specific constants from each site into your shared components. This is a common need in monorepo setups with Astro. Here's how you can achieve this:

Importing site-specific constants in shared components

You can use import aliases and a pattern that allows your shared components to access site-specific data. Here are a few approaches:

1. Using import aliases with a consistent path

In each site's tsconfig.json, set up an alias that points to its own data directory:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "$lib/components/*": ["../packages/shared-components/components/*"],
      "@site-data/*": ["./src/data/*"]
    }
  }
}

Now in your shared components, you can import using this alias:

---
import { someConstant } from '@site-data/consts';
---

This works because each site has its own alias configuration pointing to its own data directory Import aliases.

2. Using environment variables

Another approach is to use environment variables to determine which site's constants to load:

In your shared component:

---
// This dynamically imports the correct constants based on the site
const { default: siteConstants } = await import(`../../${import.meta.env.SITE_ID}/src/data/consts.ts`);
---

Then in each site's .env file:

SITE_ID=site-a

3. Using middleware for site-specific context

You can also use Astro's middleware to inject site-specific data into Astro.locals:

#
// In each site's src/middleware.ts
export function onRequest(context, next) {
  // Import site-specific constants
  import('./data/consts.js').then(module => {
    // Add to locals so components can access it
    context.locals.siteConstants = module.default;
  });
  
  return next();
}

Then in your shared components:

---
const { siteConstants } = Astro.locals;
---

This leverages Astro's middleware capabilities to make site-specific data available to all components Basic Usage.

Choose the approach that best fits your project structure and requirements. The import alias method is generally the cleanest and most maintainable for most projects.

Would you like me to elaborate on any of these approaches?

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: