Skip to content

[Feature Request] - A new enhanceIslands hook to add plugins and other setup to Islands #277

Open
@TechAkayy

Description

Expanding one of the ideas from here - #276. I want to run this past the community before submitting a PR. Please share your thoughts.

Is your feature request related to a problem? Please describe.

The current enhanceApp only applies to the "outer" shell app that is used during development (for a nice HMR experience) and during build time to statically generate the app (as explained by @ElMassimo here - #213 (comment)). This is useful for certain use cases (like the usage of Vue plugins), such as what's discussed in this i18n support thread - #6. However, this "outer" app won't be available in the built app.

Currently, to use Vue plugins inside interactive Islands, the only way is to add the plugin inside the island, as discussed in these threads: #207, #259, #6 (reply in thread), #118 (comment), #213 (comment), #61 (comment). For example:

<script setup lang="ts">
  import { getCurrentInstance } from 'vue'
  import i18n from '~/services/i18n' // example
  const app = getCurrentInstance().appContext.app
  app.use(i18n)
</script>

This method is very inconvenient, especially when using UI component libraries like Vuetify, where multiple Islands on the page require the same plugin setup. In such cases, we would need to add the following code to each Island. Even if moved outside the SFC, it's an overhead to import the same in each Island.

<script setup lang="ts">
  import { getCurrentInstance } from 'vue'
  import vuetify from '@/plugins/vuetify'
  const app = getCurrentInstance().appContext.app
  app.use(vuetify())
</script>

Describe the solution you'd like

This feature request is for a new enhanceIslands API that can enhance islands by hooking into the island app's lifecycle:

  • For Vue islands, allow app.use(plugin) for plugins like Vuetify, Pinia, etc.
  • For Preact-like apps, wrap components in a custom Provider to manage global data (i18n, themes, etc.).
  • Add any initial user state to the island.
  • Enable shared state across all islands (using a common Pinia store).
  • Support Vue/Runes/other reactivity across islands.

Unlike enhanceApp, which applies to the Vue shell, enhanceIslands would apply to all supported frameworks (e.g., Svelte, Preact, Solid). Users would need to manage conditional setup based on the framework-specific setup. Open to suggestions here 😄.

Here's one idea: we could use a simple iles attribute as a convention on the hydrated island definition, pass it to the app object, and use it within enhanceIslands to conditionally apply the required setup.

<IslandBackLink iles="back-link" href="/blog" client:load>I'm a bad example, sorry!</IslandBackLink>

The API could look like this:

// app.ts
import { defineApp } from 'iles'
import { createI18n } from '~/logic/i18n'
import { createPinia } from 'pinia'
import { createVuetify } from 'vuetify'

const pinia = createPinia({/* config */})
const vuetify = createVuetify({/* config */})

export default defineApp({
  enhanceIslands({ app }) {
    if (app.iles === "hero-widget") { // Not required when using only one framework for islands
      app.use(pinia)
      app.use(vuetify)
    }
    if (app.iles === "back-link") {
      // Some Preact setup for this island.
    }
  },
  enhanceApp({ app }) {
    const i18n = createI18n()
    app.use(i18n)
    i18n.global.locale = import.meta.env.VITE_LOCALE
  },
})

Describe alternatives you've considered

Astro had a similar API proposal (https://github.com/withastro/roadmap/blob/app-setup/proposals/0000-app-setup.md) to introduce an appEntrypoint for all supported frameworks as part of this PR: withastro/roadmap#326.

Later, Astro, in their community call stream on 4/10/22, decided to drop this idea and introduce appEntryPoint only for Vue via their Vue integration community call stream on 19/10/22 with this PR: withastro/astro#5075. In this, the user creates a _app.ts file and passes it as the appEntryPoint in their Astro Vue integration, which becomes a Vite virtual module, applying the "setup" (like vue.use plugins) for all Vue Islands.

Another related thread - withastro/roadmap#810

We already have the app.ts entry, and the new enhanceIslands can be framework-agnostic, which I believe will be simpler from a usage perspective. Moving to a "framework-specific" module would create a new "layer" in the workflow, which is what Astro follows (via their integrations API) which does have its advantages.

Additional context

This new enhanceIslands API added to the Iles core will be consumed by framework-specific createFrameworkIsland (e.g., createVueIsland) modules. For example, in: https://github.com/ElMassimo/iles/blob/main/packages/hydration/vue.ts

image

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions