Configuration

Put plugin options and optional Vite settings in sitelo.config.js. No vite.config.js is required.

export default {
  site: 'https://example.com',
  rss: {
    site: 'https://example.com',
    title: 'My Blog',
    description: 'Latest posts',
    routePrefix: '/blog',
  },
  vite: {
    publicDir: 'static',
    build: {
      emptyOutDir: true,
      outDir: 'public',
    },
    server: {
      port: 8888,
    },
  },
}

Plugin options

Dev toolbar

While sitelo (dev) is running, a small bar at the bottom of each page shows the current route, page file, params, and how many server islands are on the page. Use Copy for a debug blob when filing issues. It never appears in sitelo build output.

// sitelo.config.js
export default {
  devToolbar: false, // hide for everyone on this project
}

Vite options

Anything under vite is merged into Vite’s config. CLI flags (e.g. --port) override both.

Existing vite.config.js

Still supported — either Vite-only options, or full plugin control:

// Vite options only; sitelo still injects the plugin
export default {
  publicDir: 'static',
  server: { port: 8888 },
}
// Register the plugin yourself
import htmlPages from 'sitelo'

export default {
  plugins: [htmlPages({
    site: 'https://example.com',
  })],
}

If the plugin is already in your Vite config, put plugin options there — not also as plugin options in sitelo.config.js (sitelo will error).

Sitemap & RSS

Set site to emit dist/sitemap.xml.

RSS:

export default {
  rss: {
    site: 'https://example.com',
    title: 'My Blog',
    description: 'Latest posts',
    routePrefix: '/blog',
  },
}

Produces dist/rss.xml with an item for every page under routePrefix.

Opt-in static search powered by Pagefind. Enable it, mark the content to index, mount the UI, then sitelo build.

1. Enable indexing

Set pagefind: true. After sitelo build you get dist/pagefind/, and by default a copy in public/pagefind/ so the next sitelo (dev) or sitelo preview can serve /pagefind/ without rebuilding.

export default {
  pagefind: true,
}

2. Mark content and add a mount point

Put data-pagefind-body on the main content so nav/footer aren’t indexed. Leave an empty element for the search UI:

3. Mount the Pagefind UI

Load /pagefind/pagefind-ui.js and pagefind-ui.css from your client script (only after a build has produced the index):

async function initSearch() {
  const mount = document.querySelector('#search')
  if (!mount) return

  // Index only exists after `sitelo build` (synced to public/pagefind by default)
  try {
    const probe = await fetch('/pagefind/pagefind-ui.js', { method: 'HEAD' })
    if (!probe.ok) return
  } catch {
    return
  }

  const style = document.createElement('link')
  style.rel = 'stylesheet'
  style.href = '/pagefind/pagefind-ui.css'
  document.head.appendChild(style)

  await new Promise((resolve, reject) => {
    const script = document.createElement('script')
    script.src = '/pagefind/pagefind-ui.js'
    script.onload = resolve
    script.onerror = reject
    document.body.appendChild(script)
  })

  new window.PagefindUI({
    element: '#search',
    showImages: false,
  })
}

initSearch()

4. Build and ignore the synced bundle

sitelo build
# then: sitelo preview — or sitelo (dev) using public/pagefind
public/pagefind/

Advanced options (syncPublic, glob, language, selectors, …) go on an object: pagefind: { syncPublic: false, glob: '**/*.html' }. Full UI options: pagefind.app.

404

Create src/404.ht.js for dist/404.html. Otherwise a clean default is generated.