Easily integrate multiple JavaScript frameworks into one web page
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.
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.
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.