Git Product home page Git Product logo

vike-island-example's Introduction

vike-island-example

This repository serves as an illustrative example that explores the Islands Architecture on Vike.

The general idea of an “Islands” architecture is deceptively simple: render HTML pages on the server, and inject placeholders or slots around highly dynamic regions. These placeholders/slots contain the server-rendered HTML output from their corresponding widget. They denote regions that can then be "hydrated" on the client into small self-contained widgets, reusing their server-rendered initial HTML.

— Jason Miller, Creator of Preact

Features

  • Framework-Agnostic Flexibility: This example strives to offer flexibility by accommodating multiple UI frameworks, especially Vue and React. While recognizing that most developers tend to stick to a single UI framework, it provides support for multiple ones.
  • Partial Hydration: The primary focus lies in selectively and strategically hydrating components within a server-rendered HTML context. This approach optimizes performance by avoiding unnecessary rehydration of the entire application state.
  • Client Directives: The project supports strategies related to immediate hydration using client:load, viewport visibility via client:visible, idle status with client:idle, and media query matches using client:media. These directives allow for conditional hydration of components.
  • Framework Agnostic Page Context: It offers the ability to access the same Vike page context within any framework, currently Vue or React components.

Usage

The core functionality involves marking components using a specific Higher Order Component (HOC) and the usage of directives. For instance:

React

import ClockReact from "~/components/Clock.island.tsx"; // React Component
import { withHydration } from "~/island/react";

const Clock = withHydration(ClockReact);

export default function Page() {
  return (
    <>
      {/* Hydrate React component on viewport visibility */}
      <Clock client:visible />
    </>
  );
}

Vue

<script setup lang="ts">
import { withHydration } from "~/island/vue";
import ClockReact from "~/components/Clock.island.tsx";

const Clock = withHydration(ClockReact);
</script>

<template>
  <Clock client:visible />
</template>

Caveats

  • Mandatory usage of the .island.{tsx,jsx,vue} suffix on island components.
  • The component name (displayName) and the file name must be the same.
  • Inability to render islands inside islands without unwrapping (unwrap(island)).
  • Lack of support for client-side routing.

Current Status

The project has made significant progress in the Proof of Concept (PoC) phase, allowing the import and hydration of Vue components within server-rendered React components and vice versa. However, ongoing enhancements and refinements are currently being implemented on demand to improve type support, optimize performance, conduct thorough testing, and potentially refactor for enhanced efficiency.

Technical Details

The technical implementation of the islands architecture involves basically several 3 key steps:

  1. Server-Side HTML Rendering: The pages undergo complete server-side rendering in the +onRenderHtml phase. During this stage, targeted elements designated as islands are specifically marked within the DOM using Higher Order Components (HOC).
  2. Server-Side Island Rendering: After the completion of HTML rendering with marked islands, these identified components are then rendered using the guest framework renderer. The components reside within factories, generated via a Vite glob import. Rendering includes the provision of necessary data for hydration, encompassing defined strategies for each component.
  3. Strategic Client-Side Hydration: Upon rendering, on the client side within +client, it looks for marked islands. For each identified island, the hydration data is parsed, and the respective hydration process is executed based on its strategy.

Contributions

Contributions, suggestions, and feedback are welcomed and encouraged. Feel free to explore the source code and propose enhancements or report issues through the repository.

See also

vike-island-example's People

Contributors

lourot avatar luisfuturist avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

vike-island-example's Issues

Flexible Hydration with Multi-Framework Islands on Vike

Thanks @luisfloat for exploring this. Interestingly I had a different understanding of what islands are, especially because one island could be in React, another one could be in Vue, etc. At least this is an idea that caught my eye in https://docs.astro.build/en/concepts/islands/ . So here is the direction I would have taken:

1. Replace +Page.tsx by one + file per island

I would create one new setting per island, say islandReact and islandVue, so for each page I would have files like +islandReact.tsx and +islandVue.vue instead of +Page.tsx.

See https://vike.dev/meta for creating your own settings. Page is just a setting.

2. Adapt onRenderHtml() and onRenderClient() for rendering both islands

It would look like

// https://vike.dev/onRenderHtml
export { onRenderHtml }

import React from 'react'
import { renderToString as renderReactToString } from 'react-dom/server'
import { renderToString as renderVueToString } from '@vue/server-renderer'
import { createVueApp } from './app'
import { escapeInject, dangerouslySkipEscape } from 'vike/server'

async function onRenderHtml(pageContext) {
  const { islandReact } = pageContext
  const reactViewHtml = dangerouslySkipEscape(
    renderReactToString(<islandReact />)
  )

  const vueApp = createVueApp(pageContext)
  const vueViewHtml = await renderToVueString(app)

  return escapeInject`<!DOCTYPE html>
    <html>
      <body>
        <div id="react-view">${reactViewHtml}</div>
        <div id="vue-view">${vueViewHtml}</div>
      </body>
    </html>`
}
// https://vike.dev/onRenderClient
export { onRenderClient }

import React from 'react'
import { hydrateRoot } from 'react-dom/client'
import { createVueApp } from './app'

async function onRenderClient(pageContext) {
  const { islandReact, islandVue } = pageContext
  hydrateRoot(
    document.getElementById('react-view'), <islandReact />
  )

  const vueApp = createVueApp(pageContext)
  vueApp.mount('#vue-view')
}

I basically merged these two examples:

What do you think? One drawback of this is that the amount of islands is hardcoded for all pages of the entire app, as is their layout. But I'm wondering if it is any different with Astro if you want to mix React and Vue? 👀 Anyway such an example of mixing React and Vue in the same page on Vike could be quite nice.

But if what you want is just to have certain areas of the app not being hydrated, you are basically reinventing Server Components? That's quite a complex topic and we have it on our radar: https://vike.dev/react#react-server-components

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.