Building and Deploying#

Warning

Project Neo is currently in Technical Preview. Features described in this section may change before general availability.

Extensions are deployed independently from the core Project Neo application. Two deployment models are available:

Deployment Models#

Model

How it works

Use case

Platform deployment

Bundle uploaded to the Squirro backend via squirro_asset. The host loads it per-project from /v0/workspaces/{domain}/ui_bundles/{name}/dist/.

Production deployment to a Squirro SaaS or managed instance.

Local bind-mount

Bundle folder mounted into the Project Neo Docker container at /app/extensions/. The host loads it globally.

Local development and testing.

Use platform deployment for production. The bind-mount model is useful for local testing without uploading to the platform.

Step 1: Build the Extension#

From your extension project directory:

nextgen build

Output in dist/:

dist/
├── mf-manifest.json     # Module Federation manifest
├── [hash].js            # Extension bundle(s), one per dashboard
└── [hash].css           # Styles

Bundle Size#

What the host provides#

The host supplies several libraries to extensions at runtime via Module Federation. You do not pay for their size in your extension bundle:

  • react, react-dom.

  • react-router-dom.

  • zustand.

  • @tanstack/react-query.

  • i18next, react-i18next.

Any other dependency you add to package.json is bundled into the extension output.

Per-dashboard code splitting#

Code splitting happens automatically. The () => import('./dashboards/MyDashboard') entry for each dashboard in the manifest produces a separate output chunk. The host fetches that chunk only when the user navigates to the dashboard, not at application load.

For heavy dependencies used in only one dashboard (such as a charting library or a PDF renderer), the same technique applies inside the component itself:

import { lazy, Suspense } from 'react';

const HeavyChart = lazy(() => import('./HeavyChart'));

export default function Analytics({ projectId }: { projectId: string }) {
  return (
    <Suspense fallback={<p>Loading chart</p>}>
      <HeavyChart projectId={projectId} />
    </Suspense>
  );
}

That splits HeavyChart and its dependencies into a separate chunk that loads on demand.

Analyzing the bundle#

To inspect chunk sizes and the dependency breakdown, run the build with rsbuild’s built-in analyzer flag from inside the project directory:

BUNDLE_ANALYZE=true npx rsbuild build

The command writes a dist/report.html file and opens it in the browser. Use it to identify which dependency is responsible for an oversized chunk.

Size recommendations#

No hard limit is enforced by the build tooling, but keep each dashboard chunk under 200 KB parsed (not gzipped) as a practical target. Chunks larger than that add noticeable load time on slower connections when a user first navigates to the dashboard.

If a chunk exceeds that target, use dynamic imports to split the heaviest dependency, or check whether the dependency has a lighter alternative.

Step 2: Deploy#

How Loading Works#

When a user navigates to a project, the host:

  1. Fetches the project configuration and reads the frontend.ui-bundle value.

  2. Loads mf-manifest.json from /v0/workspaces/<domain>/ui_bundles/<project-name>/dist/mf-manifest.json.

  3. Registers the Module Federation remote and loads the extension manifest.

  4. Adds the extension dashboards to the sidebar navigation and creates dynamic routes.

The bundle is loaded once per session and cached across project revisits within the same browser session.

Local Bind-Mount#

To test a production build locally without uploading to the platform, mount the dist/ folder into the Project Neo Docker container:

# docker-compose.local.yml
volumes:
  - /path/to/your/extension/dist:/app/extensions:ro

The host detects the /extensions/mf-manifest.json path and loads the extension globally for all projects. No frontend.ui-bundle project configuration is needed in this mode.

Note

The bind-mount model is for local development and testing only. Use platform deployment for production.

Step 3: Verify#

After deploying, open the Project Neo application in the browser and hard-refresh (Cmd+Shift+R on macOS, Ctrl+Shift+R on Windows and Linux). Your extension dashboards should appear in the sidebar.

To verify the manifest is reachable after a platform deployment:

https://your-instance.example.com/v0/workspaces/<domain>/ui_bundles/<project-name>/dist/mf-manifest.json

To verify the manifest is reachable after a local bind-mount:

http://localhost:5555/extensions/mf-manifest.json

Both URLs should return JSON. If either returns HTML or a 404, the bundle did not reach the correct path.

Updating an Extension#

  1. Make changes in src/.

  2. Run nextgen build.

  3. Run squirro_asset ui_bundle upload again with the same --folder dist/ argument, overwriting the previous build.

  4. Users see the update on their next page load. No server restart is needed.

Chunk filenames include content hashes, so new and old chunks never conflict. Only mf-manifest.json is overwritten in place.

Version Compatibility#

Extensions declare the platformVersion they were built against, injected automatically by the CLI at build time. If that version does not match the running host version, a warning is printed to the browser console and the extension still loads:

[extensions] ════════════════════════════════════════════════════════════
  ⚠  VERSION MISMATCH
  Extension built against nextgen-core@1.2.0, host is running @1.3.0. Compatibility is not guaranteed.
[extensions] ════════════════════════════════════════════════════════════

Extensions are designed to be forwards-compatible within a major version. If you see that warning in production, rebuild and redeploy against the current core version at your earliest convenience:

npm install @squirro/nextgen-core@latest
nextgen build
# then re-upload with squirro_asset

Multiple Extensions#

The host supports one extension per project. If your use case requires multiple extensions for a single project, contact Squirro support.