Skip to content

feat(cli): add Astro template to FireCMS CLI#765

Open
marianmoldovan wants to merge 1 commit intomainfrom
docs/example-astro
Open

feat(cli): add Astro template to FireCMS CLI#765
marianmoldovan wants to merge 1 commit intomainfrom
docs/example-astro

Conversation

@marianmoldovan
Copy link
Collaborator

Add a new "astro" template option to the firecms init command, allowing users to scaffold a FireCMS project with Astro SSG/SSR and blog support.

  • Add template_astro to CLI templates with templatized Firebase config, cleaned monorepo aliases, and npm package dependencies
  • Update init.ts: add --astro flag, interactive prompt option, template folder mapping, post-creation instructions, and file replacement logic
  • Update CLI build script to clean template_astro node_modules
  • Add Astro example project with CMS dashboard, public blog pages, and FireCMS-branded dark theme styling

Add a new "astro" template option to the `firecms init` command,
allowing users to scaffold a FireCMS project with Astro SSG/SSR
and blog support.
- Add `template_astro` to CLI templates with templatized Firebase
  config, cleaned monorepo aliases, and npm package dependencies
- Update [init.ts](cci:7://file:///Users/marian/Code/firecms/firecms/packages/cli/src/commands/init.ts:0:0-0:0): add `--astro` flag, interactive prompt option,
  template folder mapping, post-creation instructions, and file
  replacement logic
- Update CLI build script to clean template_astro node_modules
- Add Astro example project with CMS dashboard, public blog pages,
  and FireCMS-branded dark theme styling
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new "astro" template to the FireCMS CLI, enabling users to scaffold FireCMS projects with Astro SSG/SSR support and a public blog feature. The implementation includes both a CLI template (for distribution to users) and an example project (for monorepo development/testing).

Changes:

  • Added --astro flag and template option to CLI init command with appropriate prompts and post-creation instructions
  • Created template_astro with Astro configuration, FireCMS dashboard setup, blog components, and Firebase integration
  • Added parallel example_astro in examples directory for monorepo development
  • Updated lerna.json to include the new example project in the monorepo workspace

Reviewed changes

Copilot reviewed 50 out of 52 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
packages/cli/src/commands/init.ts Added astro template support with flag, prompt, folder mapping, and file replacement logic
packages/cli/README.md Added documentation for the new --astro CLI flag
packages/cli/templates/template_astro/* New template directory with Astro app structure, FireCMS integration, and blog support
examples/example_astro/* Parallel example project for monorepo development with proper monorepo path mappings
lerna.json Added examples/example_astro to workspace packages

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +74 to +88
const handleSubmit = (email: string) => {
const url = "https://api.firecms.co/notifications/newsletter";
fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
email_address: email,
source: "demo"
})
}).then((res) => {
console.log("newsletter response", res);
});
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The newsletter submission lacks error handling. If the fetch fails or the response is not ok, the error is silently ignored. Add proper error handling with a catch block and check response.ok to handle failure cases appropriately.

Copilot uses AI. Check for mistakes.
Comment on lines 32 to 33
"examples/example_pro"
],
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trailing comma on line 32 after the last array element (followed by the closing bracket on line 33) is unnecessary and may cause issues with some JSON parsers that don't support trailing commas. While it's valid in JSON5 and modern JavaScript, standard JSON does not allow trailing commas.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +8
export const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "[REPLACE_WITH_PROJECT_ID].firebaseapp.com",
projectId: "[REPLACE_WITH_PROJECT_ID]",
storageBucket: "[REPLACE_WITH_PROJECT_ID].appspot.com",
messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
appId: "YOUR_APP_ID"
};
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The template's Firebase configuration contains placeholder values that need to be replaced by the CLI. However, the firebaseConfig should include a check in App.tsx (already present at line 47-49) to ensure users are warned if they forget to configure it. Consider also adding a more descriptive comment in this file explaining that these values will be automatically replaced during CLI initialization.

Copilot uses AI. Check for mistakes.
Comment on lines +49 to +63
<a
href="/cms"
class="glow-blue"
style="display:inline-flex;align-items:center;gap:0.5rem;padding:0.75rem 1.5rem;border-radius:0.5rem;background:#0070f4;color:#ffffff;font-weight:600;text-decoration:none;transition:all 0.2s;"
onmouseenter="this.style.transform='scale(1.05)'"
onmouseleave="this.style.transform='scale(1)'"
>
Open CMS →
</a>
<a
href="/blog"
style="display:inline-flex;align-items:center;gap:0.5rem;padding:0.75rem 1.5rem;border-radius:0.5rem;border:1px solid #454552;background:rgba(23, 23, 26, 0.5);color:#b7b7bf;font-weight:500;text-decoration:none;transition:all 0.2s;"
onmouseenter="this.style.borderColor='#0070f4';this.style.color='#0070f4'"
onmouseleave="this.style.borderColor='#454552';this.style.color='#b7b7bf'"
>
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inline event handlers use string-based style manipulation (e.g., onmouseenter="this.style.transform='scale(1.05)'"). This approach is less maintainable and harder to test than using CSS classes with hover states. Consider using Tailwind's hover utilities or CSS classes instead of inline JavaScript for hover effects.

Copilot uses AI. Check for mistakes.
Comment on lines +10 to +11
@source "../../packages/**/src/**/*.{js,ts,jsx,tsx}";
@source "../../node_modules/@firecms/**/src/**/*.{js,ts,jsx,tsx}";
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The @source directives reference monorepo-specific paths (lines 10-11) that won't exist in user projects. Lines 10-11 should be removed: "../../packages//src//.{js,ts,jsx,tsx}" and "../../node_modules/@firecms//src//.{js,ts,jsx,tsx}". Only keep the local source references (lines 8-9).

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +5
import "@fontsource/poppins";
import "@fontsource/playfair-display";
import "@fontsource/jetbrains-mono";
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These font imports (Poppins, Playfair Display) are not used in the CMS pages. The design system primarily uses Rubik (as seen in index.astro and blog pages). These unused imports should be removed to improve bundle size and reduce unnecessary network requests.

Copilot uses AI. Check for mistakes.
Comment on lines +58 to +79
function renderMarkdown(md: string): string {
let html = md
.replace(/```([\s\S]*?)```/g, '<pre style="background:rgb(23,23,26);border-radius:0.75rem;padding:1rem;margin:1rem 0;overflow-x:auto;font-size:0.875rem;font-family:monospace;color:#b7b7bf"><code>$1</code></pre>')
.replace(/`([^`]+)`/g, '<code style="background:rgb(23,23,26);padding:0.125rem 0.375rem;border-radius:0.25rem;color:#0070f4;font-size:0.875rem">$1</code>')
.replace(/^### (.+)$/gm, '<h3 style="font-size:1.25rem;font-weight:600;color:#ffffff;margin:2rem 0 0.75rem">$1</h3>')
.replace(/^## (.+)$/gm, '<h2 style="font-size:1.5rem;font-weight:700;color:#ffffff;margin:2.5rem 0 1rem">$1</h2>')
.replace(/^# (.+)$/gm, '<h1 style="font-size:2rem;font-weight:700;color:#ffffff;margin:2.5rem 0 1rem">$1</h1>')
.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1" style="border-radius:0.75rem;margin:1.5rem 0;max-width:100%" loading="lazy" />')
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" style="color:#0070f4" target="_blank" rel="noopener noreferrer">$1</a>')
.replace(/\*\*(.+?)\*\*/g, '<strong style="color:#ffffff;font-weight:600">$1</strong>')
.replace(/\*(.+?)\*/g, '<em>$1</em>')
.replace(/^[-*] (.+)$/gm, '<li style="margin-left:1rem;color:#b7b7bf;margin-bottom:0.25rem">$1</li>')
.replace(/^(?!<[hlupai]|<code|<pre|<li|<img)(.+)$/gm, '<p style="color:#b7b7bf;line-height:1.75;margin-bottom:1rem">$1</p>');

html = html.replace(/((?:<li[^>]*>.*<\/li>\s*)+)/g, '<ul style="list-style:disc;margin:1rem 0 1rem 1rem">$1</ul>');
return html;
}

function ContentRenderer({ block }: { block: ResolvedContentBlock }) {
switch (block.type) {
case "text":
return <div dangerouslySetInnerHTML={{ __html: renderMarkdown(block.value || "") }} />;
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The renderMarkdown function uses dangerouslySetInnerHTML without proper sanitization of user-provided markdown content. While basic markdown is parsed, there's no protection against XSS attacks if malicious HTML is embedded in the markdown. Consider using a proper markdown library with built-in XSS protection (like marked with DOMPurify) or at least sanitize the HTML output before rendering.

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +43
"@firecms/core": [
"../../packages/firecms_core/src"
],
"@firecms/firebase": [
"../../packages/firebase_firecms/src"
],
"@firecms/ui": [
"../../packages/ui/src"
],
"@firecms/editor": [
"../../packages/editor/src"
],
"@firecms/data_enhancement": [
"../../packages/data_enhancement/src"
],
"@firecms/collection_editor": [
"../../packages/collection_editor/src"
],
"@firecms/collection_editor_firebase": [
"../../packages/collection_editor_firebase/src"
],
"@firecms/data_import": [
"../../packages/data_import/src"
],
"@firecms/data_export": [
"../../packages/data_export/src"
],
"@firecms/user_management": [
"../../packages/user_management/src"
],
"@firecms/schema_inference": [
"../../packages/schema_inference/src"
]
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tsconfig.json contains monorepo-specific path mappings (lines 11-43) that should be removed from the template. These paths point to the monorepo's packages directory structure (e.g., "../../packages/firecms_core/src") which won't exist when users create a new project. The template should only use npm package imports like "@firecms/core" without custom path mappings, as these packages will be installed in node_modules.

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +64
First, install dependencies from the monorepo root:

```bash
npm install
```

Then, run the development server:

```bash
cd examples/example_astro
npm run dev
```

Open [http://localhost:4321/cms](http://localhost:4321/cms) with your browser to access the FireCMS dashboard.

## Project Structure

```
src/
├── cms/ # FireCMS React components
│ ├── App.tsx # Main FireCMS app component
│ ├── CMSRoute.tsx # Client-side routing wrapper
│ ├── collections/ # Firestore collection definitions
│ │ ├── products.tsx
│ │ ├── blog.tsx
│ │ ├── users_collection.tsx
│ │ └── locales.tsx
│ ├── components/
│ │ └── CustomLoginView.tsx
│ └── views/
│ ├── ExampleCMSView.tsx
│ └── TestEditorView.tsx
├── common/ # Shared config and types
│ ├── firebase_config.ts
│ └── types.ts
├── pages/ # Astro pages (file-based routing)
│ ├── index.astro # Redirects to /cms
│ └── cms/
│ └── [...path].astro # Catch-all route for FireCMS
└── styles/
└── index.css # Tailwind CSS + FireCMS styles
```

## How It Works

Astro renders pages statically by default, but FireCMS is a fully interactive React application that requires client-side rendering. This example uses Astro's `client:only="react"` directive to render the CMS entirely on the client side, avoiding SSR for components that depend on browser APIs like `window` and `BrowserRouter`.

The catch-all route `[...path].astro` ensures all CMS sub-routes (`/cms/products`, `/cms/blog`, etc.) are handled by the React Router inside FireCMS.

## Learn More

- [FireCMS Documentation](https://firecms.co/docs)
- [Astro Documentation](https://docs.astro.build)
- [Astro React Integration](https://docs.astro.build/en/guides/integrations-guide/react/)

## Deploy

You can deploy this Astro app to any static hosting provider or use SSR adapters for platforms like Netlify, Vercel, or Cloudflare.
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README references a monorepo structure that doesn't apply to projects created from the template. Lines 43-44 state "Redirects to /cms" and "Catch-all route for FireCMS", but the index.astro page actually provides a welcome page with navigation, not a redirect. Additionally, the installation and running instructions (lines 7-18) assume the user is in a monorepo context ("install dependencies from the monorepo root", "cd examples/example_astro"), which won't be true for projects created via the CLI. These instructions should be updated for standalone project usage.

Copilot uses AI. Check for mistakes.
Comment on lines +4 to +6
import "@fontsource/poppins";
import "@fontsource/playfair-display";
import "@fontsource/jetbrains-mono";
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These font imports (Poppins, Playfair Display, JetBrains Mono) are not used in this blog post view. The page uses inline styles that default to system fonts. Only the Rubik font family is referenced in the main layout. These unused imports should be removed to improve bundle size.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments