[Feature Request] - A new enhanceIslands
hook to add plugins and other setup to Islands #277
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