--- name: workleap-squide description: | Squide is a React modular application shell for Workleap web applications. Use this skill when: (1) Creating or modifying Squide host applications or modules (2) Registering routes, navigation items, or MSW request handlers (3) Working with FireflyRuntime, initializeFirefly, or AppRouter (4) Setting up integrations: TanStack Query, i18next, LaunchDarkly, Honeycomb, MSW, Storybook (5) Implementing deferred registrations or conditional navigation items (6) Fetching global public/protected data with usePublicDataQueries/useProtectedDataQueries (7) Using Squide hooks: useNavigationItems, useRenderedNavigationItems, useIsBootstrapping, useLogger, useEventBusListener, useEventBusDispatcher, useEnvironmentVariable, useFeatureFlag (8) Implementing error boundaries in modular applications (9) Questions about modular architecture patterns in React applications --- # Squide Framework Squide is a React modular application shell. Use only documented APIs. ## Core Concepts ### Runtime The `FireflyRuntime` instance is the backbone of a Squide application. Never instantiate directly - use `initializeFirefly()`. ### Modular Registration Modules register routes, navigation items, and MSW handlers via a registration function. Each module contributes its own configuration, assembled by the host at bootstrapping. ### Public vs Protected Routes - Routes default to `protected` (rendered under `ProtectedRoutes` placeholder) - Use `registerPublicRoute()` for public routes (rendered under `PublicRoutes` placeholder) - Public routes only fetch public global data; protected routes fetch both public and protected data ### Deferred Registrations Navigation items dependent on remote data or feature flags use two-phase registration: 1. First phase: Register static routes and navigation items 2. Second phase: Return a function from registration to defer navigation items ## Quick Reference ### Host Application Setup ```tsx // host/src/index.tsx import { createRoot } from "react-dom/client"; import { FireflyProvider, initializeFirefly } from "@squide/firefly"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { App } from "./App.tsx"; import { registerHost } from "./register.tsx"; const runtime = initializeFirefly({ localModules: [registerHost] }); const queryClient = new QueryClient(); const root = createRoot(document.getElementById("root")!); root.render( ); ``` ```tsx // host/src/App.tsx import { AppRouter, useIsBootstrapping } from "@squide/firefly"; import { createBrowserRouter, Outlet } from "react-router"; import { RouterProvider } from "react-router/dom"; function BootstrappingRoute() { if (useIsBootstrapping()) { return
Loading...
; } return ; } export function App() { return ( {({ rootRoute, registeredRoutes, routerProviderProps }) => ( , children: registeredRoutes }] }])} {...routerProviderProps} /> )} ); } ``` ```tsx // host/src/register.tsx import { PublicRoutes, ProtectedRoutes, type ModuleRegisterFunction, type FireflyRuntime } from "@squide/firefly"; import { RootLayout } from "./RootLayout.tsx"; export const registerHost: ModuleRegisterFunction = runtime => { runtime.registerRoute({ element: , children: [PublicRoutes, ProtectedRoutes] }, { hoist: true }); runtime.registerRoute({ index: true, element: }); runtime.registerPublicRoute({ path: "*", element: }); }; ``` ### Local Module Setup ```tsx // local-module/src/register.tsx import type { ModuleRegisterFunction, FireflyRuntime } from "@squide/firefly"; import { Page } from "./Page.tsx"; export const register: ModuleRegisterFunction = runtime => { runtime.registerRoute({ path: "/page", element: }); runtime.registerNavigationItem({ $id: "page", $label: "Page", to: "/page" }); }; ``` ### Navigation Rendering ```tsx import { Link, Outlet } from "react-router"; import { useNavigationItems, useRenderedNavigationItems, isNavigationLink, type RenderItemFunction, type RenderSectionFunction } from "@squide/firefly"; const renderItem: RenderItemFunction = (item, key) => { if (!isNavigationLink(item)) return null; const { label, linkProps, additionalProps } = item; return (
  • {label}
  • ); }; const renderSection: RenderSectionFunction = (elements, key) => (
      {elements}
    ); export function RootLayout() { const navigationItems = useNavigationItems(); const navigationElements = useRenderedNavigationItems(navigationItems, renderItem, renderSection); return ( <> ); } ``` ### Global Data Fetching ```tsx // Protected data import { useProtectedDataQueries, useIsBootstrapping, AppRouter } from "@squide/firefly"; function BootstrappingRoute() { const [session] = useProtectedDataQueries([{ queryKey: ["/api/session"], queryFn: async () => { const response = await fetch("/api/session"); if (!response.ok) throw new ApiError(response.status); return response.json(); } }], error => isApiError(error) && error.status === 401); if (useIsBootstrapping()) return
    Loading...
    ; return ( ); } // In App component, set waitForProtectedData ... ``` ```tsx // Public data const [data] = usePublicDataQueries([{ queryKey: [...], queryFn: ... }]); ... ``` ### Deferred Navigation Items ```tsx export const register: ModuleRegisterFunction = runtime => { // Always register routes runtime.registerRoute({ path: "/feature", element: }); // Return function for deferred navigation items return (deferredRuntime, { userData }) => { if (userData.isAdmin && deferredRuntime.getFeatureFlag("enable-feature")) { deferredRuntime.registerNavigationItem({ $id: "feature", $label: "Feature", to: "/feature" }); } }; }; ``` ```tsx // Execute deferred registrations in BootstrappingRoute const data = useMemo(() => ({ userData }), [userData]); useDeferredRegistrations(data); ``` ### MSW Request Handlers ```tsx export const register: ModuleRegisterFunction = async runtime => { if (runtime.isMswEnabled) { const requestHandlers = (await import("../mocks/handlers.ts")).requestHandlers; runtime.registerRequestHandlers(requestHandlers); } }; ``` ### Event Bus ```tsx // Listen import { useEventBusListener } from "@squide/firefly"; const handleEvent = useCallback((data, context) => { /* ... */ }, []); useEventBusListener("event-name", handleEvent); // Dispatch import { useEventBusDispatcher } from "@squide/firefly"; const dispatch = useEventBusDispatcher(); dispatch("event-name", payload); ``` ### Environment Variables ```tsx // Register at initialization const runtime = initializeFirefly({ environmentVariables: { apiBaseUrl: "https://api.example.com" } }); // Or register in module runtime.registerEnvironmentVariable("key", "value"); // Use import { useEnvironmentVariable } from "@squide/firefly"; const apiUrl = useEnvironmentVariable("apiBaseUrl"); ``` ### Feature Flags ```tsx // Initialize with LaunchDarkly import { initialize as initializeLaunchDarkly } from "launchdarkly-js-client-sdk"; const ldClient = initializeLaunchDarkly("client-id", { kind: "user", anonymous: true }, { streaming: true }); await ldClient.waitForInitialization(5); const runtime = initializeFirefly({ launchDarklyClient: ldClient }); // Use import { useFeatureFlag } from "@squide/firefly"; const isEnabled = useFeatureFlag("feature-key", defaultValue); ``` ### Logging ```tsx import { useLogger } from "@squide/firefly"; const logger = useLogger(); logger.debug("Message"); ``` ### Error Boundaries ```tsx // Root error boundary (wraps everything) runtime.registerRoute({ errorElement: , children: [{ element: , children: [PublicRoutes, ProtectedRoutes] }] }, { hoist: true }); // Module error boundary (isolates module failures) runtime.registerRoute({ element: , children: [{ errorElement: , children: [PublicRoutes, ProtectedRoutes] }] }, { hoist: true }); ``` ## API Quick Reference ### initializeFirefly Options - `mode`: `"development"` | `"production"` - `localModules`: Array of registration functions - `context`: Object passed to registration functions - `useMsw`: Enable MSW support - `startMsw`: Function to start MSW - `environmentVariables`: Initial environment variables - `honeycombInstrumentationClient`: For tracing - `launchDarklyClient`: For feature flags - `loggers`: Array of logger instances - `plugins`: Array of plugin factory functions - `onError`: Error handler for bootstrapping errors ### Route Registration Options - `hoist`: Register at router root (bypasses layouts/auth) - `parentPath`: Nest under route with matching `path` - `parentId`: Nest under route with matching `$id` ### Route Properties - `$id`: Identifier for nesting - `$visibility`: `"public"` | `"protected"` (default) ### Navigation Item Properties - `$id`: Unique identifier (recommended for stable keys) - `$label`: Text or ReactNode - `$priority`: Sorting priority (higher = first) - `$canRender`: Conditional render function - `$additionalProps`: Custom props for renderer - `to`: Route path (supports dynamic segments like `/user/:id`) - `style`: Inline styles for the navigation item - `target`: Link target (e.g., `"_blank"` to open in new tab) ### Navigation Registration Options - `menuId`: Target a specific menu (default: `"root"`) - `sectionId`: Nest under section with matching `$id` ### AppRouter Props - `waitForPublicData`: Delay until public data ready - `waitForProtectedData`: Delay until protected data ready ### Hooks - `useNavigationItems(options?)`: Get navigation items - `useRenderedNavigationItems(items, renderItem, renderSection)`: Render nav items - `useIsBootstrapping()`: Check if bootstrapping - `usePublicDataQueries(queries)`: Fetch public global data - `usePublicDataHandler(handler)`: Execute handler when modules are ready - `useProtectedDataQueries(queries, isUnauthorizedError)`: Fetch protected data - `useProtectedDataHandler(handler)`: Execute handler when modules ready and route is protected - `useDeferredRegistrations(data?, options?)`: Execute deferred registrations (options: `{ onError? }`) - `useEventBusListener(event, handler, options?)`: Listen to events - `useEventBusDispatcher()`: Get dispatch function - `useLogger()`: Get logger instance - `useEnvironmentVariable(key)`: Get env variable - `useEnvironmentVariables()`: Get all env variables - `useFeatureFlag(key, defaultValue)`: Get feature flag - `useFeatureFlags()`: Get all feature flags - `useLaunchDarklyClient()`: Get LaunchDarkly client instance - `usePlugin(name)`: Get plugin instance - `useRuntime()`: Get runtime instance - `useRuntimeMode()`: Get runtime mode - `useRoutes()`: Get registered routes - `useIsRouteProtected(route)`: Check if a route is protected - `useRouteMatch(locationArg, options?)`: Match route against location ### Helper Functions - `isNavigationLink(item)`: Type guard for navigation links - `isGlobalDataQueriesError(error)`: Type guard for query errors - `resolveRouteSegments(path, params)`: Resolve dynamic segments - `getFeatureFlag(client, key, defaultValue)`: Get flag in non-React code - `mergeDeferredRegistrations(candidates)`: Merge multiple deferred registration functions For detailed API documentation, see the references folder.