7.1 KiB
Nebula.js Development Guide for AI Agents
Project Overview
Nebula.js is a framework for building and embedding Qlik visualizations. It's a Lerna monorepo managing multiple packages under @nebula.js npm scope. The core architecture separates visualization authoring (supernova) from rendering (nucleus) with stardust as the public API facade.
Architecture
Package Structure
apis/stardust/- Public API that exposesnucleusandsupernovaAPIs. Entry point for consumers.apis/nucleus/- React-based mashup runtime that renders visualizations in web appsapis/supernova/- Hooks-based API for building custom visualizations (the "component" layer)apis/locale/- Translation strings and locale generation (private)apis/theme/- Theme access and consumption (private)apis/conversion/- Conversion utilities for hyperCube extensions (private)apis/enigma-mocker/- Mock enigma app for rendering without Qlik engineapis/snapshooter/- Chart rendering as imagesapis/test-utils/- Testing utilitiescommands/- CLI tools (build,serve,create,sense) for visualization developmentpackages/ui/- Shared UI components (private)
Visualization Component Pattern (Supernova)
Visualizations are defined as "supernovas" with this structure:
export default function supernova(galaxy) {
return {
qae: {
properties: {}, // QIX object properties schema
data: {} // Data definition (dimensions, measures)
},
component() {
// Hooks-based component using @nebula.js/stardust hooks
const element = useElement();
const layout = useLayout();
useEffect(() => {
// Render logic here
}, [layout]);
}
};
}
Key hooks from @nebula.js/stardust:
useElement()- Get the DOM elementuseLayout()- Get QIX layout objectuseModel()- Access QIX modeluseStaleLayout()- Layout that doesn't trigger re-rendersuseSelections()- Handle user selectionsuseConstraints()- Interaction constraints (edit, select, active, passive)useEffect(),useState(), etc. - React-like hooks
See apis/supernova/src/hooks.js for complete hook implementations.
Nucleus Rendering Flow
Nucleus (React-based) orchestrates visualization rendering:
Supernova.jsxcomponent mounts the visualization element- Calls supernova lifecycle:
created()→mounted()→render()→willUnmount() - Passes context (constraints, interactions, theme, appLayout) to component
- Uses
RenderDebouncerto batch updates
Development Workflow
Setup & Build
yarn install # Install all dependencies
yarn run locale:generate # Generate translation files (required before build)
yarn run build # Build all packages (production UMD + ESM)
yarn run build:dev # Build with source maps for development
yarn run build:watch # Watch mode for active development
Critical: Always run locale:generate before building if locale files changed.
Testing
yarn test:unit # Jest unit tests for all packages
yarn test:component # Playwright component tests
yarn test:integration # Playwright integration tests
yarn test:rendering # Visual regression tests (Playwright)
yarn test:mashup # Full mashup integration tests
Unit tests use jest with jest-environment-jsdom. See jest.config.js for coverage and test patterns.
CLI Commands for Visualizations
When developing a supernova visualization:
nebula create <name> # Scaffold new visualization
nebula serve # Start dev server with hot reload
nebula build # Build visualization for distribution
nebula sense # Build as Qlik Sense extension
Dev Server (nebula serve):
- Builds visualization to
/distautomatically - Connects to Qlik Associative Engine (default: localhost:9076)
- Supports fixtures for testing without engine connection
- See commands/serve/README.md for options
Rollup Build Configuration
All packages use shared rollup.config.js:
- UMD format for browsers (default export via
unpkg/jsdelivr) - ESM format for bundlers (exposed via
modulefield) - Creates
.dev.jsvariants with source maps in development mode - Validates
main,module,unpkg,jsdelivrtargets in package.json match naming convention
Lerna Versioning
This project uses Lerna for version management with conventional commits:
- Use commit types:
feat:,fix:,chore:,docs:, etc. lerna versionreads commits to determine semver bump- All packages are versioned together (see lerna.json)
Code Conventions
ESLint Configuration
- Uses Airbnb style with Prettier formatting
- Flat config format (eslint.config.mjs)
- Jest environment globals enabled for test files
- Custom rules:
max-len: 0,no-plusplus: 0, React prop-types disabled
File Naming
- Test files:
*.spec.js,*.test.js,*.spec.jsx,*.test.jsx - Stories (Storybook):
**/__stories__/** - Built artifacts:
dist/,lib/(git-ignored)
Private Packages
Packages like locale, theme, conversion, and ui are marked private/internal - they're consumed by stardust but not published as standalone packages.
Common Patterns
Picasso.js Integration
Many visualizations use Picasso.js for rendering. Standard pattern:
import picassojs from 'picasso.js';
import picassoQ from 'picasso-plugin-q';
const picasso = picassojs();
picasso.use(picassoQ);
// In component:
const instance = picasso.chart({
element,
data: [{ type: 'q', key: 'qHyperCube', data: layout.qHyperCube }],
settings: definition({ layout })
});
See commands/create/templates/sn/picasso/common/src/index.js.
Handling Selections
Use pic-selections helper for Picasso-based charts to connect brush selections to QIX selections API. Example in templates.
Extension Points (ext)
Qlik Sense extensions can define ext object for Sense-specific customizations (support.export, etc.). Pass galaxy.anything.sense to detect Sense environment.
Key Files to Reference
- apis/supernova/src/creator.js - Component lifecycle implementation
- apis/nucleus/src/components/Supernova.jsx - React wrapper for visualizations
- apis/supernova/src/hooks.js - All available hooks
- .github/CONTRIBUTING.md - Contribution guidelines and git workflow
Debugging
- Build issues: Check locale generation ran, verify package.json targets match rollup config expectations
- Hook errors: "Invalid stardust hook call" means hooks called outside component function
- Visualization not updating: Check if using
useStaleLayout()vsuseLayout()correctly - stale doesn't trigger re-renders