Illustration de Adding Vue to Astro: how to use Component Islands

Adding Vue to Astro: how to use Component Islands

Par Théotime, Front-End Developer

Publié le

Astro integrates the concept of Component Islands which offers a neat way of integrating Vue components in an otherwise static website.

#frontend#featured#vue#astro

As a VueJs enthusiast, I was pretty excited about trying Astro to create this blog. It looks like Vue but in the end, it generates a fully static website, with no Javascript. For more details about the differences between Vue and Astro, I recommend this official article: MPAs vs. SPAs

A cool thing about Astro is that you can easily integrate Vue components in your pages. This is what we’re going to explore in this article.

What are Component Islands ?

Component Islands is neat concept that was first introduced Etsy’s frontend architect Katie Sylor-Miller in 2019. Basically, a Component Island is an interactive UI element in an otherwise static, HTML page.

It’s kind of an iframe: it completely independent from the rest of your page. You can interact inside of it, but it does not affect its surroundings.

For this example, our Component Island is a simple, interactive Vue counter.

Integrating Vue in our project

If you have not started you Astro project yet, please follow the official guide before continuing.

Let’s start with a simple page:

index.astro

---
import BaseHead from '../components/BaseHead.astro';
import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
---

<!DOCTYPE html>
<html lang="en">
  <head>
    <BaseHead title="{SITE_TITLE}" description="{SITE_DESCRIPTION}" />
  </head>
  <body>
    <main>
      <h1>Hello!</h1>
    </main>
  </body>
</html>

Astro allows us to install Vue with a single command in your terminal, awesome ✨ It automatically installs the relevant packages and updates astro.config.mjs to integrate Vue.

Terminal

# Using NPM
npx astro add vue
# Using Yarn
yarn astro add vue

And that’s it!

Creating our Vue component

For this example, I’m using Vue3 with the composition API. If you’re still in Vue 2 or use the Options API, I really recommend switching to this. I was on the fence at first but I’ll never go back, it’s pretty nice.

In src/components, create a Vue component called BaseCounter.vue. You can forget about Astro for a little bit, because this is 100% Vue! Here’s my simple component:

Counter.vue

<template>
  <div>
    Counter: {{ count }}

    <div>
      <button @click="onChange(-1)">-</button>
      <button @click="onChange(1)">+</button>
    </div>
  </div>
</template>

<script setup>
  import { ref } from "vue";

  const count = ref(0);

  const onChange = (amount) => {
    count.value += amount;
  };
</script>

Integrating our Vue component in our Astro page

Now, here comes the cool part. Let’s first import our component and fit it inside our base page:

index.astro

---
import BaseHead from '../components/BaseHead.astro';
import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';

import Counter from '../components/Counter.vue';
---

<!DOCTYPE html>
<html lang="en">
  <head>
    <BaseHead title="{SITE_TITLE}" description="{SITE_DESCRIPTION}" />
  </head>
  <body>
    <main>
      <h1>Hello!</h1>

      <Counter client:load />
    </main>
  </body>
</html>

Adding client:load is key: this tell Astro to asynchronously load the component after loading the page and make interactive. Without this, the component will appear but you won’t be able to interact with it: all the Javascript has been stripped.

Defining props for our component

Remember that when you’re working in an Astro file, you’re using Astro’s syntax. If you were to have props on your component, this would not work:

index.astro

<!-- this won't work -->
<Counter :max="15" client:load />

<!-- this is the correct way to bind variables in Astro -->
<Counter max="{15}" client:load />

But once you’re inside a Vue file, you use Vue’s syntax, as usual:

Counter.vue

<template>
  <div>
    Counter: {{ count }}

    <ExampleComponent :prop="15" />
  </div>
</template>

<script setup>
  [...]
</script>

This might seem obvious but switching between similar syntaxes can be confusing sometimes.

Don’t go over the top with Component Islands

At its core, Astro is made to render static websites that don’t need a lot of interactivity: landing pages, blogs… This is why Astro is so fast to load. If your project has complexity and you find yourself using a lot of Component Islands, Astro might not be the best choice.

For Fundimmo’s main product, we use Vue which is more adequate for what we develop.

En parlant de #frontend...