@keboola/vite-plugin-kai-preview
v1.0.1
Published
Vite plugin for Keboola data apps: pick parts of the page in Keboola's app preview and tell Kai where each is written
Readme
@keboola/vite-plugin-kai-preview
Vite plugin that connects a Keboola data app to Keboola's app preview. The preview learns whether the app rendered or crashed, and in the app Builder the user picks parts of the running app so Kai learns which parts they mean and where each is written in the code.
Install
npm install --save-dev @keboola/vite-plugin-kai-preview// vite.config.ts
import { kaiPreview } from '@keboola/vite-plugin-kai-preview';
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [react(), kaiPreview()],
});What it does
- Every page, in dev and in the build, tells the preview whether it rendered or crashed:
kai-preview-erroron the first uncaught error,kai-preview-healthyonce the app renders into#root. An app mounting elsewhere passeskaiPreview({ mount: '#app' }); without the element, any content in<body>counts. - Source locations are relative to the git repository holding the app, or to the Vite root outside one, so they match the paths in the repository.
- On the dev server only, injects a part picker. Keboola's preview turns it on and off; outside the preview it does nothing. A click picks an element (
kind: 'element'); a drag picks an area, sent withkind: 'area'andarea: { inside, within, above, below }: the parts in it, the part around it and its nearest neighbours, each with its source location. - On the dev server only, stamps each HTML element with
data-kai-source="src/File.tsx:line:column", where its JSX is written, by serving React's dev JSX runtime through a wrapper.
An error boundary reports what it catches through the page globals typed by KaiPreviewWindow:
// In the boundary's componentDidCatch:
window.__kaiPreviewCrashed = true; // never reports healthy while the fallback shows
window.__kaiNotifyError?.(error.message, error.stack);Works with React 18 and 19 on Vite 5 and later, with @vitejs/plugin-react.
Messages
The picker talks only to the page embedding it, by postMessage:
| Direction | Type |
| -------------- | -------------------------------------------------------------------- |
| Page → preview | kai-preview-error (message, stack), kai-preview-healthy |
| Preview → page | kai-preview-healthy-ack |
| Page → preview | kai-preview-picker-ready (features, version; on load and ping) |
| Preview → page | kai-preview-picker-ping |
| Preview → page | kai-preview-pick-start, kai-preview-pick-stop |
| Preview → page | kai-preview-pick-clear (one part by id, or all) |
| Page → preview | kai-preview-picked (id, selection) |
| Page → preview | kai-preview-unpicked (id; a picked part clicked again) |
| Page → preview | kai-preview-pick-cancelled (Esc) |
