Skip to content

Introduction

A frontend feature is an extension that lives outside the core, in its own directory, and adds to Clarive without rebuilding the core:

  • React pages (their own routes), menu entries (side and top menus) and their own side menu sections.
  • Components painted inside core screens, such as the body of a topic revision.
  • Permissions (actions that show up in the role editor).
  • Backend endpoints in Perl, protected by those permissions.
  • Their own translations and stylesheets.

The feature is built on its own with Vite. The libraries that must be the core's own instances (React, antd...) are left as unresolved imports. At runtime the browser resolves them against the core through an import map. The feature and the core therefore share a single React instance, and adding or rebuilding a feature never requires rebuilding the core.

 feature (npm run build)                     core (already built)
 ───────────────────────                     ────────────────────
 import React from 'react'   ── import map ──►  /static/dist/sdk/react.js       ──► core React
 import { Button } from 'antd'  ────────────►  /static/dist/sdk/antd.js         ──► core antd
 import { useSdk } from '@clarive/sdk'  ────►  /static/dist/sdk/clarive-sdk.js  ──► core SDK

The examples in these pages come from a sample feature called hello-react.

Directory structure

CLARIVE_BASE/features/<id>/          <- <id> = directory name, e.g. hello-react
├── feature.yml                      <- manifest: declares the frontend
├── package.json                     <- build devDependencies only (vite, postcss-prefix-selector)
├── vite.config.mjs                  <- standalone build
├── src/                             <- frontend source code
│   ├── index.jsx                    <- entry: export default register(sdk)
│   ├── HelloPage.jsx                <- pages (loaded on demand)
│   ├── actions.js                   <- action (permission) names
│   └── hello.css                    <- plain CSS (prefixed at build time)
├── public/                          <- WHAT THE CORE SERVES at /feature/<id>/...
│   └── dist/                        <- build output (index.js, chunks/, style.css)
├── i18n/
│   └── es.po                        <- the feature's own translations
└── lib/BaselinerX/                  <- Perl backend (it is in @INC)
    ├── HelloReact.pm                <- action (permission) registration
    └── Controller/HelloReact.pm     <- /feature/<id>/api/... endpoints

Rules:

  • The feature id is the directory name. It is used in urls (/feature/<id>/...), in the CSS wrapper (data-feature="<id>") and in the namespace of the Perl controller.
  • A directory whose name starts with # is ignored. Renaming a feature directory to #<id> disables it without deleting it.
  • Features are looked up in CLARIVE_BASE/features and CLARIVE_HOME/features.
  • Only public/ is served over HTTP. src/, lib/, node_modules/... are never reachable.

feature.yml

name: Hello React
version: 0.1.0
author: Clarive Team
frontend:
    entry: dist/index.js    # relative to public/ -> /feature/hello-react/dist/index.js
    css: dist/style.css     # optional; a file or a list of files, also relative to public/
    sdk: "^1"               # SDK major the feature is built for (a minor too if it needs one: "^1.2")
Key Required What it does
name no Human name of the feature. If present, it must be a text.
frontend.entry yes ES module the core imports at startup. Must be a .js (or .mjs) file inside public/.
frontend.css no Stylesheets the core adds to the <head>: a file or a list of files. A declared file that does not exist or escapes public/ is skipped with a warning in the log.
frontend.sdk yes SDK compatibility. "^1" (or "1", "1.x") = any 1.x. "^1.2" (or "1.2") = same major (1) and minor >= 2. If the core does not match, the feature is skipped with a warning in the browser console.

The server validates the frontend part of feature.yml. A feature that breaks the schema (invalid YAML, a missing entry or sdk, a wrong type, an entry that has not been built...) is left out with an error in the server log, and the rest of the features load normally:

Feature hello-react: feature.yml frontend.sdk is required, e.g. sdk: "^1", frontend not loaded
Feature hello-react: feature.yml frontend.entry dist/index.js not found in public/ (not built?), frontend not loaded

An unknown key under frontend (usually a typo, such as entyr) is only a warning: feature.yml frontend.entyr is not a known key, ignored. A feature without a frontend key is backend-only and is not announced to the browser.

The server reads feature.yml on every page load (it is not cached), so changing it or dropping a new frontend-only feature in shows up after reloading the browser.

What the server sends to the browser (in appData.features) for each feature is:

{
  id: 'hello-react',
  name: 'Hello React',
  sdk: '^1',
  entry: '/feature/hello-react/dist/index.js?v=1790668000',  // ?v=<mtime>: busts the cache on rebuild
  css: ['/feature/hello-react/dist/style.css?v=1790668000'],
  i18n: { 'Save': 'Grabar', ... }                             // dictionary of the user's language
}

Development workflow

When you change... Do this
Code in src/ or CSS npm run build in the feature and reload the browser. The core is not touched.
feature.yml Reload the browser (it is read on every page load).
i18n/<lang>.po Reload the browser.
Perl in lib/ (actions, controllers, CIs) Restart the web server (cla web-stop and cla web-start).
A new feature Create the directory and build it. Restart the web server if it has Perl code; if it only has a frontend, reloading is enough.

Checklist for a new feature:

  1. Create CLARIVE_BASE/features/<id> with feature.yml, package.json and vite.config.mjs (set FEATURE_ID to <id>).
  2. src/index.jsx with export default function register(sdk); pages with React.lazy.
  3. src/actions.js and lib/BaselinerX/<Name>.pm with the actions; permissions on routes and menus.
  4. If there is a backend: lib/BaselinerX/Controller/<Name>.pm with namespace => 'feature/<id>/api' and Does('ACL') : ACL(...) on every action.
  5. Texts with sdk._() and i18n/<lang>.po files.
  6. If it paints inside core screens: sdk.addComponent and viewer_components in the repository CI.
  7. Plain CSS in src/, declared in frontend.css; colors with var(--cla-...).
  8. feature.yml with sdk: "^1" (or "^1.<minor>" if it uses something added in that minor).
  9. npm install && npm run build, restart the server if there is Perl, grant the actions in a role and check __CLARIVE_SDK__.features shows loaded in the browser console.