Easily integrate multiple JavaScript frameworks into one web page

Amin Partovi
Geek Culture
Published in
3 min readFeb 12, 2023

Who will win the battle? React, Vue, Angular, or …

It can be a starting point for building UI-tech-agnostic projects in the future and using different frameworks on a single project without war and bloodshed.

It is still not recommended to build a front-end project with different frameworks, but here we discuss how Astro makes this possible.

integration

INTRODUCTION

The Astro framework is a super-fast JS framework based on islands architecture and is perfect for content-focused websites.

In an Astro project, no JavaScript is shipped to the client by default, and the developer can decide which component loads JavaScript independently; This pattern calls islands architecture, i.e. the static HTML content is the sea and the components are isolated islands in the sea.

An interesting feature of Astro is that we can use any UI framework to build these islands. You can find the list of these frameworks here. This article will demonstrate how to integrate React and Vue, two popular JavaScript frameworks, into a single web page, as well as how to share states between their components (islands).

LET’S START

Build your Astro project through the following command line:

npm create astro@latest

after setting different configs you are able to add your favorite frameworks. Here we added React and Vue with these command lines:

npx astro add react
npx astro add vue

Astro automatically adds integration config for you in the Astro.config.mjs file. Here you can find the current project’s GitHub repository.

Components that composed the example project

In the index.astro file you can find the following code. In this file, you find a <Layout> component which is an Astro file, <component> which is a React file with .tsx extension, and <PhotoList> component which is a Vue component with .vue extension. Here we integrated these three types of a component into a single web page.

---
import Container from '../components/container/Container';
import PhotoList from '../components/photoList/PhotoList.vue';
import Layout from '../layouts/Layout.astro';
import texts from '../texts/texts';
---


<Layout title={texts.TITLE}>
<Container >
<PhotoList client:load/>
</Container>
</Layout>

Client:load in the <PhotoList client:load/> tag shows that it is an interactive component and we want to hydrate this island with JavaScript.

SHARING STATE

In the <PhotoList> we are going to fetch a list of photos from the JsonPlaceHolder fake rest API. Astro recommended Nano Stores as a fast, UI-agnostic state manager to share data across all the components.

The Nano Stores library supports a variety of JavaScript libraries and frameworks. While Nano Stores documentation is not robust, its initialization is straightforward and concise. Just one line of code is needed to create and initialize your store (atom).

In the store/photos.ts we fetch data from the JasonPlaceHolder on the mounting of the component.

import { atom, onMount, task } from "nanostores";

interface Photo {
albumId: number;
id: number;
title: string;
url: string;
thumbnailUrl: string;
}
interface FetchPhotos {
isLoading: boolean;
data: Photo[];
}

export const photos = atom<FetchPhotos>({ isLoading: false, data: [] });

onMount(photos, () => {
photos.set({ isLoading: true, data: [] });

task(async () => {
try {
const response = await fetch(
"https://jsonplaceholder.typicode.com/photos?albumId=5&_start=0&_limit=20"
);

photos.set({ isLoading: false, data: await response.json() });
} catch (e) {
console.log(e);
}
});
});

Then in the <PhotoList> component (Vue component), we access the fetched data through the useStore hook. When any changes are made to the photos’ object, this hook hydrates and rerender the islands. It is important to import the hook from the right module.

<script setup>
import { useStore } from '@nanostores/vue'
import { photos } from "../../store/photos";
import PhotoCard from "../photoCard/PhotoCard.vue"
const $fetchedPhotos = useStore(photos)
</script>

<template>
<h1 v-if="fetchedPhotos?.isLoading">loading ...</h1>
<PhotoCard v-else v-for="photo in $fetchedPhotos.data" :photo="photo" />
</template>

Now the fetched data is available in our Vue component.

CONCLUSION

  • The Astro framework simplifies the integration of multiple frameworks on a single web page
  • You can create interactive components (islands) with Vanilla JavaScript or any JavaScript framework.
  • Nano Stores library is recommended by the Astro team for sharing states between interactive islands.
  • The initialization of Nano Stores is simple and concise, but the documentation is not as good as we would expect.

--

--

Amin Partovi
Geek Culture

A passionate developer exploring various technologies. Let's connect to geek out together! Keep coding and stay curious! https://github.com/Amin-Partovi