 
 Mitosis - Using Astro.js as the dev server to preview the component with hot-reload
  Patrick Chiu • 2023/08/31
 Patrick Chiu • 2023/08/31 
 
- Set up Mitosis
- Set up Astro.js in /test-app
- Update the build script
- (Bonus) .gitignore
- (Bonus) Settings of Publishing to NPM

TL;DR Here’s the Mitosis Astro.js Starter repo to jump start the development. I built a GitHub Activity Widget component with a similar setup, which compiles to native React, Svelte, Vue, SolidJS and Qwik components.
What is Mitosis
In case you are new to Mitosis, Mitosis enables you to develop a consistent design system across multiple frameworks e.g. React, Svelte and Vue.
Its syntax is pretty similar to React. It allows you to write your component in JSX and transforms into native components of the various frameworks.
Astro.js as the dev server
While Mitosis is great at generating framework-native components, it doesn’t come with a dev server to let you preview the component. You may ask, why do we want to preview the component in various frameworks, instead of only previewing it in one of them e.g. svelte?
Turns out there are quite a few of gotchas and open issues in using Mitosis (when this tutorial is written). Sometimes the generated code works perfectly in React and Vue but not Svelte. Sometimes the others. It would be great if
- We could preview most (if not all) generated components in a single page
- Even better, have hot-reload enabled
In this tutorial, we will walk through the steps to set up a hot-reload dev server with Astro.js.
Note: Astro supports a variety of popular frameworks including React, Preact, Svelte, Vue, SolidJS, AlpineJS and Lit with official integrations. While for other frameworks e.g. Angular and Qwik, you may still benefit from this tutorial and you would need to further set up the community maintained framework integrations.

Steps
1. Set up Mitosis
This step references the official Create a new project cli guide with the following modifications.
- We aren’t initializing test-appsfor each framework. Instead, we would run onetest-appwith Astro.js for all frameworks.
- In terms of NPM package, we aren’t scoping the component under a namespace and output various packages like @my-awesome-component/library-reactand@my-awesome-component/library-svelteetc. Instead, we publish all components in one package onlymy-awesome-component. The output components can then be imported likemy-awesome-component/reactandmy-awesome-component/svelteetc
The folder structure should look like this by the end of this step.
.
├── src/
│   └── MyAwesomeComponent.lite.tsx
├── mitosis.config.cjs
├── package.json
└── tsconfig.jsonWithout further ado, let’s initiate an empty project.
mkdir my-awesome-component
cd ./my-awesome-component
npm init -yInstall the relevant packages
npm i @builder.io/eslint-plugin-mitosis @builder.io/mitosis @builder.io/mitosis-cli
npm i watch --save-devSetup mitosis.config.cjs. In the targets field, place all downstream frameworks to compile.
/**
 * @type {import('@builder.io/mitosis').MitosisConfig}
 */
