Skip to content

Moving onto the plugin build

Until 0.12, protobase build built the whole admin app into each bundle, with the project’s protobase.ui.tsx and every --extend folder’s compiled into it. Each bundle was frozen at the @protobase/ui it was built with: the app’s fixes reached it only with a rebuild. From 0.12 the admin app is prebuilt once per release, and protobase build builds the project’s protobase.ui.tsx as a plugin beside it. The project’s code is written the same way; this guide moves a project over and says what to look at.

Move the project’s @protobase packages to 0.12 or newer, as for any release, and build:

Terminal window
bun add @protobase/cli@^0.12 @protobase/server@^0.12 @protobase/schema@^0.12 @protobase/layout@^0.12 @protobase/ui@^0.12
bun run protobase build
built dist: protobase.config.js, public/ with plugins app and protobase.bundle.json (api /api)

A bundle of an older release is refused by the 0.12 runtime, as every new minor below 1.0 is; this one rebuild is the whole migration for most projects. The new bundle holds:

dist/
protobase.config.js
public/
index.html, assets/ the prebuilt admin app
plugins/app/ protobase.ui.tsx, as the plugin app
protobase.theme.css empty until the project has a theme
protobase.favicon.svg Protobase's until the project has its own
protobase.bundle.json version 3, naming the plugins and the app's version

Nothing in it has to change: its named component exports, defineUi({ actions, shell, extends }) and the components it registers work as before. definePlugin is the same function under its new name, and also takes field types. Three things a plugin cannot do, which a built-in protobase.ui.tsx could, fail the build or show at once:

  • Modules of the shared packages. react, react/jsx-runtime, react-dom and @protobase/ui come from the app, by those names. An import of another module of theirs, such as react-dom/client or a file inside @protobase/ui, fails the build: import from the package’s main entry instead.
  • Browser work at the top level. The build loads protobase.ui.tsx once in Node to read its field types. Code that touches window, document or localStorage when a module loads fails the build; move it into a component, a hook or a handler.
  • A data library of its own. A component that used @tanstack/react-query directly found the app’s query client while it was built into the app; as a plugin it carries its own copy, which does not. Read through @protobase/ui’s hooks (useList, useRecord, useClient), which share the app’s cache and session.

The project’s Tailwind classes are built into the plugin’s own stylesheet, plugins/app/assets/styles-<hash>.css: utilities only, each reading the app’s tokens. bg-primary and rounded-md look as before. A class that only worked because the app’s own stylesheet happened to have it is now in the plugin’s too, so nothing is lost. To change the app’s colors, radius or font, write a protobase.theme.css, not rules against the app’s markup.

Each --extend folder’s protobase.ui.tsx becomes a plugin of its own, plugins/<name>/, named by its package.json, else its folder, and merged before the project’s, as before. Its protobase.config.ts is merged into the config module as before. Two extensions that would be plugins of one name fail the build: give one’s package.json another name.

A host that serves public/ as before keeps working: index.html for navigations, files for the rest. Two things are new:

  • The plugins’ assets/ folders, public/plugins/<name>/assets/, are named by their content like public/assets/: serve them as immutable too. plugin.json, protobase.theme.css and protobase.favicon.svg are served with no-cache.
  • A host that keeps the prebuilt app of newer releases may serve it for the manifest’s shell.paths, so the app gets that release’s fixes without a rebuild (see the shell). protobase serve does so with its own when every plugin of the bundle loads in it.

Nothing changes: protobase dev builds protobase.ui.tsx into its page with hot reload, as before, and serves the theme too. protobase build && protobase serve dist runs the bundle as a host does, with the project’s UI loaded as the plugin app.

From now on, a release of Protobase within the same minor needs no rebuild of the project’s UI: the app it runs in is the release’s, and the plugin keeps working within its plugin API. The server config still follows the bundle’s rule, so a new minor below 1.0 is still a rebuild.