npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tempots/vite

v0.0.7

Published

Vite plugin for Tempo SSR, SSG, and Islands architecture

Readme

@tempots/vite

Vite plugin for Tempo applications with SPA, SSG, and SSR support.

Installation

npm install @tempots/vite
# or
pnpm add @tempots/vite

Features

  • SPA Mode (default): Pure client-side rendering, no server pipeline
  • SSG Mode: Pre-render pages at build time for static hosting
  • SSR Mode: Server-side render on each request with HMR support
  • Islands Mode: Static by default, hydrate only marked interactive components
  • Hybrid Mode: Combine SSG for static pages with SSR for dynamic ones
  • HMR: Component-level hot module replacement with state preservation

Usage

Single-Page Application (SPA)

Pure client-side rendering — the default. No entry-server.ts required:

// vite.config.ts
import { defineConfig } from 'vite'
import { tempo } from '@tempots/vite'

export default defineConfig({
  plugins: [tempo()]
})

Static Site Generation (SSG)

Pre-render pages at build time:

// vite.config.ts
import { defineConfig } from 'vite'
import { tempo } from '@tempots/vite'

export default defineConfig({
  plugins: [
    tempo({
      mode: 'ssg',
      routes: ['/', '/about', '/contact'],
    })
  ]
})

Server-Side Rendering (SSR)

Render pages on each request:

// vite.config.ts
import { defineConfig } from 'vite'
import { tempo } from '@tempots/vite'

export default defineConfig({
  plugins: [
    tempo({
      mode: 'ssr',
      ssrEntry: 'src/entry-server.ts',
    })
  ]
})

Islands Architecture

Static by default, hydrate only interactive components:

// vite.config.ts
import { defineConfig } from 'vite'
import { tempo } from '@tempots/vite'

export default defineConfig({
  plugins: [
    tempo({
      mode: 'islands',
    })
  ]
})

HMR (Hot Module Replacement)

The plugin provides automatic HMR for Tempo applications in dev mode. No code changes required — just add the plugin.

How It Works

  • File-level HMR: The plugin detects render() calls and wraps them in an HMR boundary. When any file changes, the app re-renders without a full page reload.
  • Component-level HMR: Calls to PascalCase functions imported from local modules (e.g., ItemLink(item)) are wrapped in component boundaries. When a component's source file changes, only the subtrees using that component re-render — the rest of the page is untouched.
  • State preservation: Prop signals assigned to variables (const count = prop(0)) are automatically labeled in dev mode. Their values are snapshotted before a hot update and restored after re-render.
  • Error overlay: If a re-render throws, Vite's native error overlay shows the error. Fixing the code and saving dismisses it automatically.

Component Naming Convention

The component-level HMR uses PascalCase as a heuristic to identify component functions:

  • ItemLink, PageFeedView, Appwrapped (PascalCase, imported from relative path)
  • loadRoute, formatItemnot wrapped (camelCase)
  • When, ForEach, Fragmentnot wrapped (imported from @tempots/dom, not a relative path)

HMR Configuration

HMR is enabled by default in dev mode. To disable:

tempo({ hmr: false })

Configuration

Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | mode | 'spa' \| 'ssg' \| 'ssr' \| 'islands' \| 'hybrid' | 'spa' | Rendering mode | | routes | string[] \| RouteConfig[] \| (() => Promise<...>) \| 'crawl' | 'crawl' | Routes to pre-render (SSG) | | seedRoutes | string[] | ['/'] | Seed routes for crawl mode | | entry | string | 'src/entry-client.ts' | Client entry file | | ssrEntry | string | 'src/entry-server.ts' | Server entry file (exports render or App) | | template | string | 'index.html' | HTML template file | | container | string | '#app' | App container selector | | hydrate | boolean | true for SSR/islands | Generate hydration markers | | outDir | string | 'dist' | Output directory | | hmr | boolean \| { errorBoundary?: boolean } | true | HMR configuration (dev mode only) |

Route Configuration

Routes can be simple strings or objects with more options:

tempo({
  mode: 'ssg',
  routes: [
    '/',                              // Simple path
    '/about',
    { path: '/blog', output: 'blog.html' },  // Custom output
  ]
})

Automatic Route Discovery (Default)

By default, the plugin automatically discovers routes by crawling internal links starting from /:

tempo({
  mode: 'ssg',
  // routes: 'crawl' is the default
})

Customize crawling with seed routes:

tempo({
  mode: 'ssg',
  routes: 'crawl',
  seedRoutes: ['/', '/api', '/docs'],  // Start crawling from multiple entry points
})

The crawler:

  • Follows all internal links (href starting with /)
  • Skips external links and static assets
  • Handles .html routes
  • Strips query strings and hash fragments

Dynamic Routes

Use a function to generate routes dynamically:

tempo({
  mode: 'ssg',
  routes: async () => {
    const posts = await fetchBlogPosts()
    return [
      '/',
      '/about',
      ...posts.map(post => `/blog/${post.slug}`)
    ]
  }
})

API

tempo(options?)

Creates the Tempo Vite plugin.

Returns: Plugin[] - Array of Vite plugins

renderApp(app, options?)

Helper to render a Tempo app to HTML string. Useful for custom SSR setups.

import { renderApp } from '@tempots/vite'
import { App } from './App'

const html = await renderApp(App(), { hydrate: true })

Project Structure

Recommended project structure for SSR:

my-app/
├── src/
│   ├── App.ts           # Main app component
│   ├── entry-client.ts  # Client entry (hydration)
│   └── entry-server.ts  # Server entry (rendering)
├── index.html           # HTML template
├── server.js            # Express/Node server
└── vite.config.ts       # Vite configuration

Example: Full SSR Setup

See the ssr-demo for a complete working example.

License

Apache-2.0