Building and Deploying#

Warning

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

Bundles 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. 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 Bundle#

From your bundle directory:

neo-ui build

Output in dist/:

dist/
├── mf-manifest.json     # Module Federation manifest
├── bundle-info.json     # Deploy metadata (name, version, dashboards), stamped by neo-ui build
├── [hash].js            # Bundle chunk(s), one per dashboard
└── [hash].css           # Styles

Bundle Size#

What the host provides#

The host supplies several libraries to bundles at runtime via Module Federation. You do not pay for their size in your 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 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/<bundle-name>/dist/mf-manifest.json.

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

  4. Adds the bundle 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/bundle/dist:/app/extensions:ro

The host detects the /extensions/mf-manifest.json path and loads the bundle 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 bundle 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/<bundle-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 a Bundle#

  1. Make changes in src/.

  2. Run neo-ui build.

  3. Run neo-ui deploy again to upload the new build, overwriting the previous one.

  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#

Each bundle build records the platformVersion it was compiled against, which is the @squirro/nextgen-core version in your project. neo-ui deploy checks this against the running host version and gates the deploy on the result:

Verdict

Meaning

Deploy behavior

compatible

Exact version match.

Proceeds.

degraded

Same 0.x minor, different patch or pre-release.

Warns and proceeds.

incompatible

Different 0.x minor.

Blocked. Fix before deploying.

unknown

Instance predates version reporting.

Warns and proceeds.

If the deploy is blocked as incompatible, upgrade the bundle to match the host, then deploy again:

neo-ui upgrade
neo-ui deploy

To override the gate and deploy anyway, use --force:

neo-ui deploy --force

To check the verdict in advance without uploading, run neo-ui deploy --dry-run.

Multiple Bundles#

The host supports one bundle per project. If your use case requires multiple bundles for a single project, visit the Squirro Support website and submit a technical support request.