ElMassimo / ElMassimo/iles

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

Open
#277 7 comments 1 reaction 0 assignees View on GitHub
enhancement
Dominant language
TypeScript
Stars
1.2k
Forks
36
PR merge metrics
No merged PRs in 30d

Description

Expanding one of the ideas from here - https://github.com/ElMassimo/iles/issues/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`](https://iles.pages.dev/config#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 - https://github.com/ElMassimo/iles/discussions/213#discussioncomment-4472002). This is useful for certain use cases (like the usage of Vue plugins), such as what's discussed in this i18n support thread - https://github.com/ElMassimo/iles/discussions/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: https://github.com/ElMassimo/iles/issues/207, https://github.com/ElMassimo/iles/issues/259, https://github.com/ElMassimo/iles/discussions/6#discussioncomment-4312998, https://github.com/ElMassimo/iles/discussions/118#discussioncomment-2654522, https://github.com/ElMassimo/iles/discussions/213#discussioncomment-4472002, https://github.com/ElMassimo/iles/discussions/61#discussioncomment-1840921. For example:

```ts

import { getCurrentInstance } from 'vue'
import i18n from '~/services/i18n' // example
const app = getCurrentInstance().appContext.app
app.use(i18n)

```

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.

```ts

import { getCurrentInstance } from 'vue'
import vuetify from '@/plugins/vuetify'
const app = getCurrentInstance().appContext.app
app.use(vuetify())

```

**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.

```html
I'm a bad example, sorry!
```

The API could look like this:

```ts
// 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: https://github.com/withastro/roadmap/pull/326.

Later, Astro, in their [community call stream on 4/10/22](https://www.youtube.com/watch?v=_0IQIsSKbyM&t=1064s), decided to drop this idea and introduce `appEntryPoint` only for Vue via their Vue integration [community call stream on 19/10/22](https://www.youtube.com/watch?v=6MnIORimV94&t=1356s) with this PR: https://github.com/withastro/astro/pull/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 - https://github.com/withastro/roadmap/discussions/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](https://github.com/user-attachments/assets/e5c3c74f-ac11-4072-9c96-5cf51186b8cf)

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.