module.exports = {
  files: 'src/**',
  targets: ['react', 'svelte', 'solid', 'vue'],
  dest: 'output',
  commonOptions: { typescript: true },
  options: { react: { stylesType: 'style-tag' }, svelte: {}, qwik: {} },
};Setup tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "strict": true,
    "jsx": "preserve",
    "noImplicitAny": false,
    "moduleResolution": "node",
    "jsxImportSource": "@builder.io/mitosis"
  },
  "include": ["src"]
}Initialize src/MyAwesomeComponent.lite.tsx
import { useState } from '@builder.io/mitosis';
export default function MyComponent(props) {
  const [name, setName] = useState('Steve');
  return (
    <div>
      <input
        css={{ color: 'red' }}
        value={name}
        onChange={(event) => setName(event.target.value)}
      />
      Hello! I can run natively in React, Vue, Svelte, Qwik, and many more
      frameworks!
    </div>
  );
}2. Set up Astro.js in /test-app
The folder structure should look like this by the end of this step. We will focus on test-app
.
├── src/
│   └── MyAwesomeComponent.lite.tsx
├── test-app/
│   └── astro.config.mjs
├── mitosis.config.js
├── package.json
└── tsconfig.jsonCreate astro project with the following config
npm create astro@latest# Where should we create your new project?
./test-app
# How would you like to start your new project?
Empty
# Do you plan to write TypeScript?
Yes
# How strict should TypeScript be?
Strict
# Install dependencies?
Yes
# Initialize a new git repository?
NoCd into the directory
cd test-app2.1. Framework integrations
Follow the official integration guide to add React.js, Vue, Svelte and Solid.js. (You can add more if you need)
npx astro add react
npx astro add vue
npx astro add svelte
npx astro add solidSince both React.js and Solid.s uses JSX, we need to let Astro.js where to find both correspondingly. Update astro.config.mjs with the following settings.
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
import solid from '@astrojs/solid-js';
import svelte from '@astrojs/svelte';
import vue from '@astrojs/vue';
export default defineConfig({
  integrations: [
    react({ include: ['**/react/**'] }),
    solid({ include: ['**/solid/**'] }),
    svelte(),
    vue(),
  ],
});2.2. Astro.js folder structure
Let’s structure our Astro.js test-app like the following and import all components to index.astro.
.
├── test-app/
│   ├── src/
│   │   ├── components/
│   │   │   ├── react/
│   │   │   │   └── ReactApp.tsx
│   │   │   ├── solid/
│   │   │   │   └── SolidApp.tsx
│   │   │   ├── SvelteApp.svelte
│   │   │   └── VueApp.vue
│   │   └── pages/
│   │       └── index.astro
│   └── astro.config.mjsSee the GitHub repo for content in ReactApp.tsx, SvelteApp.svelte, VueApp.vue and SolidApp.tsx.
For index.astro, replace with the following. This wires up various framework components into a single Astro.js page.
---
import ReactApp from '../components/react/ReactApp.jsx'
import SvelteApp from '../components/SvelteApp.svelte'
import VueApp from '../components/VueApp.vue'
import SolidApp from '../components/solid/SolidApp.jsx'
---
<html lang="en">
  <head>
    <meta charset="utf8" />
    <title>Test App</title>
  </head>
  <body>
    <div class="w-50">
      <div class="title">
        <span>React</span>
      </div>
      <ReactApp client:only="react" />
    </div>
    <div class="w-50">
      <div class="title">
        <span>Svelte</span>
      </div>
      <SvelteApp client:load />
    </div>
    <div class="w-50">
      <div class="title">
        <span>Vue</span>
      </div>
      <VueApp client:only="vue" />
    </div>
    <div class="w-50">
      <div class="title">
        <span>Solid</span>
      </div>
      <SolidApp client:only="solid-js" />
    </div>
  </body>
</html>
<style>
  body {
    background-color: aliceblue;
  }
  .w-50 {
    display: inline-block;
    width: calc(48% - 12px * 2 - 8px * 2);
    margin: 8px;
    padding: 12px;
    border-radius: 8px;
    box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.1);
    background-color: white;
  }
  .title {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 8px;
  }
</style>3. Update the build script
Now let’s wire up Mitosis and Astro.js! Update the root package.json with the following.
- npm run build: Mitosis generates downstream components to- ./outputand we copy it to- ./test-app/src
- npm run start: we- watchchanges in- ./srcand- npm run buildwhen there are changes
{
  // ...
  "scripts": {
    "start": "watch \"npm run build\" ./src",
    "build": "mitosis build --c mitosis.config.cjs && cp -R ./output ./test-app/src",
    "lint": "eslint"
  }
  // ...
}4. (Bonus) .gitignore
Mitosis build script would compile the downstream component to ./output. Let’s ignore it together with ./node_modules and Astro.js’ generated types
# dependencies
node_modules/
# Mitosis
output/
# Astro.js
.astro/5. (Bonus) Settings of Publishing to NPM
Now you have built an awesome Mitosis component. Let’s update package.json so that developers of various frameworks can use your component!
(Don’t forget to change the actual package name from my-awesome-component to something else!)
{
  "name": "my-awesome-component",
  // ...
  "main": "./output/react/src/MyAwesomeComponent.tsx",
  "exports": {
    "./react": "./output/react/src/MyAwesomeComponent.tsx",
    "./svelte": "./output/svelte/src/MyAwesomeComponent.svelte",
    "./vue": "./output/vue/src/MyAwesomeComponent.vue",
    "./solid": "./output/solid/src/MyAwesomeComponent.tsx"
  },
  "files": ["output/**/*"]
}The above settings do 2 things
- You only publish the generated downstream components in the ./outputdirectory to NPM
- Your component can be imported with…
// React
import MyAwesomeComponent from 'my-awesome-component/react';
// Vue
import MyAwesomeComponent from 'my-awesome-component/vue';
// Svelte
import MyAwesomeComponent from 'my-awesome-component/svelte';
// Solid
import MyAwesomeComponent from 'my-awesome-component/solid';Hope you enjoy the journey of setting up Mitosis with Astro.js which enables you to preview all the generated components at a glance! Lastly, do you need a quick walkthrough on creating a Mitosis component? Here’s how to develop the Github Activity Calendar with Mitosis 😉
 
 