From c86d7e4b96bc12f2bafe3547b2aa3a40f2ccbba3 Mon Sep 17 00:00:00 2001 From: Retype GitHub Action Date: Mon, 18 Nov 2024 18:48:39 +0000 Subject: [PATCH] Refreshes Retype-generated documentation. Process triggered by patricklafrance. --- 404.html | 8 +- about/index.html | 8 +- getting-started/create-host/index.html | 10 +- .../create-local-module/index.html | 10 +- .../create-remote-module/index.html | 10 +- getting-started/deploy/index.html | 10 +- getting-started/index.html | 8 +- getting-started/learn-the-api/index.html | 10 +- guides/add-a-public-route/index.html | 10 +- guides/add-a-shared-dependency/index.html | 10 +- guides/add-authentication/index.html | 10 +- .../develop-a-module-in-isolation/index.html | 10 +- guides/fetch-global-data/index.html | 10 +- guides/fetch-page-data/index.html | 10 +- guides/implement-a-custom-logger/index.html | 10 +- guides/index.html | 8 +- guides/isolate-module-failures/index.html | 10 +- guides/manage-shared-state/index.html | 8 +- guides/override-a-react-context/index.html | 10 +- guides/override-the-host-layout/index.html | 10 +- guides/setup-honeycomb/index.html | 14 +- guides/setup-i18next/index.html | 10 +- guides/setup-msw/index.html | 10 +- guides/use-environment-variables/index.html | 10 +- guides/use-feature-flags/index.html | 10 +- guides/use-modular-tabs/index.html | 10 +- index.html | 8 +- .../environmentvariablesplugin/index.html | 10 +- .../getenvironmentvariablesplugin/index.html | 10 +- .../useenvironmentvariable/index.html | 10 +- .../useenvironmentvariables/index.html | 10 +- .../localstoragesessionmanager/index.html | 10 +- .../readonlysessionlocalstorage/index.html | 10 +- .../index.html | 407 +++++++++--------- .../setglobalspanattributes/index.html | 27 +- reference/i18next/geti18nextplugin/index.html | 10 +- .../i18nextnavigationitemlabel/index.html | 10 +- reference/i18next/i18nextplugin/index.html | 10 +- .../i18next/usechangelanguage/index.html | 10 +- .../i18next/usecurrentlanguage/index.html | 10 +- .../i18next/usei18nextinstance/index.html | 10 +- reference/index.html | 8 +- reference/logging/consolelogger/index.html | 10 +- reference/logging/logger/index.html | 10 +- reference/messaging/eventbus/index.html | 10 +- .../useeventbusdispatcher/index.html | 10 +- .../messaging/useeventbuslistener/index.html | 10 +- reference/msw/setmswasready/index.html | 10 +- reference/packages/index.html | 8 +- reference/plugins/plugin/index.html | 10 +- reference/registration/bootstrap/index.html | 10 +- .../mergedeferredregistrations/index.html | 10 +- .../registerlocalmodules/index.html | 10 +- .../registerremotemodules/index.html | 10 +- .../usedeferredregistrations/index.html | 10 +- reference/routing/approuter/index.html | 10 +- reference/routing/isnavigationlink/index.html | 10 +- reference/routing/protectedroutes/index.html | 10 +- reference/routing/publicroutes/index.html | 10 +- .../routing/resolveroutesegments/index.html | 10 +- .../routing/useisbootstrapping/index.html | 10 +- .../routing/useisrouteprotected/index.html | 10 +- .../userenderednavigationitems/index.html | 10 +- reference/routing/useroutematch/index.html | 10 +- reference/runtime/runtime-class/index.html | 10 +- reference/runtime/runtimecontext/index.html | 10 +- reference/runtime/uselogger/index.html | 10 +- reference/runtime/useloggers/index.html | 10 +- .../runtime/usenavigationitems/index.html | 10 +- reference/runtime/useplugin/index.html | 10 +- reference/runtime/useroutes/index.html | 10 +- reference/runtime/useruntime/index.html | 10 +- reference/runtime/useruntimemode/index.html | 10 +- .../isglobaldataquerieserror/index.html | 10 +- .../useprotecteddataqueries/index.html | 10 +- .../usepublicdataqueries/index.html | 10 +- .../webpack/definebuildhostconfig/index.html | 10 +- .../definebuildremotemoduleconfig/index.html | 10 +- .../webpack/definedevhostconfig/index.html | 10 +- .../definedevremotemoduleconfig/index.html | 10 +- resources/js/config.js | 2 +- resources/js/search.json | 2 +- samples/index.html | 8 +- sitemap.xml.gz | Bin 1273 -> 1273 bytes troubleshooting/index.html | 10 +- upgrading/index.html | 8 +- upgrading/migrate-to-firefly-v9.0/index.html | 10 +- upgrading/migrate-to-firefly-v9.3/index.html | 10 +- 88 files changed, 635 insertions(+), 617 deletions(-) diff --git a/404.html b/404.html index 13988a13a..b4fdcf79b 100644 --- a/404.html +++ b/404.html @@ -4,7 +4,7 @@ - + @@ -29,11 +29,11 @@ - + - + - + diff --git a/about/index.html b/about/index.html index 5250455a5..8ba3b2f61 100644 --- a/about/index.html +++ b/about/index.html @@ -4,7 +4,7 @@ - + @@ -32,11 +32,11 @@ - + - + - + diff --git a/getting-started/create-host/index.html b/getting-started/create-host/index.html index c0aea22ec..de2fdcdbc 100644 --- a/getting-started/create-host/index.html +++ b/getting-started/create-host/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/getting-started/create-local-module/index.html b/getting-started/create-local-module/index.html index 1bae494ca..b5eabb5dc 100644 --- a/getting-started/create-local-module/index.html +++ b/getting-started/create-local-module/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/getting-started/create-remote-module/index.html b/getting-started/create-remote-module/index.html index 476d4b32a..df00889e4 100644 --- a/getting-started/create-remote-module/index.html +++ b/getting-started/create-remote-module/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/getting-started/deploy/index.html b/getting-started/deploy/index.html index 35dbe8dc6..3a86c6f85 100644 --- a/getting-started/deploy/index.html +++ b/getting-started/deploy/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/getting-started/index.html b/getting-started/index.html index feb42da19..1989f92c5 100644 --- a/getting-started/index.html +++ b/getting-started/index.html @@ -4,7 +4,7 @@ - + @@ -32,11 +32,11 @@ - + - + - + diff --git a/getting-started/learn-the-api/index.html b/getting-started/learn-the-api/index.html index 414c29f88..38a8d1adb 100644 --- a/getting-started/learn-the-api/index.html +++ b/getting-started/learn-the-api/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/add-a-public-route/index.html b/guides/add-a-public-route/index.html index 6f390067e..9bc813da3 100644 --- a/guides/add-a-public-route/index.html +++ b/guides/add-a-public-route/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/add-a-shared-dependency/index.html b/guides/add-a-shared-dependency/index.html index 028ca4f82..cfb837f1d 100644 --- a/guides/add-a-shared-dependency/index.html +++ b/guides/add-a-shared-dependency/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/add-authentication/index.html b/guides/add-authentication/index.html index 5ac3ab6b5..78b81aa4a 100644 --- a/guides/add-authentication/index.html +++ b/guides/add-authentication/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/develop-a-module-in-isolation/index.html b/guides/develop-a-module-in-isolation/index.html index 7bd87f565..7220f1fa2 100644 --- a/guides/develop-a-module-in-isolation/index.html +++ b/guides/develop-a-module-in-isolation/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/fetch-global-data/index.html b/guides/fetch-global-data/index.html index bac94b574..87cf26f05 100644 --- a/guides/fetch-global-data/index.html +++ b/guides/fetch-global-data/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/fetch-page-data/index.html b/guides/fetch-page-data/index.html index 3cda00c2c..af8f04527 100644 --- a/guides/fetch-page-data/index.html +++ b/guides/fetch-page-data/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/implement-a-custom-logger/index.html b/guides/implement-a-custom-logger/index.html index f21f16050..b88c6880c 100644 --- a/guides/implement-a-custom-logger/index.html +++ b/guides/implement-a-custom-logger/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/index.html b/guides/index.html index c4837b01f..7d80b2f61 100644 --- a/guides/index.html +++ b/guides/index.html @@ -4,7 +4,7 @@ - + @@ -32,11 +32,11 @@ - + - + - + diff --git a/guides/isolate-module-failures/index.html b/guides/isolate-module-failures/index.html index a3762b83d..4c95c6c82 100644 --- a/guides/isolate-module-failures/index.html +++ b/guides/isolate-module-failures/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/manage-shared-state/index.html b/guides/manage-shared-state/index.html index ee9d65e40..f131b4675 100644 --- a/guides/manage-shared-state/index.html +++ b/guides/manage-shared-state/index.html @@ -4,7 +4,7 @@ - + @@ -32,11 +32,11 @@ - + - + - + diff --git a/guides/override-a-react-context/index.html b/guides/override-a-react-context/index.html index 70f88bacd..516b20e5f 100644 --- a/guides/override-a-react-context/index.html +++ b/guides/override-a-react-context/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/override-the-host-layout/index.html b/guides/override-the-host-layout/index.html index f3067cd63..122ffb1d7 100644 --- a/guides/override-the-host-layout/index.html +++ b/guides/override-the-host-layout/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/setup-honeycomb/index.html b/guides/setup-honeycomb/index.html index c5e6be4cb..3b67c44e4 100644 --- a/guides/setup-honeycomb/index.html +++ b/guides/setup-honeycomb/index.html @@ -4,7 +4,7 @@ - + @@ -34,12 +34,12 @@ - + - + - - + + @@ -398,8 +398,8 @@

}); // Register Honeycomb instrumentation. -registerHoneycombInstrumentation(runtime, "endpoints-sample", [/.+/g,], { - endpoint: "https://my-collector" +registerHoneycombInstrumentation(runtime, "squide-sample", [/.+/g,], { + endpoint: "https://squide-collector" }); const root = createRoot(document.getElementById("root")!); diff --git a/guides/setup-i18next/index.html b/guides/setup-i18next/index.html index 1ed9fe34d..9980b3e83 100644 --- a/guides/setup-i18next/index.html +++ b/guides/setup-i18next/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/setup-msw/index.html b/guides/setup-msw/index.html index c805fa4d2..dc0d9dda6 100644 --- a/guides/setup-msw/index.html +++ b/guides/setup-msw/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/use-environment-variables/index.html b/guides/use-environment-variables/index.html index 60154d8af..454ffc8e3 100644 --- a/guides/use-environment-variables/index.html +++ b/guides/use-environment-variables/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/use-feature-flags/index.html b/guides/use-feature-flags/index.html index 0b0190bb0..d56b5f4b0 100644 --- a/guides/use-feature-flags/index.html +++ b/guides/use-feature-flags/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/guides/use-modular-tabs/index.html b/guides/use-modular-tabs/index.html index d564696e7..f27c6f684 100644 --- a/guides/use-modular-tabs/index.html +++ b/guides/use-modular-tabs/index.html @@ -4,7 +4,7 @@ - + @@ -34,12 +34,12 @@ - + - + - - + + diff --git a/index.html b/index.html index 7c71131f3..0f601b8b2 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - + @@ -30,11 +30,11 @@ - + - + - + diff --git a/reference/env-vars/environmentvariablesplugin/index.html b/reference/env-vars/environmentvariablesplugin/index.html index 1721c19c9..76ef5b898 100644 --- a/reference/env-vars/environmentvariablesplugin/index.html +++ b/reference/env-vars/environmentvariablesplugin/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/env-vars/getenvironmentvariablesplugin/index.html b/reference/env-vars/getenvironmentvariablesplugin/index.html index 4d2fe2a4b..a4b004c17 100644 --- a/reference/env-vars/getenvironmentvariablesplugin/index.html +++ b/reference/env-vars/getenvironmentvariablesplugin/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/env-vars/useenvironmentvariable/index.html b/reference/env-vars/useenvironmentvariable/index.html index 16cc124f9..07c5ab64c 100644 --- a/reference/env-vars/useenvironmentvariable/index.html +++ b/reference/env-vars/useenvironmentvariable/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/env-vars/useenvironmentvariables/index.html b/reference/env-vars/useenvironmentvariables/index.html index a03d04c8b..91ccd3f5b 100644 --- a/reference/env-vars/useenvironmentvariables/index.html +++ b/reference/env-vars/useenvironmentvariables/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/fakes/localstoragesessionmanager/index.html b/reference/fakes/localstoragesessionmanager/index.html index c3b503f52..f3c24cb72 100644 --- a/reference/fakes/localstoragesessionmanager/index.html +++ b/reference/fakes/localstoragesessionmanager/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/fakes/readonlysessionlocalstorage/index.html b/reference/fakes/readonlysessionlocalstorage/index.html index 35edfa1f4..bed3edc1d 100644 --- a/reference/fakes/readonlysessionlocalstorage/index.html +++ b/reference/fakes/readonlysessionlocalstorage/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/honeycomb/registerhoneycombinstrumentation/index.html b/reference/honeycomb/registerhoneycombinstrumentation/index.html index bb87e172e..538b7365a 100644 --- a/reference/honeycomb/registerhoneycombinstrumentation/index.html +++ b/reference/honeycomb/registerhoneycombinstrumentation/index.html @@ -4,7 +4,7 @@ - + @@ -12,7 +12,7 @@ registerHoneycombInstrumentation - + @@ -21,23 +21,23 @@ - + - + - + - + - - + + @@ -313,7 +313,24 @@

registerHoneycombInstrumentation

-

Initializes an instance of Honeycomb Web SDK and registers custom instrumentation to monitor the performance of a Squide application.

+

Initialize an instance of Honeycomb Web SDK and registers custom instrumentation to monitor the performance of a Squide application.

+
+
+ +

# @@ -335,15 +352,7 @@

  • apiServiceUrls: A RegExp or string that matches the URLs of the application's backend services. If unsure, use the temporary regex /.+/g, to match all URLs.
  • options: An optional object literal of options:
  • @@ -355,18 +364,6 @@

    Nothing

    - -

    - # - Default instrumentation -

    -
    -

    The registerHoneycombInstrumentation function registers the following OpenTelemetry instrumentations by default:

    - -

    For more details, refer to the registerHoneycombInstrumentation.ts file on GitHub.

    # @@ -380,10 +377,13 @@

    -
    import { registerHoneycombInstrumentation } from "@squide/firefly-honeycomb";
    +
    import { FireflyRuntime } from "@squide/firefly";
    +import { registerHoneycombInstrumentation } from "@squide/firefly-honeycomb";
    +
    +const runtime = new FireflyRuntime();
     
    -registerHoneycombInstrumentation(runtime, "endpoints-sample", [/.+/g,], {
    -    endpoint: "https://my-collector"
    +registerHoneycombInstrumentation(runtime, "squide-sample", [/.+/g,], {
    +    endpoint: "https://squide-collector"
     });
    @@ -411,7 +411,7 @@

    import { registerHoneycombInstrumentation } from "@squide/firefly-honeycomb";
     
    -registerHoneycombInstrumentation(runtime, "endpoints-sample", [/.+/g,], {
    +registerHoneycombInstrumentation(runtime, "squide-sample", [/.+/g,], {
         apiKey: "xyz123"
     });
    @@ -442,40 +442,73 @@

    import { registerHoneycombInstrumentation } from "@squide/firefly-honeycomb";
     
     registerHoneycombInstrumentation(
    -    runtime, "endpoints-sample", 
    +    runtime, "squide-sample", 
         [/https:\/\/workleap.com\/api\.*/], 
    -    { endpoint: "https://my-collector" }
    +    { endpoint: "https://squide-collector" }
     );
    - -

    - # - Register custom instrumentation -

    -
    -
    -
    import { registerHoneycombInstrumentation } from "@squide/firefly-honeycomb";
    -import { LongTaskInstrumentation } from "@opentelemetry/instrumentation-long-task";
    +
    +
     
                                     
                                     
    diff --git a/reference/honeycomb/setglobalspanattributes/index.html b/reference/honeycomb/setglobalspanattributes/index.html
    index 1d67e8da0..5fb9b02c0 100644
    --- a/reference/honeycomb/setglobalspanattributes/index.html
    +++ b/reference/honeycomb/setglobalspanattributes/index.html
    @@ -4,7 +4,7 @@
         
         
         
    -    
    +    
     
         
         
    @@ -32,12 +32,12 @@
         
     
         
    -    
    +    
     
    -    
    +    
         
    -    
    -    
    +    
    +    
     
         
     
    @@ -314,6 +314,23 @@ 

    Set global attributes to be included in all Honeycomb Web traces.

    +
    +
    + +

    # diff --git a/reference/i18next/geti18nextplugin/index.html b/reference/i18next/geti18nextplugin/index.html index 26042640c..0af42a981 100644 --- a/reference/i18next/geti18nextplugin/index.html +++ b/reference/i18next/geti18nextplugin/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/i18next/i18nextnavigationitemlabel/index.html b/reference/i18next/i18nextnavigationitemlabel/index.html index 7a13623b5..574d4ef48 100644 --- a/reference/i18next/i18nextnavigationitemlabel/index.html +++ b/reference/i18next/i18nextnavigationitemlabel/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/i18next/i18nextplugin/index.html b/reference/i18next/i18nextplugin/index.html index a34aaf323..36fb66880 100644 --- a/reference/i18next/i18nextplugin/index.html +++ b/reference/i18next/i18nextplugin/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/i18next/usechangelanguage/index.html b/reference/i18next/usechangelanguage/index.html index 88812cdc0..9f7dcfbaa 100644 --- a/reference/i18next/usechangelanguage/index.html +++ b/reference/i18next/usechangelanguage/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/i18next/usecurrentlanguage/index.html b/reference/i18next/usecurrentlanguage/index.html index fdfd3a193..cc968bdfe 100644 --- a/reference/i18next/usecurrentlanguage/index.html +++ b/reference/i18next/usecurrentlanguage/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/i18next/usei18nextinstance/index.html b/reference/i18next/usei18nextinstance/index.html index 0bd5f70ac..f7494e625 100644 --- a/reference/i18next/usei18nextinstance/index.html +++ b/reference/i18next/usei18nextinstance/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/index.html b/reference/index.html index ff4c484c4..b767629bb 100644 --- a/reference/index.html +++ b/reference/index.html @@ -4,7 +4,7 @@ - + @@ -32,11 +32,11 @@ - + - + - + diff --git a/reference/logging/consolelogger/index.html b/reference/logging/consolelogger/index.html index f5d5eb821..cf3f86796 100644 --- a/reference/logging/consolelogger/index.html +++ b/reference/logging/consolelogger/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/logging/logger/index.html b/reference/logging/logger/index.html index ba255b5d7..e55938ae6 100644 --- a/reference/logging/logger/index.html +++ b/reference/logging/logger/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/messaging/eventbus/index.html b/reference/messaging/eventbus/index.html index b2929d4ef..22727b10a 100644 --- a/reference/messaging/eventbus/index.html +++ b/reference/messaging/eventbus/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/messaging/useeventbusdispatcher/index.html b/reference/messaging/useeventbusdispatcher/index.html index d25f43ee0..c8b0464be 100644 --- a/reference/messaging/useeventbusdispatcher/index.html +++ b/reference/messaging/useeventbusdispatcher/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/messaging/useeventbuslistener/index.html b/reference/messaging/useeventbuslistener/index.html index f87531269..3634179da 100644 --- a/reference/messaging/useeventbuslistener/index.html +++ b/reference/messaging/useeventbuslistener/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/msw/setmswasready/index.html b/reference/msw/setmswasready/index.html index 73bc4bdf8..48e27b720 100644 --- a/reference/msw/setmswasready/index.html +++ b/reference/msw/setmswasready/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/packages/index.html b/reference/packages/index.html index 494c07e85..dffe8fc46 100644 --- a/reference/packages/index.html +++ b/reference/packages/index.html @@ -4,7 +4,7 @@ - + @@ -34,11 +34,11 @@ - + - + - + diff --git a/reference/plugins/plugin/index.html b/reference/plugins/plugin/index.html index 9e0eca89c..e75de058c 100644 --- a/reference/plugins/plugin/index.html +++ b/reference/plugins/plugin/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/registration/bootstrap/index.html b/reference/registration/bootstrap/index.html index 90bc63ad8..63c5f75f8 100644 --- a/reference/registration/bootstrap/index.html +++ b/reference/registration/bootstrap/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/registration/mergedeferredregistrations/index.html b/reference/registration/mergedeferredregistrations/index.html index 40257106b..3d7a2642c 100644 --- a/reference/registration/mergedeferredregistrations/index.html +++ b/reference/registration/mergedeferredregistrations/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/registration/registerlocalmodules/index.html b/reference/registration/registerlocalmodules/index.html index 81276ca04..6b2c77a19 100644 --- a/reference/registration/registerlocalmodules/index.html +++ b/reference/registration/registerlocalmodules/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/registration/registerremotemodules/index.html b/reference/registration/registerremotemodules/index.html index f3d1f25e0..269ce8b23 100644 --- a/reference/registration/registerremotemodules/index.html +++ b/reference/registration/registerremotemodules/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/registration/usedeferredregistrations/index.html b/reference/registration/usedeferredregistrations/index.html index d61dd3044..69550362d 100644 --- a/reference/registration/usedeferredregistrations/index.html +++ b/reference/registration/usedeferredregistrations/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/routing/approuter/index.html b/reference/routing/approuter/index.html index 8f72053f7..82b9e18e5 100644 --- a/reference/routing/approuter/index.html +++ b/reference/routing/approuter/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/routing/isnavigationlink/index.html b/reference/routing/isnavigationlink/index.html index 484cc393f..414e3ae15 100644 --- a/reference/routing/isnavigationlink/index.html +++ b/reference/routing/isnavigationlink/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/routing/protectedroutes/index.html b/reference/routing/protectedroutes/index.html index ef32aa2e1..607043f57 100644 --- a/reference/routing/protectedroutes/index.html +++ b/reference/routing/protectedroutes/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/routing/publicroutes/index.html b/reference/routing/publicroutes/index.html index 9fcf63022..3b4c68901 100644 --- a/reference/routing/publicroutes/index.html +++ b/reference/routing/publicroutes/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/routing/resolveroutesegments/index.html b/reference/routing/resolveroutesegments/index.html index 93544360e..4e11313d7 100644 --- a/reference/routing/resolveroutesegments/index.html +++ b/reference/routing/resolveroutesegments/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/routing/useisbootstrapping/index.html b/reference/routing/useisbootstrapping/index.html index c09762bd6..1985554c6 100644 --- a/reference/routing/useisbootstrapping/index.html +++ b/reference/routing/useisbootstrapping/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/routing/useisrouteprotected/index.html b/reference/routing/useisrouteprotected/index.html index f3548f4f8..ad7a1ecfa 100644 --- a/reference/routing/useisrouteprotected/index.html +++ b/reference/routing/useisrouteprotected/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/routing/userenderednavigationitems/index.html b/reference/routing/userenderednavigationitems/index.html index a9816b5f6..e828e83c1 100644 --- a/reference/routing/userenderednavigationitems/index.html +++ b/reference/routing/userenderednavigationitems/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/routing/useroutematch/index.html b/reference/routing/useroutematch/index.html index 5b251e6f9..285f51df6 100644 --- a/reference/routing/useroutematch/index.html +++ b/reference/routing/useroutematch/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/runtime/runtime-class/index.html b/reference/runtime/runtime-class/index.html index 72f8cff75..d9fd74510 100644 --- a/reference/runtime/runtime-class/index.html +++ b/reference/runtime/runtime-class/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/runtime/runtimecontext/index.html b/reference/runtime/runtimecontext/index.html index 33f0a2bff..bc11a2088 100644 --- a/reference/runtime/runtimecontext/index.html +++ b/reference/runtime/runtimecontext/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/runtime/uselogger/index.html b/reference/runtime/uselogger/index.html index 39135aea8..e6c96e593 100644 --- a/reference/runtime/uselogger/index.html +++ b/reference/runtime/uselogger/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/runtime/useloggers/index.html b/reference/runtime/useloggers/index.html index 630615afb..809b4f8d3 100644 --- a/reference/runtime/useloggers/index.html +++ b/reference/runtime/useloggers/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/runtime/usenavigationitems/index.html b/reference/runtime/usenavigationitems/index.html index 3861f5c39..69d728cb6 100644 --- a/reference/runtime/usenavigationitems/index.html +++ b/reference/runtime/usenavigationitems/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/runtime/useplugin/index.html b/reference/runtime/useplugin/index.html index a1932470b..c78fe5f68 100644 --- a/reference/runtime/useplugin/index.html +++ b/reference/runtime/useplugin/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/runtime/useroutes/index.html b/reference/runtime/useroutes/index.html index eea8ee804..1ad538496 100644 --- a/reference/runtime/useroutes/index.html +++ b/reference/runtime/useroutes/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/runtime/useruntime/index.html b/reference/runtime/useruntime/index.html index 890ea2573..17bf12f21 100644 --- a/reference/runtime/useruntime/index.html +++ b/reference/runtime/useruntime/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/runtime/useruntimemode/index.html b/reference/runtime/useruntimemode/index.html index 63036a4f7..644835f66 100644 --- a/reference/runtime/useruntimemode/index.html +++ b/reference/runtime/useruntimemode/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/tanstack-query/isglobaldataquerieserror/index.html b/reference/tanstack-query/isglobaldataquerieserror/index.html index d80cdddbe..eb91e0c66 100644 --- a/reference/tanstack-query/isglobaldataquerieserror/index.html +++ b/reference/tanstack-query/isglobaldataquerieserror/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/tanstack-query/useprotecteddataqueries/index.html b/reference/tanstack-query/useprotecteddataqueries/index.html index 3ba03f96e..ea3f44a99 100644 --- a/reference/tanstack-query/useprotecteddataqueries/index.html +++ b/reference/tanstack-query/useprotecteddataqueries/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/tanstack-query/usepublicdataqueries/index.html b/reference/tanstack-query/usepublicdataqueries/index.html index 34926f27e..8c55d7308 100644 --- a/reference/tanstack-query/usepublicdataqueries/index.html +++ b/reference/tanstack-query/usepublicdataqueries/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/webpack/definebuildhostconfig/index.html b/reference/webpack/definebuildhostconfig/index.html index 304abe0f7..6de41a449 100644 --- a/reference/webpack/definebuildhostconfig/index.html +++ b/reference/webpack/definebuildhostconfig/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/webpack/definebuildremotemoduleconfig/index.html b/reference/webpack/definebuildremotemoduleconfig/index.html index 0888e4d54..0142231c7 100644 --- a/reference/webpack/definebuildremotemoduleconfig/index.html +++ b/reference/webpack/definebuildremotemoduleconfig/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/webpack/definedevhostconfig/index.html b/reference/webpack/definedevhostconfig/index.html index 5dbbef1e8..093f0a37b 100644 --- a/reference/webpack/definedevhostconfig/index.html +++ b/reference/webpack/definedevhostconfig/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/reference/webpack/definedevremotemoduleconfig/index.html b/reference/webpack/definedevremotemoduleconfig/index.html index 66b2b43e2..79b63ec49 100644 --- a/reference/webpack/definedevremotemoduleconfig/index.html +++ b/reference/webpack/definedevremotemoduleconfig/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/resources/js/config.js b/resources/js/config.js index e1950c9d5..4f68e5e11 100644 --- a/resources/js/config.js +++ b/resources/js/config.js @@ -1 +1 @@ -var __DOCS_CONFIG__ = {"id":"cvjgF1m89sykr87Xg7sCIPMraRLp417exX","key":"uybSqFGCGBHwfw0dDaA0ZhyeUwoiL1jwQn3jXQMfbgs.LSIBQVRnNY3wyNzLHriRlMaM7cP6jStoxtSIFNv/++qN5ngz1WNJ1QIunfTB/b+n1iedb/x6sIhsPMYczlUh3Q.300100","base":"/wl-squide/","host":"gsoft-inc.github.io","version":"1.0.0","useRelativePaths":true,"documentName":"index.html","appendDocumentName":false,"trailingSlash":true,"preloadSearch":false,"cacheBustingToken":"3.6.0.785208429613","cacheBustingStrategy":"query","sidebarFilterPlaceholder":"Filter","toolbarFilterPlaceholder":"Filter","showSidebarFilter":true,"filterNotFoundMsg":"No member names found containing the query \"{query}\"","maxHistoryItems":15,"homeIcon":"","access":[{"value":"public","label":"Public"},{"value":"protected","label":"Protected"}],"toolbarLinks":[{"id":"fields","label":"Fields"},{"id":"properties","label":"Properties"},{"id":"methods","label":"Methods"},{"id":"events","label":"Events"}],"sidebar":[{"n":"getting-started","l":"Getting started","o":true,"i":[{"n":"create-host","l":"Create an host app"},{"n":"create-remote-module","l":"Create a remote module"},{"n":"create-local-module","l":"Create a local module"},{"n":"learn-the-api","l":"Learn the API"},{"n":"deploy","l":"Deploy"}],"s":""},{"n":"guides","l":"Guides","o":true,"i":[{"n":"setup-msw","l":"Setup Mock Service Worker"},{"n":"fetch-global-data","l":"Fetch global data"},{"n":"fetch-page-data","l":"Fetch page data"},{"n":"manage-shared-state","l":"Manage shared state"},{"n":"isolate-module-failures","l":"Isolate module failures"},{"n":"add-authentication","l":"Add authentication"},{"n":"add-a-public-route","l":"Add a public route"},{"n":"override-the-host-layout","l":"Override the host layout"},{"n":"use-modular-tabs","l":"Use modular tabs"},{"n":"use-feature-flags","l":"Use feature flags"},{"n":"use-environment-variables","l":"Use environment variables"},{"n":"setup-i18next","l":"Setup i​18​next"},{"n":"setup-honeycomb","l":"Setup Honeycomb"},{"n":"develop-a-module-in-isolation","l":"Develop a module in isolation"},{"n":"override-a-react-context","l":"Override a React context"},{"n":"add-a-shared-dependency","l":"Add a shared dependency"},{"n":"implement-a-custom-logger","l":"Implement a custom logger"}],"s":""},{"n":"upgrading","l":"Updating","o":true,"i":[{"n":"migrate-to-firefly-v9.0","l":"Migrate to firefly v​9.​0"},{"n":"migrate-to-firefly-v9.3","l":"Migrate to firefly v​9.​3"}],"s":""},{"n":"reference","l":"Reference","o":true,"i":[{"n":"packages","l":"Packages"},{"n":"runtime","l":"Runtime","c":false,"i":[{"n":"runtime-class","l":"Firefly​Runtime class"},{"n":"runtimecontext","l":"Runtime​Context"},{"n":"useruntime","l":"use​Runtime"},{"n":"useruntimemode","l":"use​Runtime​Mode"},{"n":"useroutes","l":"use​Routes"},{"n":"usenavigationitems","l":"use​Navigation​Items"},{"n":"uselogger","l":"use​Logger"},{"n":"useloggers","l":"use​Loggers"},{"n":"useplugin","l":"use​Plugin"}]},{"n":"registration","l":"Registration","c":false,"i":[{"n":"bootstrap"},{"n":"registerlocalmodules","l":"register​Local​Modules"},{"n":"registerremotemodules","l":"register​Remote​Modules"},{"n":"usedeferredregistrations","l":"use​Deferred​Registrations"},{"n":"mergedeferredregistrations","l":"merge​Deferred​Registrations"}]},{"n":"routing","l":"Routing","c":false,"i":[{"n":"approuter","l":"App​Router"},{"n":"publicroutes","l":"Public​Routes"},{"n":"protectedroutes","l":"Protected​Routes"},{"n":"useisbootstrapping","l":"use​Is​Bootstrapping"},{"n":"userenderednavigationitems","l":"use​Rendered​Navigation​Items"},{"n":"useroutematch","l":"use​Route​Match"},{"n":"resolveroutesegments","l":"resolve​Route​Segments"},{"n":"useisrouteprotected","l":"use​Is​Route​Protected"},{"n":"isnavigationlink","l":"is​Navigation​Link"}]},{"n":"logging","l":"Logging","c":false,"i":[{"n":"consolelogger","l":"Console​Logger"},{"n":"logger","l":"Logger"}]},{"n":"messaging","l":"Messaging","c":false,"i":[{"n":"eventbus","l":"Event​Bus"},{"n":"useeventbusdispatcher","l":"use​Event​Bus​Dispatcher"},{"n":"useeventbuslistener","l":"use​Event​Bus​Listener"}]},{"n":"plugins","l":"Plugins","c":false,"i":[{"n":"plugin","l":"Plugin"}]},{"n":"webpack","c":false,"i":[{"n":"definedevhostconfig","l":"define​Dev​Host​Config"},{"n":"definedevremotemoduleconfig","l":"define​Dev​Remote​Module​Config"},{"n":"definebuildhostconfig","l":"define​Build​Host​Config"},{"n":"definebuildremotemoduleconfig","l":"define​Build​Remote​Module​Config"}]},{"n":"tanstack-query","l":"Tan​Stack Query","c":false,"i":[{"n":"usepublicdataqueries","l":"use​Public​Data​Queries"},{"n":"useprotecteddataqueries","l":"use​Protected​Data​Queries"},{"n":"isglobaldataquerieserror","l":"is​Global​Data​Queries​Error"}]},{"n":"msw","l":"Mock Service Worker","c":false,"i":[{"n":"setmswasready","l":"set​Msw​As​Ready"}]},{"n":"i18next","l":"i​18​next","c":false,"i":[{"n":"i18nextplugin","l":"i​18​next​Plugin"},{"n":"geti18nextplugin","l":"get​I​18​next​Plugin"},{"n":"usechangelanguage","l":"use​Change​Language"},{"n":"usecurrentlanguage","l":"use​Current​Language"},{"n":"usei18nextinstance","l":"use​I​18​next​Instance"},{"n":"i18nextnavigationitemlabel","l":"I​18​next​Navigation​Item​Label"}]},{"n":"honeycomb","l":"Honeycomb","c":false,"i":[{"n":"registerhoneycombinstrumentation","l":"register​Honeycomb​Instrumentation"},{"n":"setglobalspanattributes","l":"set​Global​Span​Attributes"}]},{"n":"env-vars","l":"Environment variables","c":false,"i":[{"n":"environmentvariablesplugin","l":"Environment​Variables​Plugin"},{"n":"getenvironmentvariablesplugin","l":"get​Environment​Variables​Plugin"},{"n":"useenvironmentvariable","l":"use​Environment​Variable"},{"n":"useenvironmentvariables","l":"use​Environment​Variables"}]},{"n":"fakes","l":"Fakes","c":false,"i":[{"n":"localstoragesessionmanager","l":"Local​Storage​Session​Manager"},{"n":"readonlysessionlocalstorage","l":"Readonly​Session​Local​Storage"}]}],"s":""},{"n":"troubleshooting","l":"Troubleshooting","s":""},{"n":"samples","l":"Samples","s":""},{"n":"about","l":"About","v":false}],"search":{"mode":0,"minChars":2,"maxResults":20,"placeholder":"Search","hotkeys":["k"],"noResultsFoundMsg":"Sorry, no results found.","recognizeLanguages":true,"languages":[0],"preload":false},"resources":{"History_Title_Label":"History","History_ClearLink_Label":"Clear","History_NoHistory_Label":"No history items","API_AccessFilter_Label":"Access","API_ParameterSection_Label":"PARAMETERS","API_SignatureSection_Label":"SIGNATURE","API_CopyHint_Label":"Copy","API_CopyNameHint_Label":"Copy name","API_CopyLinkHint_Label":"Copy link","API_CopiedAckHint_Label":"Copied!","API_MoreOverloads_Label":"more","API_MoreDropdownItems_Label":"More","API_OptionalParameter_Label":"optional","API_DefaultParameterValue_Label":"Default value","API_InheritedFilter_Label":"Inherited","Search_Input_Placeholder":"Search","Toc_Contents_Label":"Contents","Toc_RelatedClasses_Label":"Related Classes","History_JustNowTime_Label":"just now","History_AgoTime_Label":"ago","History_YearTime_Label":"y","History_MonthTime_Label":"mo","History_DayTime_Label":"d","History_HourTime_Label":"h","History_MinuteTime_Label":"m","History_SecondTime_Label":"s"}}; +var __DOCS_CONFIG__ = {"id":"PxrBb9Rc47FDOnZ41Blptdlx8pLL5GNkzM","key":"RhTT1kpokz28mmRVDomD0ciCjlylxfi0HWhBfgh97bA.ISEbmMtlq9J7oCLYJq/ZeXzhc98rESOjKPCSKfm5j3q9ckl6XLgMY0701xR70h+/b8LlevZSaFDZSD9mXTWW9g.300093","base":"/wl-squide/","host":"gsoft-inc.github.io","version":"1.0.0","useRelativePaths":true,"documentName":"index.html","appendDocumentName":false,"trailingSlash":true,"preloadSearch":false,"cacheBustingToken":"3.6.0.785270913724","cacheBustingStrategy":"query","sidebarFilterPlaceholder":"Filter","toolbarFilterPlaceholder":"Filter","showSidebarFilter":true,"filterNotFoundMsg":"No member names found containing the query \"{query}\"","maxHistoryItems":15,"homeIcon":"","access":[{"value":"public","label":"Public"},{"value":"protected","label":"Protected"}],"toolbarLinks":[{"id":"fields","label":"Fields"},{"id":"properties","label":"Properties"},{"id":"methods","label":"Methods"},{"id":"events","label":"Events"}],"sidebar":[{"n":"getting-started","l":"Getting started","o":true,"i":[{"n":"create-host","l":"Create an host app"},{"n":"create-remote-module","l":"Create a remote module"},{"n":"create-local-module","l":"Create a local module"},{"n":"learn-the-api","l":"Learn the API"},{"n":"deploy","l":"Deploy"}],"s":""},{"n":"guides","l":"Guides","o":true,"i":[{"n":"setup-msw","l":"Setup Mock Service Worker"},{"n":"fetch-global-data","l":"Fetch global data"},{"n":"fetch-page-data","l":"Fetch page data"},{"n":"manage-shared-state","l":"Manage shared state"},{"n":"isolate-module-failures","l":"Isolate module failures"},{"n":"add-authentication","l":"Add authentication"},{"n":"add-a-public-route","l":"Add a public route"},{"n":"override-the-host-layout","l":"Override the host layout"},{"n":"use-modular-tabs","l":"Use modular tabs"},{"n":"use-feature-flags","l":"Use feature flags"},{"n":"use-environment-variables","l":"Use environment variables"},{"n":"setup-i18next","l":"Setup i​18​next"},{"n":"setup-honeycomb","l":"Setup Honeycomb"},{"n":"develop-a-module-in-isolation","l":"Develop a module in isolation"},{"n":"override-a-react-context","l":"Override a React context"},{"n":"add-a-shared-dependency","l":"Add a shared dependency"},{"n":"implement-a-custom-logger","l":"Implement a custom logger"}],"s":""},{"n":"upgrading","l":"Updating","o":true,"i":[{"n":"migrate-to-firefly-v9.0","l":"Migrate to firefly v​9.​0"},{"n":"migrate-to-firefly-v9.3","l":"Migrate to firefly v​9.​3"}],"s":""},{"n":"reference","l":"Reference","o":true,"i":[{"n":"packages","l":"Packages"},{"n":"runtime","l":"Runtime","c":false,"i":[{"n":"runtime-class","l":"Firefly​Runtime class"},{"n":"runtimecontext","l":"Runtime​Context"},{"n":"useruntime","l":"use​Runtime"},{"n":"useruntimemode","l":"use​Runtime​Mode"},{"n":"useroutes","l":"use​Routes"},{"n":"usenavigationitems","l":"use​Navigation​Items"},{"n":"uselogger","l":"use​Logger"},{"n":"useloggers","l":"use​Loggers"},{"n":"useplugin","l":"use​Plugin"}]},{"n":"registration","l":"Registration","c":false,"i":[{"n":"bootstrap"},{"n":"registerlocalmodules","l":"register​Local​Modules"},{"n":"registerremotemodules","l":"register​Remote​Modules"},{"n":"usedeferredregistrations","l":"use​Deferred​Registrations"},{"n":"mergedeferredregistrations","l":"merge​Deferred​Registrations"}]},{"n":"routing","l":"Routing","c":false,"i":[{"n":"approuter","l":"App​Router"},{"n":"publicroutes","l":"Public​Routes"},{"n":"protectedroutes","l":"Protected​Routes"},{"n":"useisbootstrapping","l":"use​Is​Bootstrapping"},{"n":"userenderednavigationitems","l":"use​Rendered​Navigation​Items"},{"n":"useroutematch","l":"use​Route​Match"},{"n":"resolveroutesegments","l":"resolve​Route​Segments"},{"n":"useisrouteprotected","l":"use​Is​Route​Protected"},{"n":"isnavigationlink","l":"is​Navigation​Link"}]},{"n":"logging","l":"Logging","c":false,"i":[{"n":"consolelogger","l":"Console​Logger"},{"n":"logger","l":"Logger"}]},{"n":"messaging","l":"Messaging","c":false,"i":[{"n":"eventbus","l":"Event​Bus"},{"n":"useeventbusdispatcher","l":"use​Event​Bus​Dispatcher"},{"n":"useeventbuslistener","l":"use​Event​Bus​Listener"}]},{"n":"plugins","l":"Plugins","c":false,"i":[{"n":"plugin","l":"Plugin"}]},{"n":"webpack","c":false,"i":[{"n":"definedevhostconfig","l":"define​Dev​Host​Config"},{"n":"definedevremotemoduleconfig","l":"define​Dev​Remote​Module​Config"},{"n":"definebuildhostconfig","l":"define​Build​Host​Config"},{"n":"definebuildremotemoduleconfig","l":"define​Build​Remote​Module​Config"}]},{"n":"tanstack-query","l":"Tan​Stack Query","c":false,"i":[{"n":"usepublicdataqueries","l":"use​Public​Data​Queries"},{"n":"useprotecteddataqueries","l":"use​Protected​Data​Queries"},{"n":"isglobaldataquerieserror","l":"is​Global​Data​Queries​Error"}]},{"n":"msw","l":"Mock Service Worker","c":false,"i":[{"n":"setmswasready","l":"set​Msw​As​Ready"}]},{"n":"i18next","l":"i​18​next","c":false,"i":[{"n":"i18nextplugin","l":"i​18​next​Plugin"},{"n":"geti18nextplugin","l":"get​I​18​next​Plugin"},{"n":"usechangelanguage","l":"use​Change​Language"},{"n":"usecurrentlanguage","l":"use​Current​Language"},{"n":"usei18nextinstance","l":"use​I​18​next​Instance"},{"n":"i18nextnavigationitemlabel","l":"I​18​next​Navigation​Item​Label"}]},{"n":"honeycomb","l":"Honeycomb","c":false,"i":[{"n":"registerhoneycombinstrumentation","l":"register​Honeycomb​Instrumentation"},{"n":"setglobalspanattributes","l":"set​Global​Span​Attributes"}]},{"n":"env-vars","l":"Environment variables","c":false,"i":[{"n":"environmentvariablesplugin","l":"Environment​Variables​Plugin"},{"n":"getenvironmentvariablesplugin","l":"get​Environment​Variables​Plugin"},{"n":"useenvironmentvariable","l":"use​Environment​Variable"},{"n":"useenvironmentvariables","l":"use​Environment​Variables"}]},{"n":"fakes","l":"Fakes","c":false,"i":[{"n":"localstoragesessionmanager","l":"Local​Storage​Session​Manager"},{"n":"readonlysessionlocalstorage","l":"Readonly​Session​Local​Storage"}]}],"s":""},{"n":"troubleshooting","l":"Troubleshooting","s":""},{"n":"samples","l":"Samples","s":""},{"n":"about","l":"About","v":false}],"search":{"mode":0,"minChars":2,"maxResults":20,"placeholder":"Search","hotkeys":["k"],"noResultsFoundMsg":"Sorry, no results found.","recognizeLanguages":true,"languages":[0],"preload":false},"resources":{"History_Title_Label":"History","History_ClearLink_Label":"Clear","History_NoHistory_Label":"No history items","API_AccessFilter_Label":"Access","API_ParameterSection_Label":"PARAMETERS","API_SignatureSection_Label":"SIGNATURE","API_CopyHint_Label":"Copy","API_CopyNameHint_Label":"Copy name","API_CopyLinkHint_Label":"Copy link","API_CopiedAckHint_Label":"Copied!","API_MoreOverloads_Label":"more","API_MoreDropdownItems_Label":"More","API_OptionalParameter_Label":"optional","API_DefaultParameterValue_Label":"Default value","API_InheritedFilter_Label":"Inherited","Search_Input_Placeholder":"Search","Toc_Contents_Label":"Contents","Toc_RelatedClasses_Label":"Related Classes","History_JustNowTime_Label":"just now","History_AgoTime_Label":"ago","History_YearTime_Label":"y","History_MonthTime_Label":"mo","History_DayTime_Label":"d","History_HourTime_Label":"h","History_MinuteTime_Label":"m","History_SecondTime_Label":"s"}}; diff --git a/resources/js/search.json b/resources/js/search.json index aac40f9a2..2b12c3469 100644 --- a/resources/js/search.json +++ b/resources/js/search.json @@ -1 +1 @@ -[[{"i":"#","p":["The documentation for Squide firefly v8 is available here."]},{"l":"Getting started","p":["Welcome to Squide (yes \uD83E\uDD91 with an \"e\"), a shell for Workleap web applications built on top of Module Federation, React Router and TanStack Query. In this getting started section, you'll find an overview of the shell and a quick start guide to create a new application from scratch."]},{"i":"why-squide","l":"Why Squide?","p":["We originally built this shell to facilitate the adoption of federated applications at Workleap by enforcing patterns that we believe are essential for teams to successfully implement a distributed frontend architecture.","While Squide remains a great shell for federated applications, as we experimented with new products, we discovered that Squide also offers significant value for non-federated web applications:","With the power of local modules and the Runtime API, Squide addresses a long-lasting challenge at Workleap: How can we effectively enforce the boundaries of a business subdomain in the frontend? Squide's modular design naturally upholds these boundaries.","With Squide, teams can confidently develop new products as a simple monorepo application, knowing that as new members are onboarded, their development velocity will scale seamlessly. Over time, local modules can be migrated to remote modules without the need to refactor the core application architecture.","For both federated and non-federated web applications, Squide's modular architecture and lightweight API layer provide a significant upside, combining the strengths of industry-leading third-party libraries:"]},{"l":"Module Federation","p":["We identified 2 major challenges with federated applications:","How can we prevent loading the same large dependencies twice when switching between modules?","How can we offer a cohesive experience that doesn't feel modular?","To address the first challenge, we believe that Module Federation provides a solution by offering a mechanism capable of deduping common dependencies shared between the host application and the remote modules at runtime.","With this mechanism in place, all federated parts of an application can now be loaded in the same browsing context instead of nested browsing contexts such as iframes.","By sharing the same browsing context (e.g. the same Document object, the same Window object, and the same DOM), federated parts now form a unified and cohesive single application, addressing the second challenge.","With Module Federation, we hope to develop federated applications that provide the same user experience as monolithic applications \uD83D\uDE80."]},{"l":"React Router","p":["React Router nested routes feature is ideal for modular applications as it enables highly composable and decoupled UI. For a more in-depth explanation, refer to this article."]},{"l":"TanStack Query","p":["TanStack Query simplifies server state management with an innovative approach to data fetching, caching, and synchronization, enhancing both the perceived performance and the user experience.","TanStack Query is particularly well-suited for modular applications due to its ability to manage server state across multiple independent React components. It’s an effective solution for modular applications that requires isolating data and state between independent parts."]},{"l":"Module registration","p":["The most distinctive aspect of this shell is the conventions it enforces for loading and registering remote modules. Here's a brief overview of the flow:","During bootstrap, the host application attempts to load predefined modules and calls a registration function with a specific name and signature for each successfully loaded module.","During registration, a module receives the runtime of the application and use the instance to dynamically register its routes and navigation items.","Once all the modules are registered, the host application will create a React Router instance with the registered routes and renders a navigation menu with the registered navigation items.","This is a high-level overview. Of course, there is more to it, but these are the main ideas."]},{"l":"Guiding principles","p":["While developing the API of Squide, we kept a few guiding principles in mind. Those principles are not settled stones, you might want to diverge from them from time to time, but adhering to those will make your experience more enjoyable:","A module should correspond to a subdomain of the application's business domain.","A module should be autonomous.","A module should not directly reference the other modules of the application. To coordinate with other modules, including the host application, a module should always use Squide's Runtime API.","A modular application should feel cohesive. Different parts of the application should have the ability to communicate with each others and react to changes happening outside of their boundaries (without taking an hard reference on other parts of the application).","Data and state should never be shared between modules. Even if two modules require the same data or the same state values, they should load, store and manage those independently."]},{"l":"Limitations","p":["If you choose to include remote modules to your application, Module Federation comes with a few manageable limitations that are important to consider when architecting a distributed application:","A shared dependency cannot be tree-shaken. Since remote modules are loaded at runtime, module federation cannot infer which parts of a shared dependency will be used by the application modules. Therefore, tree-shaking is disabled for shared dependencies.","Updating a shared dependency to a new major version is not always straightforward and may result in complex deployment processes."]},{"l":"Create your project","p":["To get started, follow the quick start guide to create a new Squide's application from scratch."]}],[{"l":"Create an host application","p":["We highly recommend going through the entire getting started guide. However, if you prefer to scaffold the application we'll be building, a template is available with degit:","Let's begin by creating the application that will serve as the entry point for our modular application and host the application modules."]},{"l":"Install the packages","p":["Create a new application (we'll refer to ours as host), then open a terminal at the root of the new solution and install the following packages:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Setup the application","p":["First, create the following files:","Then, ensure that you are developing your application using ESM syntax by specifying type: module in your package.json file:","Finally, use a dynamic import to add an async boundary:","To learn more about this async boundary and the bootstrap.tsx file, read the following article."]},{"l":"Module registration","p":["Next, to register the modules, instanciate a shell FireflyRuntime instance and register the remote module with the bootstrap function (the configuration of the remote module will be covered in the next section):","Then, render the AppRouter component to define a React Router browser instance configured with the registered routes:"]},{"l":"Navigation items","p":["Next, create a layout component to render the navigation items. In many applications, multiple pages often share a common layout that includes elements such as a navigation bar, a user profile menu, and a main content section. In a React Router application, this shared layout is commonly referred to as a RootLayout:","The RootLayout component created in the previous sample will serves as the default layout for the homepage as well as for every page (route) registered by a module that are not nested under a parent route with either the parentPath or the parentId option."]},{"l":"Homepage","p":["Next, create the HomePage component that will serve as the homepage:","Then, add a local module at the root of the host application to register the homepage:","And an hoisted route to render the RootLayout with the PublicRoutes and ProtectedRoutes placeholders:","The PublicRoutes and ProtectedRoutes placeholders indicates where routes that are neither hoisted or nested with a parentPath or parentId option will be rendered. In this example, the homepage route is considered as a protected route and will be rendered under the ProtectedRoutes placeholder.","Finally, update the bootstrapping code to register the newly created local module:"]},{"i":"not-found-page-404","l":"Not found page (404)","p":["Now, let's ensure that users who enter a wrong URL end up somewhere by registering a custom no-match route. First, create the NotFoundPage component, which will serve as the page for handling not found routes:","Then, register the newly created component as the * route:"]},{"l":"Configure webpack","p":["Squide webpack configuration is built on top of @workleap/webpack-configs, @workleap/browserslist-config and @workleap/swc-configs. If you are having issues with the configuration of these tools, refer to the tools documentation websites.","First, open the public/index.html file created at the beginning of this guide and copy/paste the following HtmlWebpackPlugin template:","Then, open the .browserslist file and copy/paste the following content:"]},{"l":"Development configuration","p":["To configure webpack for a development environment, first open the swc.dev.js file and copy/paste the following code:","Then, open the webpack.dev.js file and use the defineDevHostConfig function to configure webpack:","If you are having issues with the wepack configuration that are not related to module federation, refer to the @workleap/webpack-configs documentation."]},{"l":"Build configuration","p":["To configure webpack for a build environment, first open the swc.build.js file and copy/paste the following code:","Then, open the webpack.build.js file and use the defineBuildHostConfig function to configure webpack:","If you are having issues with the wepack configuration that are not related to module federation, refer to the @workleap/webpack-configs documentation."]},{"l":"Add CLI scripts","p":["To initiate the development server, add the following script to the application package.json file:","To build the application, add the following script to the application package.json file:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script. You should see the homepage. Even if the remote module application is not yet available, the host application will gracefully (and ignore the remote module)."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong:","[squide] Found 4 local modules to register.","[squide] 1/4 Registering local module.","[squide] 1/4 Local module registration completed.","[squide] Found 1 remote module to register.","[squide] 1/1 Loading module register of remote1.","[squide] 1/1 Registering module register of remote remote1.","[squide] 1/1 The registration of the remote remote1 is completed.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Create a remote module","p":["We highly recommend going through the entire getting started guide. However, if you prefer to scaffold the application we'll be building, a template is available with degit:","Remote modules are modules that are not included in the host application build but are instead loaded at runtime from a remote server. They provide a way for teams to be fully autonomous by independently deploying their modules without relying on the other parts of the application.","Let's add our first remote module!"]},{"l":"Install the packages","p":["Create a new application (we'll refer to ours as remote-module), then open a terminal at the root of the new solution and install the following packages:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Setup the application","p":["First, create the following files:","Then, ensure that you are developing your module using ESM syntax by specifying type: module in your package.json file:"]},{"l":"Routes registration","p":["Next, register the remote module routes and navigation items with the registerRoute and registerNavigationItem functions:","Then, create the Page component:"]},{"l":"Configure webpack","p":["Squide webpack configuration is built on top of @workleap/webpack-configs, @workleap/browserslist-config and @workleap/swc-configs. If you are having issues with the configuration of these tools, refer to the tools documentation websites."]},{"l":"Development configuration","p":["To configure webpack for a development environment, first open the swc.dev.js file and copy/paste the following code:","Then, open the webpack.dev.js file and use the defineDevRemoteModuleConfig function to configure webpack:","If you are having issues with the wepack configuration that are not related to module federation, refer to the @workleap/webpack-configs documentation."]},{"l":"Build configuration","p":["To configure webpack for a build environment, first open the swc.build.js file and copy/paste the following code:","Then, open the webpack.build.js file and use the defineBuildRemoteModuleConfig function to configure webpack:","If you are having issues with the wepack configuration that are not related to module federation, refer to the @workleap/webpack-configs documentation."]},{"l":"Add CLI scripts","p":["To initiate the development server, add the following script to the application package.json file:","To build the module, add the following script to the application package.json file:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the host and the remote-module applications in development mode using the dev script. You should notice an additional link labelled Remote/Page in the navigation menu. Click on the link to navigate to the page of your new remote module!"]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong:","[squide] The following route has been registered.","[squide] The following static navigation item has been registered to the root menu for a total of 2 static items.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Create a local module","p":["We highly recommend going through the entire getting started guide. However, if you prefer to scaffold the application we'll be building, a template is available with degit:","Local modules are regular modules that are part of the host application build. They are independent modules that expose a registration function to the host application's bootstrapping code. A local module can be a standalone package, a sibling project (in a monorepo setup), or even a local folder within the host application.","Local modules have many uses but are especially useful when launching a new product with an unrefined business domain or migrating from a monolithic application to a distributed application.","Let's add a local module to demonstrate how it's done!"]},{"l":"Install the packages","p":["Create a new application (we'll refer to ours as local-module), then open a terminal at the root of the new solution and install the following packages:","While you can use any package manager to develop an application with Squide, it is highly recommend that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Setup the application","p":["First, create the following files:","Then, ensure that you are developing your module using ESM syntax by specifying type: module in your package.json file:","Finally, configure the package to be shareable by adding the name, version, and export fields to the package.json file:"]},{"l":"Routes registration","p":["Next, register the local module routes and navigation items with registerRoute and registerNavigationItem functions:","Then, create the Page component:"]},{"l":"Register the local module","p":["Go back to the host application and add a dependency to the @getting-started/local-module package in the host application package.json file:","If your project is set up as a monorepo, use workspace:* for the version instead of 0.0.1.","Then, register the local module with the bootstrap function:"]},{"l":"Configure tsup","p":["If you are having issues with the tsup configuration, refer to the @workleap/tsup-configs documentation."]},{"l":"Development configuration","p":["To configure tsup for a development environment, open the tsup.dev.ts file and copy/paste the following code:"]},{"l":"Build configuration","p":["To configure tsup for a build environment, open the tsup.build.ts file and copy/paste the following code:"]},{"l":"Add CLI scripts","p":["To initiate the development server, add the following script to the application package.json file:","To build the module, add the following script to the application package.json file:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the host, remote-module and local-module applications in development mode using the dev script. You should notice an additional link labelled Local/Page in the navigation menu. Click on the link to navigate to the page of your new local module!"]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong:","[squide] The following route has been registered.","[squide] The following static navigation item has been registered to the root menu for a total of 2 static items.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Learn the API","p":["Now that we've created a host application, loaded a few modules and registered routes and navigation items, let's delve into the APIs provided by this shell."]},{"l":"Runtime mode","p":["In an effort to optimize the development experience, Squide can be bootstrapped in development or production mode:","By default, the Runtime mode is development."]},{"l":"Logging","p":["Squide includes a built-in logging feature that integrates with the FireflyRuntime class and the useLogger hook.","First, register your own custom logger by implementing the Logger interface or register Squide built-in ConsoleLogger:","Then, log entries from any parts of your modular application with the useLogger hook:","Or the useLoggers hook to target specific logger instances:","The logger is also available from the FireflyRuntime instance."]},{"l":"Messaging","p":["It's crucial that the parts of a modular application remains loosely coupled. To help with that, Squide offers a built-in Event Bus.","First, listen to an event with the useEventBusListener hook:","Then, dispatch an event from anywhere with the useEventBusDispatcher hook:","You can use the event bus to enable various communication scenarios, such as notifying components of state changes, broadcasting messages across modules, or triggering actions based on specific events.","The event bus is also available from the FireflyRuntime instance."]},{"l":"Plugins","p":["To keep Squide lightweight, not all functionalities should be integrated as a core functionality. However, to accommodate a broad range of technologies, a plugin system has been implemented to fill the gap.","Plugins can be registered at bootstrapping with the FireflyRuntime instance:","And can be accessed from any parts of the application with the usePlugin hook:","A plugin can also be retrieved from the FireflyRuntime instance.","By default, the FireflyRuntime registers Squide's MSW plugin. An optional i18next plugin is available."]},{"l":"TanStack Query","p":["Hooks are available to retrieve global application data using TanStack Query. To fetch public data, use the usePublicDataQueries hook:","To retrieve protected data, use the useProtectedDataQueries hook instead:","If an unmanaged error occur while retrieving the data, a GlobalDataQueriesError is thrown."]},{"l":"Fakes","p":["Take a look at the fake implementations. These implementations are designed to facilitate the set up of a module isolated environment."]},{"l":"Guides","p":["Explore the guides section to learn about Squide advanced features.","Be sure to read, at a minimum, the following guides:","Setup Mock Service Worker","Fetch global data","Fetch page data","Manage shared state","Isolate module failures","Add authentication","Add a shared dependency"]},{"l":"Reference","p":["For a comprehensive list of the Squide API, refer to the reference section."]},{"l":"Samples","p":["Finally, have a look at the sample applications to see the Squide API in action."]}],[{"l":"Deploy","p":["The deployment process for a modular application can vary depending on various factors, including the chosen hosting provider. Therefore, we do not recommend any specific deployment setup.","However, there are a few essential configurations that need to be made regardless of your architectural and deployment choices."]},{"l":"Add a default redirect","p":["To enable support for direct page hits, add the following redirect rule to your host application's hosting provider:","For Netlify, it can either be with a netlify.toml file at the root of project:","Or by adding a _redirects file into the Netlify publish directory:"]},{"l":"Set the remote URL","p":["If your modular applications includes remote modules, configure the remote modules production URL:"]},{"l":"Update the runtime mode","p":["Don't forget to change the FireflyRuntime mode to production:"]},{"l":"Remove the console logger","p":["Remove the ConsoleLogger from the production build:"]}],[{"l":"Guides","p":["Add a public route","Add a shared dependency","Add authentication","Develop a module in isolation","Fetch global data","Fetch page data","Implement a custom logger","Isolate module failures","Manage shared state","Override a React context","Override the host layout","Setup Honeycomb","Setup i18next","Setup Mock Service Worker","Use environment variables","Use feature flags","Use modular tabs"]}],[{"l":"Setup Mock Service Worker","p":["To speed up frontend development and encourage an API first approach, Squide has built-in support for Mock Service Worker(MSW). MSW offers an API to host fake endpoints directly in the browser. This means that unlike alternative solutions, it doesn't require running an additional process."]},{"l":"Setup the host application","p":["First, open a terminal at the root of the host application and install the msw package:","Then initialize MSW by executing the following command:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Add an environment variable","p":["Then, update the dev PNPM script to define with cross-env an USE_MSW environment variable that will conditionally include MSW code into the application bundles:","Then, update the development webpack configuration file to include the USE_MSW environment variable into the application bundles:","For more information about the environmentVariables predefined option, refer to the webpack configuration documentation.","Don't forget to define the USE_MSW environment variable for the build script and build webpack configuration as well."]},{"l":"Start the service","p":["With the newly added USE_MSW environment variable, the host application bootstrapping code can now be updated to conditionally start MSW when all the request handlers has been registered.","First, define a function to start MSW:","Then, update the bootstrapping code to start MSW when it's enabled:"]},{"l":"Delay routes rendering until the service is started","p":["Finally, update the host application code to delay the rendering of the routes until MSW is started. This is done by setting the waitForMsw property of the AppRouter component to true:"]},{"l":"Setup a remote module","p":["First, open a terminal at the root of the remote module application and install the msw package:","Then, define a request handler:","Finally, register the request handler with the FireflyRuntime instance:"]},{"l":"Setup a local module","p":["Follow the same steps as for a remote module."]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Update a page component code to fetch the /api/character/1 fake API endpoint, then start the application in development mode using the dev script. You should notice that the data has been fetched from the request handler.","In Chrome devtools, the status code for a successful network call that has been handled by an MSW request handler will be 200 OK (from service worker)."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each request handlers registration that occurs and error messages if something went wrong:","[squide] The following MSW request handlers has been registered: [...]","[squide] MSW is ready.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Fetch global data","p":["Before going forward with this guide, make sure that you completed the Setup Mock Service Worker guide.","Retrieving the global data of an application is a crucial aspect that isn't always straightforward to implement. That's why we encourage feature teams to build their global data fetching strategy on top of the Squide AppRouter component."]},{"l":"Challenges with global data","p":["At first glance, one might wonder what could be so complicated about fetching the global data of an application. It's only fetches ...right? Well, there are several concerns to take into account for a Squide application:","When in development, the global data cannot be fetched until the Mock Service Worker (MSW) request handlers are registered and MSW is ready.","To register the MSW request handlers, the modules(including the remote modules) must be registered first.","If the requested page is public, only the global public data should be fetched.","If the requested page is protected, both the global public and protected data should be fetched.","The requested page rendering must be delayed until the global data has been fetched.","A unique loading spinner should be displayed to the user during this process, ensuring there's no flickering due to different spinners being rendered.","To help manage those concerns, Squide offer an AppRouter component that takes care of setuping Squide's primitive and orchestrating the different states."]},{"l":"Fetch public data"},{"l":"Add an endpoint","p":["First, define in the host application an MSW request handler that returns the number of times it has been fetched:","Then, register the request handler using the module registration function:"]},{"l":"Create a shared context","p":["Then, in a shared project, create a React context named FetchCountContext:","Ensure that the shared project is configured as a shared dependency."]},{"l":"Create a custom error class","p":["Then, in the same shared project, create a ApiError class:"]},{"l":"Fetch the data","p":["Finally, update the App component to add the usePublicDataQueries hook. The hook will fetch the data from /api/count and forward the retrieved fetchCount value through FetchCountContext:"]},{"l":"usePublicDataQueries","p":["The usePublicDataQueries hook is a wrapper around TanStack Query's native useQueries hook. This wrapper coordinates the execution of the queries with the AppRouter component's state."]},{"i":"waitforpublicdata--useisbootstrapping","l":"waitForPublicData & useIsBootstrapping","p":["To ensure the AppRouter component wait for the public data to be ready before rendering the requested route, set the waitForPublicData property to true.","Combine the usePublicDataQueries with the useIsBootstrapping hook to display a loader until the public data is fetched and the application is ready."]},{"l":"Use the endpoint data","p":["Now, create a GlobalDataLayout component that uses the count retrieved from FetchCountContext and render pages with a green background color if the value is odd:","Then, create a Page component:","Finally, register both components, either in the host application or within any module:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script and navigate to the /global-data page. Refresh the page a few times, the background color should alternate between transparent and green."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this section of the guide:","Open the DevTools console. You'll find a log entry for each registration that occurs (including MSW request handlers) and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]},{"l":"Fetch protected data","p":["Now, let's load protected data. The process is similar to fetching public data, but this time, we'll use the useProtectedDataQueries hook instead."]},{"i":"add-an-endpoint-1","l":"Add an endpoint","p":["First, define a MSW request handler that returns a user tenant subscription data:","If you've registered the public data request handler, the newly created request handler should be automatically registered."]},{"i":"create-a-shared-context-1","l":"Create a shared context","p":["Then, in a shared project, create a SubscriptionContext:","If you're not adding the SubscriptionContext to the shared project created earlier for the public data example, make sure to configure this new shared project as a shared dependency."]},{"i":"fetch-the-data-1","l":"Fetch the data","p":["Finally, update the App component to add the useProtectedDataQueries hook. The hook will fetch the data from /api/subscription and forward the retrieved subscription data through SubscriptionContext:"]},{"l":"useProtectedDataQueries","p":["The useProtectedDataQueries hook is a wrapper around TanStack Query's native useQueries hook. This wrapper coordinates the execution of the queries with the AppRouter component's state."]},{"l":"waitForProtectedData","p":["To ensure the AppRouter component wait for the protected data to be ready before rendering the requested route, set the waitForProtectedData property to true."]},{"i":"use-the-endpoint-data-1","l":"Use the endpoint data","p":["Now, update the GlobalDataLayout component that was previously created for the public data example to render the user tenant subscription status:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script and navigate to the /global-data page. You should notice the subscription status."]},{"i":"troubleshoot-issues-1","l":"Troubleshoot issues","p":["If you are experiencing issues with this section of the guide:","Open the DevTools console. You'll find a log entry for each registration that occurs (including MSW request handlers) and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Fetch page data","p":["Before going forward with this guide, make sure that you completed the Setup Mock Service Worker guide.","There are various approaches to fetching data for pages. At Workleap, our preference is to develop a backend for frontend (BFF) with a dedicated endpoint per page, returning a data structure specifically tailored for that page. We rely on server state as our single source of truth and leverage TanStack Query to manage data fetching.","Although this approach works well, a few adjustments are necessary for modular applications."]},{"l":"Install TanStack Query","p":["First, open a terminal at the root of the module and install the following packages:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Setup the query client","p":["Then, instanciate a QueryClient instance in the module registration function and wrap the routes element with a QueryClientProvider:","To minimize unexpected situations and faciliate maintenance, the TanStack Query cache shouldn't be shared between the host application and the modules. As the TanStack Query cache is located in the QueryClient, both the host application and the modules should instantiate their own QueryClient instance."]},{"l":"Create a component for providers","p":["If the module register multiple routes, to prevent duplicating registration code, you can create a Providers component:"]},{"l":"Setup the development tools","p":["To faciliate development, TanStack Query provides devtools to help visualize all of the inner workings of TanStack Query.","However, the TanStack Query devtools has not been developed to handle a modular application with multiple QueryClient instances. To use the devtools, you must define a ReactQueryDevtools component for each QueryClient instance:","Then, depending on which page of the application has been rendered, a distinct devtools instance will be accessible. For a better experience, we recommend activating the TanStack Query devtools exclusively when developing a module in isolation:"]},{"l":"Fetch the page data","p":["Now, let's fetch some data. First, add a Mock Service Worker(MSW) request handler to the local module:","Then, register the request handler using the module registration function:","Then, update the Page component to fetch and render the data with useSuspenseQuery:"]},{"l":"Define a fallback element","p":["The previous code sample uses useSuspenseQuery instead of useQuery to fetch data. This enables an application to leverage a React Suspense boundary to render a fallback element in a layout component while the data is being fetched:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the local module in a development environment using the dev-isolated script. If you haven't completed the develop a module in isolation guide, use the dev script instead and skip the part about TanStack Query devtools. Then, navigate to the /page page.","You should notice that the character's data is being fetch from the MSW request handler and rendered on the page. Additionally, you should notice that the TanStack Query devtools are available (a ribbon at the bottom right corner)."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this section of the guide:","Open the DevTools console. You'll find a log entry for each registration that occurs (including MSW request handlers) and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Manage shared state","p":["Proper management of shared state is crucial in a modular application and can become problematic if not handled carefully. As a general rule, a host application and its modules should never share state."]},{"l":"Forward the global data","p":["However, in the lifecycle of a modular application, the host will fetch the global data that should be fordwarded to the modules. Such examples include a user session or a user tenant subscription status.","As shown in the Fetch global data guide, the global data can be forwarded to modules through a React context."]},{"l":"TanStack Query","p":["Lastly, as detailed in the fetch page data guide, the TanStack Query cache should not be shared between the host and its modules. To do so, both the host application and the modules should instantiate their own QueryClient instance."]}],[{"l":"Isolate module failures","p":["One of the key characteristics of micro-frontends implementations like iframes and subdomains is the ability to isolate failures within individual modules, preventing them from breaking the entire application.","However, with a Module Federation implementation, this is not the case as all the modules share the same browsing context (e.g. the same Document object, the same Window object, and the same DOM). A failure in one module can potentially breaks the entire application.","Nevertheless, an application, federated or non-federated, can get very close to iframes failure isolation by utilizing React Router's Outlet component and the errorElement property of a React Router's routes."]},{"l":"Create an error boundary","p":["First, define a React Router's error boundary to catch module errors. For this example we'll name it ModuleErrorBoundary:"]},{"l":"Register the error boundary","p":["Then, update the host application registerHost function to declare the ModuleErrorBoundary component below the RootLayout component but above the routes of the modules. By doing so, if a module encounters an unhandled error, the error boundary will only replace the section rendered by the Outlet component within the root layout rather than the entire page.","A React Router's error boundary is declared with the errorElement of a route:","By implementing this mechanism, the level of failure isolation achieved is comparable to that of an iframes or subdomains implementation. With this mechanism, failure isolation is as good as with an iframes or subdomains implementation."]},{"l":"Hoisted pages","p":["If your application is hoisting pages, it's important to note that they will be rendered outside of the host application's ModuleErrorBoundary component. To prevent breaking the entire application when an hoisted page encounters unhandled errors, it is highly recommended to declare a React Router's error boundary for each hoisted page as well, again using errorElement:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script. Update any of your application routes that is rendered under the newly created error boundary (e.g. that is not hoisted) and throw an Error. The error should be handled by the ModuleErrorBoundary component instead of breaking the whole application."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Add authentication","p":["Before going forward with this guide, make sure that you completed the Setup Mock Service Worker and Fetch global data guides.","Most of Workleap's applications, if not all, will eventually require user authentication. While Squide doesn't offer built-in primitives for this process, it can assist by providing a well-established recipe to integrate an authentication flow with Squide."]},{"l":"Add a login page","p":["First, open a terminal at the root of the host application and install the @squide/fakes package:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM.","Then, add a Mock Service Worker(MSW) request handler to authenticate a user:","In the previous code sample, the endpoint attempts to authenticate the provided credentials against existing users. If there's a match, the user session is stored in the local storage using a LocalStorageSessionManager instance, and a 200 status code is returned.","Our security department reminds you to refrain from using a fake LocalStorageSessionManager in a production application \uD83D\uDE0A","Next, register the request handler using the host application registration function:","Then, create a login page:","After the user logs in, the application is reloaded, this is a requirement of the AppRouter component. Nevertheless, it's not a concern because Workleap's applications use a third-party service for authentication which requires a full refresh of the application."]},{"l":"Create a session manager","p":["Next, create a shared type for the session and the session manager:","Then, create a shared SessionManagerContext along with some utility hooks. This React context will be used to share the SessionManager instance down the components tree:","Finally, let's go back to the host application and create a TanStack Query implementation of the shared SessionManager interface created previously:"]},{"l":"Fetch the session","p":["Next, create an MSW request handler that returns a session object if a user is authenticated:","Then, update the host application App component to load the session with the useProtectedDataQueries hook and create an instance of TanstackQuerySessionManager with the retrieved session to share the sessuib via the SessionManagerContext:","The previous example uses the following implementation of the ApiError class:"]},{"l":"Add an authentication boundary","p":["Next, create an authentication boundary component using the shared useIsAuthenticated hook created earlier to redirect unauthenticated user to the login page:"]},{"l":"Define an authenticated layout","p":["Now, let's add a specific layout for authenticated users that passes through the AuthenticationBoundary component.","First, add a MSW request handler to log out a user:","Then, introduce a new AuthenticatedLayout component displaying the name of the logged-in user along with a logout button. This layout will retrieve the active user session from the shared useSessionManager hook introduced earlier:","By creating a new AuthenticatedLayout component, much of the layout code has been transferred from the RootLayout to the AuthenticatedLayout, leaving the root layout responsible only for styling the outer wrapper of the application for now:"]},{"l":"Setup the routes","p":["Finally, assemble everything:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application using the dev script and attempt navigating to the root page (/). You will be redirected to the /login page. Login with temp/ temp, you will be redirected to the root page."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Add a public route","p":["A route can be registered as either public or protected. This visibility indicator does not determine whether a route is accessible to everyone or restricted to authenticated users; that protection is typically enforced by an authentication boundary.","In a Squide application, the visibility indicator determines whether routes will be rendered as children of either the PublicRoutes or ProtectedRoutes placeholders and whether the usePublicDataQueries or useProtectedDataQueries hooks should execute their requests. If the initially requested route is marked as protected and both hooks are defined, each query hook will execute its respective requests. However, if the route is marked as public, only the usePublicDataQueries hook will execute its requests.","When a route is registered with the registerRoute function, it is considered protected by default. Therefore, if a route does not rely on the application's global protected data, it should be explicitly registered as public using the registerPublicRoute function:","Don't forget to register the PublicRoutes placeholder in the host application:"]}],[{"l":"Override the host layout","p":["The RootLayout component defined in the Create an host application starting guide serves as the default layout for the homepage and all the managed routes.","For most routes, this behavior is what the author expects. However, as an application introduces authentication and adds many session-related features to the default layout, this default layout may no longer be suitable for every route. For example, a login page doesn't require session-related features, as the user isn't authenticated yet. In such cases, the default layout isn't appropriate.","To accomodate pages requiring a different layout, a mechanism is needed to move their route declaration to the root of the React Router instance before RootLayout is declared."]},{"l":"Hoist a module routes","p":["Package managers supporting workspaces such as Yarn and NPM call this mechanism \"hoisting\", which means \"raise (something) by means of ropes and pulleys\". This is exactly what we are trying to achieve here.","Squide has a built-in hoist functionality capable of raising module routes marked as hoist at the root of the routes array, before the RootLayout declaration. Thus, an hoisted route will not be wrapped by the RootLayout component (or any authentication boundaries) and will have full control over its rendering.","To hoist module routes, add the hoist option to the route registration options and optionally use a different layout:","By declaring a route as hoisted, other parts of the application will not be isolated anymore from this route's failures as the route will most likely be rendered outside of the host application's root error boundary. To avoid breaking the entire application when an hoisted route encounters unhandled errors, it is highly recommended to declare a React Router's errorElement property for each hoisted routes.","By declaring a route as hoisted, the route will be rendered at the root of the router, therefore, most certainly outside the authenticated boundary of the application. If the hoisted route requires an authentication, make sure to wrap the route with an authentication boundary or to handle the authentication within the route's page."]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script and navigate to the /login page. The page should be displayed even if you are not authenticated."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Use modular tabs","p":["While it's typically recommended for a Squide application to maintain the boundary of a page within a single domain, there are situations where enhancing the user experience necessitates rendering a page with parts from multiple domains, or at the very least, simulating it \uD83D\uDE0A.","For this guide, we'll take as an example a page for which the parts that are owned by different domains are organized by tabs (modular tabs) and registered by different modules:","Tab 1: Registered by Remote Module 1","Tab 2: Registered by Remote Module 2","Tab 3: Registered by Local Module","Anatomy of a page rendering modular tabs"]},{"l":"Define a nested layout","p":["To build this page while adhering to Squide's constraint of avoiding hard references to elements from other modules, let's start by defining a React Router nested layout. This nested layout will handle rendering all the tab headers and the content of the active tab:","In the previous code sample, the TabsLayout component is similar to the RootLayout component introduced in previous guides. However, the key distinction is that this layout will be bound to the /tabs URL path. By nesting the layout under a specific path, it will only render when the user navigates to one of the modular tab pages (e.g. /tabs, /tabs/tab-1, /tabs/tab-2, /tabs/tab-3).","To register the newly created layout as a nested layout, use the registerRoute function:","With this nested layout in place, thanks to the React Router Outlet component, the content of the tabs can now reside in distinct routes(registered by different modules) while still delivering a cohesive user experience. Whenever a user navigates between the tabs, the URL will be updated, and the tab content will change, but the shared portion of the layout will remain consistent.","As a bonus, each individual tab will have its own dedicated URL! \uD83E\uDD73","It is recommended to define the shared layouts in a standalone package as it's done for the endpoints sample layouts project."]},{"l":"Create the tab routes","p":["Next, let's add the actual tabs to the modules. To do so, we'll use the parentPath option of the registerRoute function to register the routes under the TabsLayout component:","Now that the tabs has been registered, ensure that all four modules (including remote-modules-3) are registered in the host application. Start the development servers using the dev script. Navigate to the /tabs page, you should see the tab headers. Click on each tab header to confirm that the content renders correctly."]},{"l":"Decouple the navigation items","p":["Althought it's functional, the modules are currently coupled by hardcoded URLs within the TabsLayout component.","To decouple the navigation items, similar to what is done for regular module's routes, we'll use the registerNavigationItem function. In this case, we'll specify a menuId option. Defining the menuId option will allow the TabsLayout component to exclusively retrieve the navigation items that belongs to him.","First, let's register the navigation items with the menuId option. For this example the menuId will be /tabs(it can be anything):","Then, update the TabsLayout component to render the registered navigation items instead of the hardcoded URLs:"]},{"l":"Change the display order of the tabs","p":["Similarly to how the display order of regular navigation items can be configured, a modular tab position can be affected with the priority option.","To force Tab 3 to be positioned first, we'll give him a priority of 999:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["To ensure everything is still working correctly, start the development servers using the dev script and navigate to the /tabs page. You should see all three tabs, and you should be able to switch between them by clicking on the tab headers."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong:","[squide] The following route has been registered as a children of the /tabs route.","[squide] The following static navigation item has been registered to the /tabs menu for a total of 1 item.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Use feature flags","p":["Before going forward with this guide, make sure that you completed the Setup Mock Service Worker and Fetch global data guides.","To continuously deliver value to our customers, Workleap has adopted a feature flag system that enables functionalities to be activated or deactivated without requiring a code deployment. While implementing \"in-page\" feature flags in a Squide application is straightforward, feature flags that conditionally register navigation items require a more advanced deferred registration mechanism."]},{"l":"Add an endpoint","p":["First, define a MSW request handler that returns the feature flags:","Finally, register the request handler using the module registration function:"]},{"l":"Create a shared context","p":["Now, in a shared project, create a FeatureFlagsContext:","Ensure that the shared project is configured as a shared dependency."]},{"l":"Fetch the feature flags","p":["Finally, open the host application code and update the App component to fetch the feature flags data with the usePublicDataQueries hook:"]},{"l":"Conditionally render a page section","p":["Now, let's use the featureA flag from FeatureFlagsContext to conditionally render a section of a new Page component. In this example, a section of the Page component will only be rendered if featureA is activated:","Then, register the Page component using the module registration function:","If you've already registered a Page component in a previous guide, use a different name for this component."]},{"l":"Conditionally register a navigation item","p":["Conditionally registering navigation items based on a feature flag is more complex because Squide's default registration mechanism runs before the application has bootstrapped, meaning that the feature flags have not yet been fetched from the server.","To address this, Squide offers an alternate deferred registration mechanism in two-phases:","The first phase allows modules to register their static navigation items that are not dependent on initial data.","The second phase enables modules to register deferred navigation items that are dependent on initial data. We refer to this second phase as deferred registrations.","To defer a registration to the second phase, a module's registration function can return an anonymous function matching the DeferredRegistrationFunction type: (data, operation: register | update) = Promise | void.","Once the modules are registered and the useDeferredRegistrations hook is rendered, the deferred registration functions will be executed with either register or update as the value for the operation argument, depending on whether this is the initial or subsequent execution of the functions.","First, let's define a DeferredRegistrationData interface to a shared project, specifiying the initial data that module's deferred registration functions can expect:","Then, add DeferredRegistrationData to the ModuleRegisterFunction type definition and update the module register function to defer the registration of the Page component navigation item:","Finally, update the host application's App component to use the useDeferredRegistrations hook. By passing the feature flags data to useDeferredRegistrations, this data will be available to the module's deferred registration functions:","A key feature of TanStack Query is its ability to keep the frontend state synchronized with the server state. To fully leverage this, whenever the data passed to useDeferredRegistrations changes, all deferred registration functions are re-executed.","Remember to use useMemo for your deferred registration data and to specify the $id option for your navigation items!"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application using the dev and navigate to the /page page. The page should render with the conditonal section. Now, disable the featureA flag in the endpoint and refresh the page. You shouldn't see the conditonal section anymore. Finally, disable the featureB flag in the endpoint and refresh the page. The menu link labelled \"Page\" shouldn't be available anymore.","If you are experiencing issues with this section of the guide:","Open the DevTools console. You'll find a log entry for each registration that occurs (including MSW request handlers) and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Use environment variables","p":["Before going forward with this guide, make sure that you completed the Setup Mock Service Worker guide.","Environment variables are incredibly useful when working with multiple environments, such as dev, staging, and production, by decoupling configuration from the code. This allows to change an application's behavior without modifying the code itself. A common example is the URLs of dedicated API services, where each environment uses a different URL.","In webpack, environment variables are typically passed from the CLI to the application code using the DefinePlugin and accessed through process.env, e.g. process.env.BASE_API_URL.","While accessing environment variables from process.env works, it has a few downsides:","It's not ideal for testing. Tests relying on global variables can inadvertently affect other tests, introducing potential issues that affect test reliability, maintainability, and isolation.","It complicates module development in isolation. A modular application shell often makes requests to multiple endpoints, which vary depending on the environment. These endpoints require environment variables to define their URLs. When developing modules in isolation, modules should not provide these environment variables to the shell. Instead, to improve DX, the shell library should manage these environment variables internally.","To replace process.env, Squide provides the EnvironmentVariablesPlugin. This plugin acts as a registry and integrates with the Runtime API, allowing modules to register and retrieve environment variables.","Before this plugin, page components would directly rely on process.env:","With the EnvironmentVariablesPlugin, a page component can now retrieve the baseApiUrl from Squide's runtime instance by using the useEnvironmentVariable hook:","Let's go through the setup of the plugin and how to handle a few use cases."]},{"l":"Install the package","p":["First, open an existing Squide application. Then open a terminal at the root of the host application and install the following package:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Setup the plugin","p":["Then, update the host application boostrapping code to register an instance of the EnvironmentVariablesPlugin with the FireflyRuntime instance:"]},{"l":"Module augmentation","p":["Before registering variables, modules must augment the EnvironmentVariables TypeScript interface with the variables they intend to register to ensure type safety and autocompletion.","To do this, first create a types folder:","Then create an env-vars.d.ts file:","Finally, update the module tsconfig.json to include the types folder:"]},{"l":"Register variables","p":["Now, let's register our first variable. We recommend registering environment variables in the module's register function as it's the most logical place to access the runtime instance:","If multiple modules need to use the same environment variable, we recommend that each module register its own instance of the variable to maintain modularity. The EnvironmentVariablesPlugin registry will ignore any subsequent registrations for existing keys, as long as the variable value remains the same."]},{"l":"Retrieve a variable in React code","p":["Then, retrieve the variables in a new DataPage component using either the useEnvironmentVariable or useEnvironmentVariables hook:","Finally, register a route for the component:"]},{"l":"Retrieve a variable for MSW handlers","p":["Next, create an MSW handlers for the DataPage component. An handler can retrieve the variables using either the plugin's getVariable or getVariables function:","Finally, register the new handler:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script and navigate to the /data page. The page should render { foo: bar }."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this section of the guide:","Open the DevTools console. You'll find a log entry for each registration that occurs (including MSW request handlers) and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]},{"l":"Integrate with tests","p":["If the code under test uses environment variables, the EnvironmentVariablesPlugin can be used to mock these variables.","Considering the following utility hook:","You can write the following unit test to mock the value of apiBaseUrl and test the ouput of the useAbsoluteUrl hook:"]},{"l":"Integrate with stories","p":["Components included in Storybook stories often rely on environment variables. The EnvironmentVariablesPlugin can be used to mock these variables:"]},{"l":"Integrate with libraries","p":["Libraries, such as an application Shell, often need to manage environment variables internally to be portable.","Assuming the host application registers the EnvironmentVariablesPlugin into the runtime, and given the following file structure:","To setup such a library, first, create a registerShell function that accepts an argument indicating the current environment (e.g., dev, staging or production):"]},{"i":"register-variables-1","l":"Register variables","p":["Then, update the registerShell function to register the apiBaseUrl environment variable based on the provided env argument:"]},{"i":"module-augmentation-1","l":"Module augmentation","p":["Then, augment the EnvironmentVariables TypeScript interface to include the apiBaseUrl variable:","Then, update the module tsconfig.json to include the types folder:","Finally, when tsc is linting the codebase, it expects every code library that augments the EnvironmentVariables interface to include its typings. To do this, add each code library's types folder to every projects' tsconfig.json file that depends on code libraries:"]},{"i":"troubleshoot-issues-1","l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each environment variable registration that occurs and error messages if something went wrong:","[squide] The following environment variables has been registered: {...}","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Setup i18next","p":["Most Workleap's platform application are either already bilingual or will be in the future. To help feature teams deal with localized resources, Squide provides a native plugin designed to adapt the i18next library for modular applications.","The examples in this guide load all the resources from single localized resources files. For a real Workleap application, you probably want to spread the resources into multiple files and load the files with a i18next backend plugin."]},{"l":"Setup the host application","p":["Let's start by configuring the host application. First, open a terminal at the root of the host application and install the following packages:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Register the i18nextPlugin","p":["Then, update the host application boostrapping code to register an instance of the i18nextplugin with the FireflyRuntime instance:","In the previous code sample, upon creating an i18nextPlugin instance, the user language is automatically detected using the plugin.detectUserLanguage function. Applications should always detect the user language at bootstrapping, even if the current language is expected to be overriden by a preferred language setting once the user session has been loaded."]},{"l":"Define the localized resources","p":["Next, create the localized resource files for the en-US and fr-CA locales:"]},{"l":"Register an i18next instance","p":["Then, update the host application local module's register function to create and register an i18next instance with the retrieved i18nextPlugin instance. Due to how the internals of i18next works, each module (including the host application) must create its own instance of the third-party library. i18nextPlugin will handle synchronizing the language changes across all i18next instances:","In the previous code sample, notice that the i18next instance has been initialized with the current language of the i18nextPlugin instance by providing the lng option. If the user language has been detected during bootstrapping, the i18next instance will then be initialized with the user language which has been deduced from either a ?language querystring parameter or the user navigator language settings. Otherwise, the application instance will be initialized with the fallback language, which is en-US for this guide."]},{"l":"Localize the home page resources","p":["Then, update the HomePage component to use the newly created localized resource:"]},{"l":"Update the webpack configurations","p":["Finally, update the webpack development and build configurations to activate the i18next feature. Enabling this feature will configure the i18next libraries as shared dependencies:"]},{"l":"Setup a remote module","p":["First, open a terminal at the root of the remote module application and install the following packages:"]},{"i":"define-the-localized-resources-1","l":"Define the localized resources","p":["Then, create the localized resource files for the en-US and fr-CA locales:","Notice that this time, a standard navigationItems namespace has been added to the resource files. The resources in the navigationItems namespace will be used later on to localize the navigation items labels."]},{"i":"register-an-i18next-instance-1","l":"Register an i18next instance","p":["Then, update the remote module's register function to create and register an instance of i18next with the i18nextPlugin plugin instance. Similarly to the host application, due to how the internals of i18next works, this local module requires to register its own instance of the third-party library:"]},{"l":"Localize the navigation item labels","p":["Then, localize the navigation items labels using the I18nextNavigationItemLabel component. Since this example resources are in the navigationItems namespace, there's no need to specify a namespace property on the components as it will be inferred:"]},{"l":"Localize the page resources","p":["Then, update the Page component to use the newly created localized resource:"]},{"i":"update-the-webpack-configurations-1","l":"Update the webpack configurations","p":["Finally, update the webpack development and build configurations to activate the i18next feature. Enabling this feature will configure the i18next libraries as shared dependencies:"]},{"l":"Setup a local module","p":["Follow the same steps as for a remote module."]},{"l":"Integrate a backend language setting","p":["For many applications, the displayed language is expected to be derived from an application specific user \"preferred language\" setting stored in a remote database. Therefore, the frontend remains unaware of this setting value until the user session is loaded.","Hence, the strategy to select the displayed language should be as follow:","Use the language detected at bootstrapping for anonymous users (with the detectUserLanguage function).","Upon user authentication and session loading, if a \"preferred language\" setting is available from the session data, update the displayed language to reflect this preference.","This strategy can be implemented with the help of the useChangeLanguage and useProtectedDataQueries hooks:","The previous code sample assumes that your @sample/shared project includes the primitives created in the Add authentication guide as well as the session Mock Server Worker request handlers."]},{"l":"Use the Trans component","p":["The Trans component is useful for scenarios involving interpolation to render a localized resources. To use the Trans component with Squide, pair it with an i18next instance retrieved from useI18nextInstance hook:","The Trans component can also be used without the t function by including a namespace to the i18nKey property value:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script. The homepage and the navigation items should render the english ( en-US) resources. Then append ?language=fr-CA to the URL. The homepage and the navigation items should now render the french ( fr-CA) resources."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each i18next instance that is being registered and another log everytime the language is changed:","[squide] Registered a new i18next instance with key remote-module.","[squide] The language has been changed to fr-CA.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Setup Honeycomb","p":["Before going forward with this guide, make sure that you migrated to v9.3.","To monitor application performance, Workleap has adopted Honeycomb, a tool that helps teams manage and analyze telemetry data from distributed systems. Built on OpenTelemetry, Honeycomb provides a robust API for tracking frontend telemetry.","Honeycomb's in-house HoneycombWebSDK includes great default instrumentation. However, this instrumentation has to be extended to capture traces specific to Squide features. To facilitate this, Squide provides the registerHoneycombInstrumentation function."]},{"l":"Setup the host application","p":["Let's start by configuring the host application. First, open a terminal at the root of the host application and install the following packages:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Register instrumentation","p":["Then, update the host application bootstrapping code to register Honeycomb instrumentation:","Avoid using /.+/g, in production, as it could expose customer data to third parties. Instead, ensure you specify values that accurately matches your application's backend URLs.","We recommend using an OpenTelemetry collector over an ingestion API key, as API keys can expose Workleap to potential attacks.","With instrumentation in place, a few traces are now available \uD83D\uDC47"]},{"l":"Bootstrapping flow","p":["The performance of an application bootstrapping flow can now be monitored:","Bootstrapping flow performance"]},{"l":"Deferred registration update","p":["When a deferred registration is updated, the performance of the operation can be monitored:","Deferred registration update performance"]},{"l":"Fetch requests","p":["Individual fetch request performance can be monitored from end to end:","Fetch instrumentation"]},{"l":"Document load","p":["The loading performance of the DOM can be monitored:","Document load instrumentation"]},{"l":"Unmanaged error","p":["When an unmanaged error occurs, it's automatically recorded:","Recorded error"]},{"i":"real-user-monitoring-rum","l":"Real User Monitoring (RUM)","p":["The default instrumentation will automatically track the appropriate metrics to display RUM information:","Largest Contentful Paint","Cumulative Layout Shift","Interaction to Next Paint"]},{"l":"Set custom user attributes","p":["Most application needs to set custom attributes on traces about the current user environment. To help with that, Squide expose the setGlobalSpanAttributes function.","Update your host application to include the setGlobalSpanAttributes function:","Now, every trace recorded after the session initialization will include the custom attributes app.user_id:","Custom attributes"]},{"l":"Custom traces","p":["Squide does not provide a proprietary API for traces. Applications are expected to use the OpenTelemetry API to send custom traces to Honeycomb:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script. Render a page, then navigate to your Honeycomb instance. Go to the \"Query\" page and type name = squide-bootstrapping into the \"Where\" input. Run the query, select the \"Traces\" tab at the bottom of the page and view the detail of a trace. You should view the performance of your application bootstrapping flow."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Set the runtime mode to development mode or register the Honeycomb instrumentation in debug.","Open the DevTools console. You'll see a log entry for every for each dispatched event, along with multiple console outputs from Honeycomb's SDK. Squide's bootstrapping instrumentation listens to events to send Honeycomb traces. Most events should match an Honeycomb trace and vice versa.","[squide] Dispatching event squide-local-modules-registration-completed","[squide] Dispatching event squide-remote-modules-registration-completed","[squide] Dispatching event squide-public-data-fetch-started","[squide] Dispatching event squide-public-data-ready","@honeycombio/opentelemetry-web: Honeycomb link: ...","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Develop a module in isolation","p":["To develop their own independent module, a team should not need to install the host application or any other modules of the application they do not own. However, they should have a way to integrate their module with the application shell (e.g., RootLayout, RootErrorBoundary, etc..) while working in isolation.","To achieve this, the first step is to extract the application shell from the host application. There are various ways to accomplish this, but in this guide, we'll transform the host application into a monorepo and introduce a new local package named @sample/shell specifically for this purpose:"]},{"l":"Create a shell package","p":["The implementation details of the RootLayout, RootErrorBoundary and ModuleErrorBoundary components won't be covered by this guide as it already has been covered many times by other guides.","First, create a new package (we'll refer to ours as shell) and add the following fields to the package.json file:","Then, install the package dependencies and configure the new package with tsup.","Then, create an AppRouter component in the shell package to provide a reusable router configuration that can be shared between the host application and the isolated modules. This new AppRouter component should wrap the @squide/firefly AppRouter component:","Finally, create a local module to register the application shell. This module will be used by both the host application and the isolated modules:","This guide only covers the RootLayout, RootErrorBoundary and ModuleErrorBoundary components but the same goes for other shell assets such as an AuthenticationBoundary component."]},{"l":"Update the host application","p":["Now, let's revisit the host application by adding the new @sample/shell package as a dependency:","Then, integrate the AppRouter component from the @sample/shell package into the application:","And finally include the registerShell function to setup the RootLayout and RootErrorBoundary components as well as any other shell assets:"]},{"l":"Setup a remote module","p":["With the new shell package in place, we can now configure the remote module to be developed in isolation. The goal is to start the module development server and render the module pages with the same layout and functionalities as if it was rendered by the host application.","To begin, let's start by adding a dependency to the @sample/shell package:","Then, create the following files in the remote module application:"]},{"i":"indextsx","l":"index.tsx","p":["The index.tsx file is similar to the bootstrap.tsx file of an host application but, tailored for an isolated module. The key distinctions are that all the modules are registered as local modules, and a new registerDev function is introduced to register the development homepage (which will be covered in an upcoming section):"]},{"i":"apptsx","l":"App.tsx","p":["The App.tsx file uses the newly created AppRouter component to setup Squide's primitives with a React Router instance:"]},{"i":"devhometsx","l":"DevHome.tsx","p":["The DevHome component is the homepage when the remote module is developed in isolation:","To register the development homepage, create a new local module specifically for configuring the remote during isolated development:"]},{"l":"Add a new CLI script","p":["Next, add a new dev-isolated script to the package.json file to start the local development server in isolation:","If your project's package.json file does not already include the cross-env dependency, be sure to install cross-env as a development dependency.","The dev-isolated script is similar to the dev script but introduces an ISOLATED environment variable. This variable will be used by the webpack.dev.js file to conditionally configure the development server to either serve the module as an application for isolated development or as a remote endpoint by the host application through the /remoteEntry.js entry point."]},{"l":"Configure webpack","p":["First, open the public/index.html file created at the beginning of this guide and copy/paste the following HtmlWebpackPlugin template:","Then, open the .browserslist file and copy/paste the following content:"]},{"l":"Isolated environment configuration","p":["To configure webpack, open the webpack.dev.js file and update the configuration to incorporate the ISOLATED environment variable and the defineDevHostConfig function:","If you encounter issues configuring webpack, refer to the @workleap/webpack-configs documentation."]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the remote module in isolation by running the dev-isolated script. The application shell should wrap the pages of the module and the default page should be DevHome."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this section of the guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]},{"l":"Setup a local module","p":["Similarly to remote modules, local modules can also be set up for isolated development. The key difference is that the webpack.config.js file for a local module strictly serves the purpose of starting a development server for isolated development. Typically, local modules do not depend on webpack or Module Federation.","First, open a terminal at the root of the local module project and install the @squide/firefly-webpack-configs package and its dependencies:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM.","Then, add a peer dependency and a dev dependency to the @sample/shell package:","Then, create the following files in the local module application:"]},{"i":"indextsx-1","l":"index.tsx","p":["This file is similar to the index.tsx file of the remote module."]},{"i":"apptsx-1","l":"App.tsx","p":["This file is similar to the App.tsx file of the remote module."]},{"i":"devhometsx-and-registerdev","l":"DevHome.tsx and registerDev","p":["These files are similar to the dev/DevHome.tsx and dev/register.tsx files of the remote module."]},{"i":"configure-webpack-1","l":"Configure webpack","p":["First, open the public/index.html file and copy/paste the following HtmlWebpackPlugin template:","Then, open the .browserslist file and copy/paste the following content:","Then, open the swc.config.js file and copy/paste the following code:","Finally, open the webpack.config.js file and use the the defineDevHostConfig function to configure webpack:","If you encounter issues configuring webpack, refer to the @workleap/webpack-configs documentation."]},{"i":"add-a-new-cli-script-1","l":"Add a new CLI script","p":["Next, add a new dev-isolated script to the package.json file to start the local development server:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the remote module in isolation by running the dev-isolated script. The application shell should wrap the pages of the module and the default page should be DevHome."]},{"i":"troubleshoot-issues-1","l":"Troubleshoot issues","p":["If you are experiencing issues with this section of the guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Override a React context","p":["In a modular application, it's typical to configure various global React context at the root of the host application. These contexts are then used by the layouts and pages of the modules.","Let's explore a simple example using a BackgroundColorContext:","In the previous code samples, the host application provides a value for the BackgroundColorContext, and the ColoredPage component of the remote module uses this value to set its background color (to blue for this example)."]},{"l":"Override the context for the module","p":["Now, suppose the requirements change, and a page of the remote module must have a red background. The context can be overriden for that page by declaring a new provider directly in the routes registration:"]},{"l":"Extract an utility component","p":["Since there are multiple routes to setup with the new provider, an utility component can be extracted:"]},{"l":"Update a singleton dependency version","p":["This section only applies to federated applications (applications including remote modules).","Let's consider a more specific use case where the host application declares a ThemeContext from Workleap's new design system, Hopper:","In this scenario, Hopper's components are used throughout the entire application, including the modules. Moreover, @hopper/components is defined as a singleton shared dependency:","Now, consider a situation where Hopper releases a new version of the package that includes breaking changes, without a \"compatibility\" package to ensure backward compatility with the previous version.","To update the host application without breaking the modules, we recommend to temporary \"break\" the singleton shared dependency by loading two versions of the @hopper/components dependency in parallel (one for the host application and one for the modules that have not been updated yet):","As @hopper/components expose the ThemeContext, the context must be re-declared in each module until every part of the federated application has been updated to the latest version of @hopper/components:","Thankfully, React Router makes it very easy to declare contexts in a module."]}],[{"l":"Add a shared dependency","p":["This guide only applies to federated applications (applications including remote modules).","Shared dependencies is one of the most powerful concepts of Module Federation. However, mastering its configuration can be quite challenging. Failure to configure shared dependencies properly in a federated application using Module Federation can significantly impact both user and developer experiences.","Squide aims to simplify the configuration of shared dependencies by abstracting the shared dependencies necessary for building an application with React, React Router, and optionally MSW and i18next. Nevertheless, every federated application will inevitably have to configure additional custom shared dependencies.","For a comprehensive documentation of the Module Federation APIs, their functionality, and their benefits, please refer to this article."]},{"l":"Understanding singleton dependencies","p":["A singleton shared dependency does exactly what its name suggests: it loads a single instance of a dependency. This means that a dependency will be included in just one bundle file of the federated application."]},{"l":"Strict versioning","p":["Sometimes, a singleton shared dependency is paired with the strictVersion option:","When specified, the strictVersion option will generate a runtime error if a module attempts to load a version of the dependency that is incompatible with the specified version. It's often unnecessary to use a strict version, and omitting it provides greater flexibility when it comes time to update the shared dependency version."]},{"l":"Expected behaviors","p":["Please note that Squide's singleton dependency version resolution algorithm differs from the native Module Federation behavior. By default, Squide registers a runtime plugin that customize the resolution of shared dependencies."]},{"l":"Minor or patch version","p":["When the version difference between a host application and a remote module is a minor or patch version, the higher version of the dependency will be loaded. For example:","If the host application is on 10.1.0 and a remote module is on 10.1.1-> 10.1.1 will be loaded","If the host application is on 10.1.0 and a remote module is on 10.2.0-> 10.2.0 will be loaded"]},{"l":"Major version","p":["If the version difference between a host application and a remote module is a major version, once again, the higher version of the dependency will be loaded only if it's requested by the host application. For example:","If the host application is on 11.0.0 and a remote module is on 10.0.0-> 11.0.0 will be loaded","If the host application is on 10.0.0 and a remote module is on 11.0.0-> 10.0.0 will be loaded"]},{"l":"Additional examples","p":["Let's go through a few additional examples \uD83D\uDC47"]},{"l":"Example 1","p":["The version requested by remote-1 is selected because it only represents a minor difference from the version requested by the host application."]},{"l":"Example 2","p":["The version requested by the host application is selected because remote-1 is requesting a version with a major difference from the one requested by the host application."]},{"l":"Example 3","p":["The version requested by remote-2 is selected because remote-1 is requesting a version with a major difference from the one requested by the host application. Therefore, remote-2 requests the next highest version, which represents only a minor difference from the version requested by the host application."]},{"i":"what-should-be-configured-as-a-shared-dependency","l":"What should be configured as a shared dependency?","p":["Libraries matching the following criterias are strong candidates to be configured as shared dependencies:","Medium to large libraries that are used by multiple modules.","Libraries that requires a single instance to work properly (like react).","Libraries exporting React contexts."]},{"l":"Understanding eager dependencies","p":["An eager shared dependency becomes available as soon as the host application starts. In simple terms, it is included in the host application bundle rather than being loaded lazily when it is first requested.","The key point to remember about eager dependencies is that only one application or remote module should configure a shared dependency as eager. Otherwise, the dependency will be included in the bundle of the host application and of every remote module that set the dependency as eager."]},{"i":"what-should-be-configured-as-an-eager-dependency","l":"What should be configured as an eager dependency?","p":["Any shared dependency that must be loaded to bootstrap the application."]},{"l":"Default shared dependencies","p":["Since Squide has dependencies on React and React Router, the define* functions automatically configure shared dependencies for these packages by default, in addition to Squide own packages. The following shared dependencies are set as eager singleton by default:","react","react-dom","react-router-dom","@squide/core","@squide/react-router","@squide/module-federation","For the full shared dependencies configuration, have a look at the defineConfig.ts file on Github.","You can extend or override the default shared dependencies configuration."]},{"l":"Add custom shared dependencies","p":["To configure shared dependencies, use the sharedDependencies option of any define* function:","When a dependency is shared between a host application and a remote module, the sharing options must be configured on both ends:"]},{"l":"React context limitations","p":["For a React context to be provided by the host application and consumed by the remote modules, the library exporting the React context must be set as a singleton.","To troubleshoot a React context issue or find more information about the limitations, refer to the troubleshooting page."]},{"l":"React dependencies requirements","p":["react and react-dom dependencies must be configured as a singleton, otherwise either an error will be thrown at bootstrapping if the loaded react versions are incompatible, or features like useState will not work.","The react-router-dom dependency must as well be configured as a singleton because it relies on a global React context that needs to be declared in the host application and is consumed by remote modules."]},{"l":"Learn more","p":["To learn more about Module Federation shared dependencies read this article about the shared APIs and refer to this POC on GitHub."]}],[{"l":"Implement a custom logger","p":["Many applications must integrate with specific remote logging solutions such as Honeycomb and Azure Application Insights. To facilitate this integration, the shell runtime accepts any custom loggers implementing the Logger interface."]},{"l":"Create a custom logger class","p":["First, let's define a custom logger:","Then create a FireflyRuntime instance configured with an instance of the new CustomLogger:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the applications and open the developer tools, then, refresh the page. You should see the following console log message:"]}],[{"l":"Updating","p":["Migrate to firefly v9.0","Migrate to firefly v9.3"]}],[{"i":"migrate-to-firefly-v90","l":"Migrate to firefly v9.0","p":["This major version of @squide/firefly introduces TanStack Query as the official library for fetching the global data of a Squide's application and features a complete rewrite of the AppRouter component, which now uses a state machine to manage the application's bootstrapping flow.","Prior to v9.0, Squide applications couldn't use TanStack Query to fetch global data, making it challenging for Workleap's applications to keep their global data in sync with the server state. With v9.0, applications can now leverage custom wrappers of the TanStack Query's useQueries hook to fetch and keep their global data up-to-date with the server state. Additionally, the new deferred registrations update feature allows applications to even keep their conditional navigation items in sync with the server state.","Finally, with v9.0, Squide's philosophy has evolved. We used to describe Squide as a shell for federated applications. Now, we refer to Squide as a shell for modular applications. After playing with Squide's local module feature for a while, we discovered that Squide offers significant value even for non-federated applications, which triggered this shift in philosophy."]},{"l":"Breaking changes"},{"l":"Removed","p":["The useAreModulesRegistered hook has been removed, use the useIsBootstrapping hook instead.","The useAreModulesReady hook has been removed, use the useIsBootstrapping hook instead.","The useIsMswStarted hook has been removed, use the useIsBootstrapping hook instead.","The completeModuleRegistrations function as been removed use the useDeferredRegistrations hook instead.","The completeLocalModulesRegistrations function has been removed use the useDeferredRegistrations hook instead.","The completeRemoteModuleRegistrations function has been removed use the useDeferredRegistrations hook instead.","The useSession hook has been removed, define your own React context instead.","The useIsAuthenticated hook has been removed, define your own React context instead.","The sessionAccessor option has been removed from the FireflyRuntime options, define your own React context instead.","The ManagedRoutes placeholder has been removed, use PublicRoutes and ProtectedRoutes instead."]},{"l":"Renamed","p":["The setMswAsStarted function has been renamed to setMswIsReady.","A route definition $name option has been renamed to $id.","The registerRoute parentName option has been renamed to parentId."]},{"l":"Others","p":["The @squide/firefly package now takes a peerDependency on @tanstack/react-query.","The @squide/firefly package doesn't takes a peerDependency on react-error-boundary anymore."]},{"l":"Removed support for deferred routes","p":["Deferred registration functions no longer support route registration; they are now exclusively used for registering navigation items. Since deferred registration functions can now be re-executed whenever the global data changes, registering routes in deferred registration functions no longer makes sense as updating the routes registry after the application has bootstrapped could lead to issues.","This change is a significant improvement for Squide's internals, allowing us to eliminate quirks like:","Treating unknown routes as protected: When a user initially requested a deferred route, Squide couldn't determine if the route was public or protected because it wasn't registered yet. As a result, for that initial request, the route was considered protected, even if the deferred registration later registered it as public.","Mandatory wildcard * route registration: Previously, Squide's bootstrapping would fail if the application didn't include a wildcard route.","Before:","Now:"]},{"l":"Conditional routes","p":["To handle direct access to a conditional route, each conditional route's endpoint should return a 403 status code if the user is not authorized to view the route. Those 403 errors should then be handled by the nearest error boundary."]},{"i":"plugins-constructors-now-requires-a-runtime-instance","l":"Plugin's constructors now requires a runtime instance","p":["Prior to this release, plugin instances received the current runtime instance through a _setRuntime function. This approach caused issues because some plugins required a reference to the runtime at instantiation. To address this, plugins now receive the runtime instance directly as a constructor argument.","Before:","Now:"]},{"l":"Plugins now registers with a factory function","p":["Prior to this release, the FireflyRuntime accepted plugin instances as options. Now, FireflyRuntime accepts factory functions instead of plugin instances. This change allows plugins to receive the runtime instance as a constructor argument.","Before:","Now:"]},{"l":"Rewrite of the AppRouter component","p":["This release features a full rewrite of the AppRouter component. The AppRouter component used to handle many concerns like global data fetching, deferred registrations, error handling and a loading state. Those concerns have been delegated to the consumer code, supported by the new useIsBootstrapping, usePublicDataQueries, useProtectedDataQueries and useDeferredRegistrations hooks.","Before:","Now:"]},{"l":"New hooks and functions","p":["A new useIsBoostrapping hook is now available.","A new useDeferredRegistrations hook is now available.","A new usePublicDataQueries hook is now available.","A new useProtectedDataQueries hook is now available.","A new isGlobalDataQueriesError function is now available.","A new registerPublicRoute function is now available."]},{"l":"Improvements","p":["Deferred registration functions now always receive a data argument.","Deferred registration functions now receives a new operations argument.","Navigation items now include a $canRender option, enabling modules to control whether a navigation item should be rendered."]},{"i":"new-id-option-for-navigation-items","l":"New $id option for navigation items","p":["Navigation items now supports a new $id option. Previously, most navigation item React elements used a key property generated by concatenating the item's level and index, which goes against React's best practices:","It wasn't that much of a big deal since navigation items never changed once the application was bootstrapped. Now, with the deferred registration functions re-executing when the global data changes, the registered navigation items can be updated post-bootstrapping. The new $id option allows the navigation item to be configured with a unique key at registration, preventing UI shifts.","The configured $id option is then passed as a key argument to the useRenderedNavigationItems rendering functions:","If no $id is configured for a navigation item, the key argument will be a concatenation of the level and index argument."]},{"l":"Migrate an host application","p":["A migration example from v8 to v9 is available for the wl-squide-monorepo-template.","Add a dependency to @tanstack/react-query. View example","Add an $id option to the navigation item registrations. View example","Add or update the AuthenticationBoundary component to use the new useIsAuthenticated hook. Global data fetch request shouldn't be throwing 401 error anymore when the user is not authenticated. View example","Convert all deferred routes into static routes. View example","Create a TanStackSessionManager class and the SessionManagerContext. Replace the session's deprecated hooks by creating the customs useSession and useIsAuthenticated hooks. View example","errorElement is removed and somewhat replaced by a root error boundary","fallbackElement becomes useIsBootstrapping","onCompleteRegistrations becomes useDeferredRegistrations","onLoadProtectedData+ isProtectedDataLoaded becomes useProtectedDataQueries","onLoadPublicData+ isPublicDataLoaded becomes usePublicDataQueries","Remove the sessionAccessor option from the FireflyRuntime instance. Update the BootstrappingRoute component to create a TanStackSessionManager instance and share it down the component tree using a SessionManagedContext provider. View example","Replace the ManagedRoutes placeholder with the new PublicRoutes and ProtectedRoutes placeholders. View example","The v9.0 release introduces several breaking changes affecting the host application code. Follow these steps to migrate an existing host application:","Transition to the new AppRouter component. View example","Update the AuthenticatedLayout component to use the new key argument. View example","Update the AuthenticatedLayout component to use the session manager instance to clear the session. Retrieve the session manager instance from the context defined in the BootstrappingRoute component using the useSessionManager hook. View example"]},{"l":"Root error boundary","p":["When transitioning to the new AppRouter component, make sure to nest the RootErrorBoundary component within the AppRouter component's render function.","Before:","Now:"]},{"l":"Migrate a module","p":["A migration example from v8 to v9 is available for the wl-squide-monorepo-template.","The changes in v9.0 have minimal impact on module code. To migrate an existing module, follow these steps:","Convert all deferred routes into static routes. View example","Add a $id option to the navigation item registrations. View example"]},{"l":"Isolated development","p":["If your module is set up for isolated development, ensure that you also apply the host application migration steps to your isolated setup."]}],[{"i":"migrate-to-firefly-v93","l":"Migrate to firefly v9.3","p":["Before following this guide, make sure that you migrated to v9.0."]},{"l":"Deprecation","p":["The registerLocalModules function has been deprecated, use the bootstrap function instead.","The registerRemoteModules function has been deprecated, use the bootstrap function instead.","The setMswAsReady function has been deprecated, use the bootstrap function instead."]},{"l":"Migrate an host application","p":["The bootstrap function is a new primitive that simplifies the bootstrapping of a Squide application. It replaces the registerLocalModules, registerRemoteModules and setMswAsReady functions."]},{"l":"Modules registration","p":["To update an application's module registration code, replace the registerLocalModules and registerRemoteModules functions with a call to the bootstrap function:","Before:","After:"]},{"l":"Mock Service Worker","p":["The MSW bootstrapping logic has been moved from user code to the bootstrap function. To update an application, replace the user code with the startMsw option of the bootstrap function.","Before:","After:"]}],[{"l":"Reference"},{"l":"Artefacts","p":["Packages"]},{"l":"API"},{"l":"Runtime","p":["FireflyRuntime class","RuntimeContext","useRuntime","useRuntimeMode","useRoutes","useNavigationItems","useLogger","usePlugin"]},{"l":"Registration","p":["bootstrap","registerLocalModules","registerRemoteModules","useDeferredRegistrations","mergeDeferredRegistrations"]},{"l":"Routing","p":["AppRouter","PublicRoutes","ProtectedRoutes","useRenderedNavigationItems","useIsBoostrapping","useRouteMatch","useIsRouteProtected","resolveRouteSegments","isNavigationLink"]},{"l":"Logging","p":["Logger","ConsoleLogger"]},{"l":"Messaging","p":["EventBus","useEventBusDispatcher","useEventBusListener"]},{"l":"Plugins","p":["Plugin"]},{"l":"webpack","p":["defineDevHostConfig","defineDevRemoteModuleConfig","defineBuildHostConfig","defineBuildRemoteModuleConfig"]},{"l":"TanStack Query","p":["usePublicDataQueries","useProtectedDataQueries","isGlobalDataQueriesError"]},{"l":"Mock Service Worker","p":["setMswAsReady"]},{"l":"i18next","p":["i18nextPlugin","getI18nextPlugin","useChangeLanguage","useCurrentLanguage","useI18nextInstance","I18nextNavigationItemLabel"]},{"l":"Honeycomb","p":["registerHoneycombInstrumentation","setGlobalSpanAttributes"]},{"l":"Environment variables","p":["EnvironmentVariablesPlugin","getEnvironmentVariablesPlugin","useEnvironmentVariable","useEnvironmentVariables"]},{"l":"Fakes","p":["Squide offers a collection of fake implementations designed to facilitate the set up of a module isolated environment.","LocalStorageSessionManager","ReadonlySessionLocalStorage"]}],[{"l":"Packages","p":["@squide/core","@squide/env-vars","@squide/fakes","@squide/firefly","@squide/firefly-honeycomb","@squide/firefly-webpack-configs","@squide/i18next","@squide/module-federation","@squide/msw","@squide/react-router","@squide/webpack-configs","A collection of fake implementations to facilitate the development of federated modules.","Add support for environment variables.","Add support for i18next.","Add support for Module Federation.","Add support for MSW.","Core functionalities of Squide.","Description","Honeycomb instrumentation for the Squide firefly technology stack.","Name","NPM","npm version","Specific implementation of the core functionalities to support React Router.","Squide for the firefly technology stack.","Utilities to configure webpack.","webpack configuration helpers for the Squide firefly technology stack."]}],[{"l":"FireflyRuntime class","p":["A runtime instance give modules access to functionalities such as routing, navigation, request handlers and logging."]},{"l":"Reference"},{"l":"Parameters","p":["options: An optional object literal of options:","mode: An optional mode to optimize Squide for production. Values are development(default) and production.","useMsw: An optional boolean value indicating whether or not to create the runtime with Mock Service Work(MSW) support.","loggers: An optional array of Logger instances.","plugins: An optional array of Plugin factory functions."]},{"l":"Methods","p":["registerRoute(route, options?): Register a route.","registerNavigationItem(navigationItem, options?): Register a navigation item.","getNavigationItems(menuId?): Retrieve the registered navigation items.","registerRequestHandlers(handlers): Register the MSW request handlers.","getPlugin(name): Retrieve the registered plugin by the specified name."]},{"l":"Getters","p":["mode: Retrieve the runtime mode.","routes: Retrieve the registered routes.","requestHandlers: Retrieve the registered MSW request handlers.","plugins: Retrieve the registered plugins.","logger: Retrieve the runtime logger.","eventBus: Retrieve the runtime event bus.","isMswEnabled: Indicate whether or not MSW is enabled."]},{"l":"Usage"},{"l":"Create a runtime instance"},{"l":"Change the runtime mode"},{"l":"Use Mock Service Worker"},{"l":"Register routes","p":["route: accept any properties of a React Router Route component with the addition of:","$id: An optional identifier for the route. Usually used to nest routes under a specific route.","$visibility: An optional visibility indicator for the route. Accepted values are public or protected.","options: An optional object literal of options:","hoist: An optional boolean value to register the route at the root of the router. The default value is false.","parentPath: An optional path of a parent route to register this new route under.","parentId: An optional id of a parent route to register this new route under."]},{"l":"Register an hoisted route","p":["Unlike a regular route, a hoisted route is added at the root of the router, outside of the host application's root layout, root error boundary and even root authentication boundary. This means that a hoisted route has full control over its rendering. To mark a route as hoisted, provide an hoist option to the route options.","By declaring a route as hoisted, other parts of the application will not be isolated anymore from this route's failures and the route will not be protected anymore by the application authenticated boundary.","To avoid breaking the entire application when an hoisted route encounters unhandled errors, it is highly recommended to declare a React Router's errorElement property for each hoisted route.","If the hoisted route requires an authentication, make sure to wrap the route with an authentication boundary or to handle the authentication within the route."]},{"l":"Register a public route","p":["When registering a route, a value can be provided indicating whether the route is public or protected. This is especially useful when dealing with code that fetches global data for protected routes(e.g. a session). Although a route definition accepts a $visibility value, we recommended using the runtime registerPublicRoute function to register a root public route instead.","A nested route can also be public:","When no $visibility indicator is provided, a route is considered protected."]},{"l":"Register a route with an id","p":["The registerRoute function accepts a parentId option, allowing a route to be nested under an existing parent route. When searching for the parent route matching the parentId option, the parentId will be matched against the $id option of every route.","A $id option should only be defined for routes that doesn't have a path like an error boundary or an authentication boundary."]},{"l":"Register nested routes","p":["React router nested routes enable applications to render nested layouts at various points within the router tree. This is quite helpful for modular applications as it enables composable and decoupled UI.","To fully harness the power of nested routes, the registerRoute function allows a route to be registered under any previously registered route, even if that route was registered by another module. The only requirement is that the parent route must have been registered with the registerRoute function.","When registering a new route with the registerRoute function, to render the route under a parent route, specify a parentPath option that matches the parent route's path option:","Or a parentId option that matches the parent route's $id option:","Learn more about using nested routes for modular tabs","Likewise any other React Router routes, the path option of a route rendered under an existing parent route must be an absolute path. For example, if a parent route path is /layout, the path option of a route rendered under that parent route and responding to the /page-1 url, should be /layout/page-1."]},{"l":"Retrieve routes","p":["The registered routes are accessible from a FireflyRuntime instance, but keep in mind that the preferred way to retrieve the routes is with the useRoutes hook."]},{"l":"Register navigation items","p":["item: NavigationSection | NavigationLink.","options: An optional object literal of options:","menuId: An optional menu id to associate the item with.","sectionId: An optional section id of a parent navigation section to register this new item under.","A Squide navigation item can either be a NavigationLink or a NavigationSection. Both types can be intertwined to create a multi-level menu hierarchy. A NavigationSection item is used to setup a new level while a NavigationLink define a link."]},{"l":"NavigationLink","p":["Accept any properties of a React Router Link component with the addition of:","$id: An optional identifier for the link. Usually used as the React element key property.","$label: The link text.","$canRender: An optional function accepting an object and returning a boolean indicating whether or not the link should be rendered.","$priority: An order priority affecting the position of the item in the menu (higher first)","$additionalProps: Additional properties to be forwarded to the link renderer."]},{"l":"NavigationSection","p":["$id: An optional identifier for the section. Usually used to nest navigation items under a specific section and as the React element key property.","$label: The section text.","$canRender: An optional function accepting an object and returning a boolean indicating whether or not the section should be rendered.","$priority: An order priority affecting the position of the item in the menu (higher first)","$additionalProps: Additional properties to be forwarded to the section renderer.","children: The section content.","We recommend always providing an $id option for a navigation item, as it ensures the menus doesn't flicker when deferred registrations are updated. Be sure to use a unique identifier.","Setup the host application to render navigation items"]},{"l":"Register a navigation item with an id","p":["The registerNavigationItem function accepts a sectionId option, allowing a navigation item to be nested under an existing navigation section. When searching the parent navigation section matching the sectionId option, the sectionId will be match against the $id option of every navigation item.","Additionally, when combined with the useRenderedNavigationItems function, the $id option will be used as the React element key property."]},{"l":"Register nested navigation items","p":["Similarly to nested routes, a navigation item can be nested under an existing section be specifying a sectionId option that matches the section's $id option:","Navigation items can also be nested by registering multipe items in a single registration block:"]},{"l":"Register navigation items for a specific menu","p":["By default, every navigation item registered with the registerNavigationItem function is registered as part of the root navigation menu. To register a navigation item for a different navigation menu, specify a menuId option when registering the items."]},{"l":"Sort navigation items","p":["A $priority option can be added to a navigation item to affect it's position in the menu. The sorting algorithm is as follow:","By default a navigation item have a priority of 0.","If no navigation item have a priority, the items are positioned according to their registration order.","If an item have a priority 0, the item will be positioned before any other items with a lower priority (or without an explicit priority value).","If an item have a priority 0, the item will be positioned after any other items with a higher priority (or without an explicit priority value)."]},{"l":"Use dynamic segments for navigation items","p":["Learn more about rendering navigation items with dynamic segments"]},{"l":"Use a React element as navigation item label"},{"l":"Style a navigation item"},{"l":"Open a navigation link in a new tab"},{"l":"Conditionally render a navigation item","p":["It's the responsibility of the code rendering the menu to execute the navigation items $canRender function and conditionally render the items based on the return value."]},{"l":"Render additional props on a navigation item","p":["It's the responsibility of the code rendering the menu to handle the additional properties."]},{"l":"Retrieve navigation items","p":["The registered navigation items are accessible from a FireflyRuntime instance, but keep in mind that the preferred way to retrieve the navigation items is with the useNavigationItems hook.","By default, the getNavigationItems will return the navigation items for the root menu:","To retrieve the navigation items for a specific navigation menu, provide a menuId:"]},{"l":"Register request handlers","p":["The registered handlers must be Mock Service Worker request handlers:","Learn more about setuping Mock Service Worker"]},{"l":"Retrieve request handlers"},{"l":"Log a message"},{"l":"Log a message to specific logger instances"},{"l":"Use the event bus"},{"l":"Register a plugin","p":["The plugin factory function receives the Runtime instance as parameter.","Learn more about plugins"]},{"l":"Retrieve a plugin","p":["Learn more about plugins"]}],[{"l":"RuntimeContext","p":["React context to share a FireflyRuntime instance between an host application and the modules."]},{"l":"Reference"},{"l":"Properties","p":["value: A FireflyRuntime instance."]},{"l":"Usage"},{"l":"Provide a runtime instance"},{"l":"Retrieve a runtime instance"}],[{"l":"useRuntime","p":["Retrieve a FireflyRuntime instance.","Consider using useRoutes, useNavigationItems, useLogger instead of useRuntime."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["A FireflyRuntime instance."]},{"l":"Usage"}],[{"l":"useRuntimeMode","p":["Retrieve the runtime mode."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["Either development or production."]},{"l":"Usage"}],[{"l":"useRoutes","p":["Retrieve the registered routes from the FireflyRuntime instance."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["An array of Route."]},{"l":"Usage"}],[{"l":"useNavigationItems","p":["Retrieve the registered navigation items from the FireflyRuntime instance."]},{"l":"Reference"},{"l":"Parameters","p":["options: An optional object literal of options:","menuId: An optional id to retrieve the navigation menu for a specific menu."]},{"l":"Returns","p":["An array of NavigationLink | NavigationSection."]},{"l":"NavigationLink","p":["Accept any properties of a React Router Link component with the addition of:","$id: An optional identifier for the link. Usually used as the React element key property.","$label: The link label. Could either by a string or a ReactNode.","$canRender: An optional function accepting an object and returning a boolean indicating whether or not the link should be rendered.","$additionalProps: An optional object literal of additional props to apply to the link component."]},{"l":"NavigationSection","p":["$id: An optional identifier for the section. Usually used to nest navigation items under a specific section and as the React element key property.","$label: The section label. Could either by a string or a ReactNode.","$canRender: An optional function accepting an object and returning a boolean indicating whether or not the section should be rendered.","$additionalProps: An optional object literal of additional props to apply to the section component.","children: The section items."]},{"l":"Usage"},{"l":"Retrieve the items for the root menu"},{"l":"Retrieve the items for a specific menu"}],[{"l":"useLogger","p":["Retrieve a RuntimeLogger instance from the FireflyRuntime instance. The returned logger will log messages to all registered Logger instances."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["A RuntimeLogger instance."]},{"l":"Usage"}],[{"l":"useLoggers","p":["Retrieve a RuntimeLogger instance from the FireflyRuntime instance. The returned instance will log messages to the specified Logger instances."]},{"l":"Reference"},{"l":"Parameters","p":["names: The name of the logger instances to log messages to."]},{"l":"Returns","p":["A RuntimeLogger instance."]},{"l":"Usage"}],[{"l":"usePlugin","p":["Retrieve a plugin from the FireflyRuntime instance."]},{"l":"Reference"},{"l":"Parameters","p":["pluginName: The name of the plugin."]},{"l":"Returns","p":["A plugin instance if the plugin has been registered, otherwise an Error is thrown."]},{"l":"Usage"}],[{"l":"bootstrap","p":["Register local or remote modules and optionally start MSW. During the registration process, the modules' registration function will be invoked with a FireflyRuntime instance and an optional context object. To defer the registration of specific navigation items, a registration function can return an anonymous function.","A local module is a regular module that is part of the host application build and is bundled at build time, as opposed to a remote module which is loaded at runtime from a remote server.","A remote module is a module that is not part of the current build but is loaded at runtime from a remote server."]},{"l":"Reference"},{"l":"Parameters","p":["runtime: A FireflyRuntime instance.","options: An optional object literal of options:","localModules: An optional array of ModuleRegisterFunction.","remotes: An optional array of RemoteDefinition.","startMsw: An optional function to register MSW request handlers and start MSW service. This function is required if MSW is enabled.","context: An optional context object that will be pass to the registration function."]},{"l":"Returns","p":["A Promise object including LocalModuleRegistrationError and RemoteModuleRegistrationError if any error happens during the registration process."]},{"l":"LocalModuleRegistrationError","p":["error: The original Error object."]},{"l":"RemoteModuleRegistrationError","p":["remoteName: The name of the remote module that failed to load.","moduleName: The name of the module that Squide attempted to recover.","error: The original Error object."]},{"l":"Usage"},{"l":"Register a local module"},{"l":"Register a remote module"},{"l":"Start MSW"},{"l":"Provide a registration context"},{"l":"Handle registration errors"},{"l":"Defer the registration of navigation items","p":["Sometimes, data must be fetched to determine which navigation items should be registered by a given module. To address this, Squide offers a two-phase registration mechanism:","The first phase allows modules to register their navigation items that are not dependent on initial data(in addition to their routes and MSW request handlers when fake endpoints are available).","The second phase enables modules to register navigation items that are dependent on initial data. Such a use case would be determining whether a navigation item should be registered based on a feature flag. We refer to this second phase as deferred registrations.","To defer a registration to the second phase, a module registration function can return an anonymous function matching the DeferredRegistrationFunction type: (data, operation: register | update) = Promise | void.","Once the modules are registered, the deferred registration functions will be executed with the deferred data and register as the value for the operation argument. Afterward, whenever the deferred data changes, the deferred registration functions will be re-executed with the updated deferred data and update as the value for the operation argument.","Routes are always registered, but navigation items can be conditionally registered using a deferred registration function.","useDeferredRegistrations"]},{"l":"Use the deferred registration operation argument"},{"l":"Remote definition","p":["To ease the configuration of remote modules, make sure that you first import the RemoteDefinition type and assign it to your remote definitions array declaration."]},{"l":"name","p":["The name option of a remote definition must match the name option defined in the remote module ModuleFederationPlugin configuration.","If you are using either the Squide defineDevRemoteModuleConfig or defineBuildRemoteModuleConfig functions to add the ModuleFederationPlugin to the remote module webpack configuration object, then the remote module name is the second argument of the function.","In the following exemple, the remote module name is remote1."]}],[{"l":"registerLocalModules","p":["This function is deprecated, use the bootstrap function instead.","Register one or many local module(s). During the registration process, the specified registration function will be invoked with a FireflyRuntime instance and an optional context object. To defer the registration of specific navigation items, a registration function can return an anonymous function.","A local module is a regular module that is part of the host application build and is bundled at build time, as opposed to a remote module which is loaded at runtime from a remote server. Local modules are particularly valuable when launching a new product with an evolving business domain or when undergoing a migration from a monolithic application to a federated application."]},{"l":"Reference"},{"l":"Parameters","p":["registerFunctions: An array of ModuleRegisterFunction.","runtime: A FireflyRuntime instance.","options: An optional object literal of options:","context: An optional context object that will be pass to the registration function."]},{"l":"Returns","p":["A Promise object with an array of LocalModuleRegistrationError if any error happens during the registration."]},{"l":"LocalModuleRegistrationError","p":["error: The original Error object."]},{"l":"Usage"},{"l":"Register a local module"},{"l":"Defer the registration of navigation items","p":["Sometimes, data must be fetched to determine which navigation items should be registered by a given module. To address this, Squide offers a two-phase registration mechanism:","The first phase allows modules to register their navigation items that are not dependent on initial data(in addition to their routes and MSW request handlers when fake endpoints are available).","The second phase enables modules to register navigation items that are dependent on initial data. Such a use case would be determining whether a navigation item should be registered based on a feature flag. We refer to this second phase as deferred registrations.","To defer a registration to the second phase, a module registration function can return an anonymous function matching the DeferredRegistrationFunction type: (data, operation: register | update) = Promise | void.","Once the modules are registered, the deferred registration functions will be executed with the deferred data and register as the value for the operation argument. Afterward, whenever the deferred data changes, the deferred registration functions will be re-executed with the updated deferred data and update as the value for the operation argument.","Routes are always registered, but navigation items can be conditionally registered using a deferred registration function.","useDeferredRegistrations"]},{"l":"Use the deferred registration operation argument"},{"l":"Handle registration errors"}],[{"l":"registerRemoteModules","p":["This function is deprecated, use the bootstrap function instead.","Register one or many remote module(s). During the registration process, the module register function will be invoked with a FireflyRuntime instance and an optional context object. To defer the registration of navigation items, a registration function can return an anonymous function.","A remote module is a module that is not part of the current build but is loaded at runtime from a remote server."]},{"l":"Reference"},{"l":"Parameters","p":["remotes: An array of RemoteDefinition.","runtime: A FireflyRuntime instance.","options: An optional object literal of options:","context: An optional context object that will be pass to the registration function."]},{"l":"Returns","p":["A Promise object with an array of RemoteModuleRegistrationError if any error happens during the registration."]},{"l":"RemoteModuleRegistrationError","p":["remoteName: The name of the remote module that failed to load.","moduleName: The name of the module that Squide attempted to recover.","error: The original Error object."]},{"l":"Usage"},{"l":"Register a remote module"},{"l":"Defer the registration of navigation items","p":["Sometimes, data must be fetched to determine which navigation items should be registered by a given module. To address this, Squide offers a two-phase registration mechanism:","The first phase allows modules to register navigation items that are not dependent on initial data (in addition to their routes and MSW request handlers when fake endpoints are available).","The second phase enables modules to register navigation items that are dependent on initial data. Such a use case would be determining whether a navigation item should be registered based on a feature flag. We refer to this second phase as deferred registrations.","To defer a registration to the second phase, a module registration function can return an anonymous function matching the DeferredRegistrationFunction type: (data, operation: register | update) = Promise | void.","Once the modules are registered, the deferred registration functions will be executed with the deferred data and register as the value for the operation argument. Afterward, whenever the deferred data changes, the deferred registration functions will be re-executed with the updated deferred data and update as the value for the operation argument.","Routes are always registered, but navigation items can be conditionally registered using a deferred registration function.","useDeferredRegistrations"]},{"l":"Use the deferred registration operation argument"},{"l":"Handle registration errors"},{"l":"Remote definition","p":["To ease the configuration of remote modules, make sure that you first import the RemoteDefinition type and assign it to your remote definitions array declaration."]},{"l":"name","p":["The name option of a remote definition must match the name option defined in the remote module ModuleFederationPlugin configuration.","If you are relying on either the Squide defineDevRemoteModuleConfig or defineBuildRemoteModuleConfig functions to add the ModuleFederationPlugin to the remote module webpack configuration object, then the remote module name is the second argument of the function.","In the following exemple, the remote module name is remote1."]}],[{"l":"useDeferredRegistrations","p":["Register the modules deferred registration functions when the global data is initially fetched or update the deferred registration functions whenever the global data change.","This hook should always be used in combination with deferred registration functions and with either the usePublicDataQueries hook or the useProtectedDataQueries hook (can be both)."]},{"l":"Reference"},{"l":"Parameters","p":["data: An object literal of data that will be passed to the deferred registration functions.","options: An optional object literal of options:","onError: An optional function receiving an DeferredRegistrationsErrorsObject object as an argument."]},{"l":"DeferredRegistrationsErrorsObject","p":["localModuleErrors: An array of errors that occured during the deferred registrations of local modules.","error: The original Error object.","remoteModuleErrors: An array of errors that occured during the deferred registrations of remote modules.","remoteName: The name of the remote module that failed to load.","moduleName: The name of the module that Squide attempted to recover."]},{"l":"Returns","p":["Nothing"]},{"l":"Usage"},{"l":"Register or update deferred registrations"},{"l":"Handle registration errors"}],[{"l":"mergeDeferredRegistrations","p":["Utility function that takes an array of deferred registration functions and returns a single function wrapping and merging all the provided deferred registration functions.","If the provided array contains undefined values, they will safely be ignored."]},{"l":"Reference"},{"l":"Parameters","p":["candidates: An array of deferred registration functions."]},{"l":"Returns","p":["A function or undefined:","If multiple deferred registration functions are provided, a single function wrapping and merging all the provided deferred registration functions is returned.","If a single deferred registration function is provided, the provided function is returned.","If no deferred registration functions are provided, undefined is returned."]},{"l":"Usage"}],[{"l":"AppRouter","p":["A component that sets up Squide's primitives with a React Router instance.","The AppRouter component is required for any Squide application."]},{"l":"Reference"},{"l":"Properties","p":["waitForMsw: A boolean value indicating whether or not Squide should delay the rendering of the requested page until the Mock Service Worker request handlers are registered.","waitForPublicData: An optional boolean value indicating whether or not Squide should delay the rendering of the requested page until the public data is ready. The default value is false.","waitForProtectedData: An optional boolean value indicating whether or not Squide should delay the rendering of the requested page until the protected data is ready. The default value is false.","children: A render function defining a RouterProvider component with rootRoute, registeredRoutes and routerProviderProps."]},{"l":"Usage"},{"l":"Define a router provider","p":["The rootRoute component provided as an argument to the AppRouter rendering function must always be rendered as a parent of the registeredRoutes."]},{"l":"Define a loading component","p":["A BootstrappingRoute component is introduced in the following example because the useIsBootstrapping hook must be rendered as a child of rootRoute."]},{"l":"Define a root error boundary","p":["A React Router errorElement retrieves the current error using the useRouteError hook.","The root error boundary should always wrap the registeredRoutes and, when application, the BootstrapingRoute component."]},{"l":"Delay rendering until MSW is ready"},{"l":"Delay rendering until the public data is ready","p":["A BootstrappingRoute component is introduced in the following example because the usePublicDataQueries hook must be rendered as a child of rootRoute."]},{"l":"Delay rendering until the protected data is ready","p":["A BootstrappingRoute component is introduced in the following example because the useProtectedDataQueries hook must be rendered as a child of rootRoute."]}],[{"l":"PublicRoutes","p":["A placeholder indicating where in the routing tree should the public routes be rendered. The PublicRoutes placeholder concept is similar to React Router's outlet, it's a pipeline to inject routes at a predetermined location.","A public route is a route with a public visibility that is not hoisted or nested with either a parentPath or parentId option."]},{"l":"Reference"},{"l":"Properties","p":["None"]},{"l":"Usage","p":["The route defining the PublicRoutes placeholder must be hoisted; otherwise, there will be an infinite loop as the PublicRoutes placeholder will render within itself."]}],[{"l":"ProtectedRoutes","p":["A placeholder indicating where in the routing tree should the protected routes be rendered. The ProtectedRoutes placeholder concept is similar to React Router's outlet, it's a pipeline to inject routes at a predetermined location.","A protected route is a route with a protected visibility that is not hoisted or nested with either a parentPath or parentId option."]},{"l":"Reference"},{"l":"Properties","p":["None"]},{"l":"Usage","p":["The route defining the ProtectedRoutes placeholder must be hoisted; otherwise, there will be an infinite loop as the ProtectedRoutes placeholder will render within itself."]}],[{"l":"useIsBootstrapping","p":["Indicate whether the application is currently being bootstrapped, such as registering modules, handling deferred registrations, preparing Mock Service Worker, fetching global data, etc."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["A boolean value indicating whether or not the application is bootstrapping."]},{"l":"Usage","p":["A BootstrappingRoute component is introduced in the following example because this hook must be rendered as a child of rootRoute."]}],[{"l":"useRenderedNavigationItems","p":["Recursively parse a navigation items structure to transform the items into React Elements.","The useNavigationItems hook returns the navigation items tree structure as is, meaning the consumer has to recursively parse the structure to transform the items into actual React Elements.","As it's a non-trivial process, Squide provides this utility hook."]},{"l":"Reference"},{"l":"Parameters","p":["navigationItems: An array of NavigationLink | NavigationSection to render.","renderItem: A function to render a link from a navigation item","renderSection: A function to render a section from a collection of items."]},{"l":"NavigationLink","p":["Accept any properties of a React Router Link component with the addition of:","$id: An optional identifier for the link. Usually used as the React element key property.","$label: The link label. Could either by a string or a ReactNode.","$canRender: An optional function accepting an object and returning a boolean indicating whether or not the link should be rendered.","$additionalProps: An optional object literal of additional props to apply to the link component."]},{"l":"NavigationSection","p":["$id: An optional identifier the section. Usually used to nest navigation items undern a specific section and as the React element key property.","$label: The section label. Could either by a string or a ReactNode.","$canRender: An optional function accepting an object and returning a boolean indicating whether or not the section should be rendered.","$additionalProps: An optional object literal of additional props to apply to the section component.","children: The section items."]},{"l":"Returns","p":["An array of ReactElement."]},{"l":"Usage"},{"l":"Render nested items","p":["We recommend always providing an $id option for a navigation item, as it ensures the menus doesn't flicker when deferred registrations are updated. Be sure to use a unique key.","When no $id option is provided, a default key argument is computed based on the index and level properties. While this works in most cases, the default key cannot guarantee that the menu won't flicker during updates."]},{"l":"Render dynamic segments","p":["The to option of a navigation item can include dynamic segments (/user-profile/:userId), enabling the rendering of dynamic routes based on contextual values. To resolve a route dynamic segments, use the resolveRouteSegments function."]}],[{"l":"useRouteMatch","p":["Execute React Router's matching algorithm against Squide's routes registry and a given location to determine if any route match the location."]},{"l":"Reference"},{"l":"Parameters","p":["locationArg: The location to match the route paths against.","options: An optional object literal of options:","throwWhenThereIsNoMatch: Whether or not to throw an Error if no route match locationArg."]},{"l":"Returns","p":["A Route object if there's a matching route, otherwise if throwWhenThereIsNoMatch is enabled and no route match the given location, an Error is thrown.","If throwWhenThereIsNoMatch is disabled and there's no route matching locationArg, undefined is returned."]},{"l":"Usage"},{"l":"Using useLocation"},{"i":"using-windowlocation","l":"Using window.location"}],[{"l":"resolveRouteSegments","p":["Replace a route segments (paths starting with :) with the provided values. For a value to be applied to a segment, the value key must match the segment minus the :."]},{"l":"Reference"},{"l":"Parameters","p":["to: A route with segments.","values: An object literal of segment values."]},{"l":"Returns","p":["The resolved route."]},{"l":"Usage"}],[{"l":"useIsRouteProtected","p":["Determine whether or not a route is considered as protected.","To take advantage of this hook, make sure to add a $visibility hint to your public pages."]},{"l":"Reference"},{"l":"Parameters","p":["route: A Route object."]},{"l":"Returns","p":["A boolean value indicating whether or not the matching route is protected."]},{"l":"Usage"}],[{"l":"isNavigationLink","p":["Indicate whether or not a navigation item is a NavigationLink. This utility is particularly handy when rendering a menu with nested items."]},{"l":"Reference"},{"l":"Parameters","p":["item: A navigation item rendering props."]},{"l":"Returns","p":["A boolean value indicating whether or not the navigation item should be rendered as a link."]},{"l":"Usage"}],[{"l":"ConsoleLogger","p":["A basic console logger."]},{"l":"Reference"},{"l":"Parameters","p":["logLevel: An optional minimum level for the logger to output a log entry to the console (default is LogLevel.debug)."]},{"l":"Usage"},{"l":"Log everything"},{"l":"Only log errors","p":["To restrict the logs to error or critical, change the minimum log level to error:"]}],[{"l":"Logger","p":["An abstract base class to define a logger."]},{"l":"Usage"},{"l":"Define a custom logger"}],[{"l":"EventBus","p":["A basic implementation of a pub/sub mechanism enabling loosely coupled between the host application and the modules."]},{"l":"Reference"},{"l":"Parameters","p":["options: An optional object literal of options:","logger: An optional logger to facilitate debugging."]},{"l":"Methods","p":["addListener(eventName, callback, options?): Register the callback event listener for eventName.","removeListener(eventName, callback, options?): Remove the callback event listener for eventName.","dispatch(eventName, payload?): Dispatch an event to the listeners of eventName."]},{"l":"Usage"},{"l":"Create an event bus instance"},{"l":"Add a listener","p":["When possible, prefer useEventBusListener to eventBus.addListener."]},{"l":"Remove a listener"},{"l":"Dispatch an event","p":["When possible, prefer useEventBusDispatcher to eventBus.dispatch."]}],[{"l":"useEventBusDispatcher","p":["Retrieve an EventBus instance from the FireflyRuntime instance provided by RuntimeContext and provide a function to dispatch an event."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["A dispatch function: (eventName: string, payload?: {}) = void."]},{"l":"Usage"}],[{"l":"useEventBusListener"},{"l":"Reference"},{"l":"Parameters","p":["eventName: The name of the event to listen for.","callback: A function to be executed when a event matching the provided name is dispatched.","options: An optional object literal of options:","once: Whether or not the event listener should be automatically removed once an event as been handled."]},{"l":"Returns","p":["Nothing"]},{"l":"Usage"}],[{"l":"Plugin","p":["An abstract base class to define a plugin."]},{"l":"Protected members","p":["_runtime: Access the plugin Runtime instance."]},{"l":"Getters","p":["name: Return the name of the plugin."]},{"l":"Usage"},{"l":"Define a plugin"},{"l":"Register a plugin"},{"l":"Use a plugin runtime instance"},{"l":"Retrieve a plugin from a runtime instance"},{"l":"Retrieve a plugin with a custom function","p":["We recommend pairing a plugin definition with a custom function to retrieve the plugin from a runtime instance.","Retrieving a plugin with a custom function doesn't require the consumer to remember the plugin name, and has the upside of inferring the typings."]}],[{"l":"defineDevHostConfig","p":["Creates a webpack configuration object that is adapted for a Squide host application in development mode.","This function is a wrapper built on top of @workleap/web-configs. Make sure to read the defineDevConfig documentation first."]},{"l":"Reference"},{"l":"Parameters","p":["swcConfig: An SWC configuration object.","port: The host application port.","remotes: An array of RemoteDefinition(view the Remote definition section).","options: An optional object literal of options:","Accepts most of webpack definedDevConfig predefined options.","htmlWebpackPluginOptions: An optional object literal accepting any options of the HtmlWebpackPlugin.","features: An optional object literal of feature switches to define additional shared dependencies.","i18next: Whether or not to add @squide/i18next as a shared dependency.","sharedDependencies: An optional object literal of additional (or updated) module federation shared dependencies.","moduleFederationPluginOptions: An optional object literal of ModuleFederationPlugin options."]},{"l":"Returns","p":["A webpack configuration object tailored for a Squide host application in development mode."]},{"l":"Default shared dependencies","p":["The defineDevHostConfig function will add the following shared dependencies as singleton by default:","react","react-dom","react-router-dom","@squide/core","@squide/react-router","@squide/module-federation","@squide/msw","For the full shared dependencies configuration, have a look at the defineConfig.ts file on Github."]},{"l":"Usage"},{"l":"Define a webpack config"},{"l":"Activate optional features","p":["Features must be activated on the host application as well as every remote module."]},{"l":"Specify additional shared dependencies","p":["Additional shared dependencies must be configured on the host application as well as every remote module."]},{"l":"Extend a default shared dependency","p":["In the previous code sample, the react shared dependency will be augmented with the strictVersion option. The resulting shared dependency will be:"]},{"l":"Override a default shared dependency","p":["In the previous code sample, the react shared dependency singleton option will be overrided by the newly provided value. The resulting shared dependency will be:"]},{"l":"Customize module federation configuration","p":["While you could customize the ModuleFederationPlugin configuration by providing your own object literal through the moduleFederationPluginOptions option, we recommend using the defineHostModuleFederationPluginOptions(options) function as it will take care of merging the custom options with the default plugin options.","applicationName: The host application name.","moduleFederationPluginOptions: An object literal of ModuleFederationPlugin options."]},{"l":"Remote definition"},{"l":"name","p":["The name option of a remote definition must match the name option defined in the remote module ModuleFederationPlugin configuration.","If you are relying on the Squide defineDevRemoteModuleConfig function to add the ModuleFederationPlugin to the remote module webpack configuration object, then the remote module name is the second argument of the function.","In the following exemple, the remote module name is remote1."]},{"l":"url","p":["The url option of a remote definition must match the publicPath of the remote module webpack configuration object.","In the following exemple, the remote module publicPath is http://localhost:8081.","The publicPath is built from the provided host and port values. Therefore, if the port value is 8081, then the generated publicPath would be http://localhost:8081:"]}],[{"l":"defineDevRemoteModuleConfig","p":["Creates a webpack configuration object that is adapted for a Squide remote module application in development mode.","This function is a wrapper built on top of @workleap/web-configs. Make sure to read the defineDevConfig documentation first."]},{"l":"Reference"},{"l":"Parameters","p":["swcConfig: An SWC configuration object.","applicationName: The remote module application name.","port: The remote module application port.","options: An optional object literal of options:","Accepts most of webpack definedDevConfig predefined options.","features: An optional object literal of feature switches to define additional shared dependencies.","i18next: Whether or not to add @squide/i18next as a shared dependency.","sharedDependencies: An optional object literal of additional (or updated) module federation shared dependencies.","moduleFederationPluginOptions: An optional object literal of ModuleFederationPlugin options."]},{"l":"Returns","p":["A webpack configuration object tailored for a Squide remote module application in development mode."]},{"l":"Conventions","p":["To fulfill Squide remote module requirements, the defineDevRemoteModuleConfig function will pre-configure the ModuleFederationPlugin with the following filename and exposes properties.","If the remote module port is 8081, the remote module bundle is available at http://localhost:8081/remoteEntry.js."]},{"l":"Default shared dependencies","p":["The defineDevRemoteModuleConfig function will add the following shared dependencies as singleton by default:","react","react-dom","react-router-dom","@squide/core","@squide/react-router","@squide/module-federation","@squide/msw","For the full shared dependencies configuration, have a look at the defineConfig.ts file on Github."]},{"l":"Usage"},{"l":"Define a webpack config"},{"l":"Activate additional features","p":["Features must be activated on the host application as well as every remote module."]},{"l":"Specify additional shared dependencies","p":["Additional shared dependencies must be configured on the host application as well as every remote module."]},{"l":"Extend a default shared dependency","p":["In the previous code sample, the react shared dependency will be augmented with the newly provided strictVersion option. The resulting shared dependency will be:"]},{"l":"Override a default shared dependency","p":["In the previous code sample, the react shared dependency singleton option will be overrided by the newly provided value. The resulting shared dependency will be:"]},{"l":"Customize module federation configuration","p":["While you could customize the ModuleFederationPlugin configuration by providing your own object literal through the moduleFederationPluginOptions option, we recommend using the defineRemoteModuleFederationPluginOptions(applicationName, options) function as it will take care of merging the custom options with the default plugin options.","applicationName: The host application name.","moduleFederationPluginOptions: An object literal of ModuleFederationPlugin options."]},{"l":"Expose an additional module"}],[{"l":"defineBuildHostConfig","p":["Creates a webpack configuration object that is adapted for a Squide host application in build mode.","This function is a wrapper built on top of @workleap/web-configs. Make sure to read the defineBuildConfig documentation first."]},{"l":"Reference"},{"l":"Parameters","p":["swcConfig: An SWC configuration object.","remotes: An array of RemoteDefinition(view the Remote definition section).","options: An optional object literal of options:","Accepts most of webpack definedBuildConfig predefined options.","htmlWebpackPluginOptions: An optional object literal accepting any options of the HtmlWebpackPlugin.","features: An optional object literal of feature switches to define additional shared dependencies.","i18next: Whether or not to add @squide/i18next as a shared dependency.","sharedDependencies: An optional object literal of additional (or updated) module federation shared dependencies.","moduleFederationPluginOptions: An optional object literal of ModuleFederationPlugin options."]},{"l":"Returns","p":["A webpack configuration object tailored for a Squide host application in build mode."]},{"l":"Default shared dependencies","p":["The defineBuildHostConfig function will add the following shared dependencies as singleton by default:","react","react-dom","react-router-dom","@squide/core","@squide/react-router","@squide/module-federation","@squide/msw","For the full shared dependencies configuration, have a look at the defineConfig.ts file on GitHub."]},{"l":"Usage"},{"l":"Define a webpack config"},{"l":"Activate additional features","p":["Features must be activated on the host application as well as every remote module."]},{"l":"Specify additional shared dependencies","p":["Additional shared dependencies must be configured on the host application as well as every remote module."]},{"l":"Extend a default shared dependency","p":["In the previous code sample, the react shared dependency will be augmented with the strictVersion option. The resulting shared dependency will be:"]},{"l":"Override a default shared dependency","p":["In the previous code sample, the react shared dependency singleton option will be overrided by the newly provided value. The resulting shared dependency will be:"]},{"l":"Customize module federation configuration","p":["While you could customize the ModuleFederationPlugin configuration by providing your own object literal through the moduleFederationPluginOptions option, we recommend using the defineHostModuleFederationPluginOptions(options) function as it will take care of merging the custom options with the default plugin options.","applicationName: The host application name.","moduleFederationPluginOptions: An object literal of ModuleFederationPlugin options."]},{"l":"Remote definition"},{"l":"name","p":["The name option of a remote definition must match the name option defined in the remote module ModuleFederationPlugin configuration.","If you are relying on the Squide defineBuildRemoteModuleConfig function to add the ModuleFederationPlugin to the remote module webpack configuration object, then the remote module name is the second argument of the function.","In the following exemple, the remote module name is remote1."]},{"l":"url","p":["The url option of a remote definition must match the publicPath of the remote module webpack configuration object.","In the following exemple, the remote module publicPath is http://localhost:8081."]}],[{"l":"defineBuildRemoteModuleConfig","p":["Creates a webpack configuration object that is adapted for a Squide remote module application in build mode.","This function is a wrapper built on top of @workleap/web-configs. Make sure to read the defineBuildConfig documentation first."]},{"l":"Reference"},{"l":"Parameters","p":["swcConfig: An SWC configuration object.","applicationName: The remote module application name.","options: An optional object literal of options:","Accepts most of webpack definedDevConfig predefined options.","features: An optional object literal of feature switches to define additional shared dependencies.","i18next: Whether or not to add @squide/i18next as a shared dependency.","sharedDependencies: An optional object literal of additional (or updated) module federation shared dependencies.","moduleFederationPluginOptions: An optional object literal of ModuleFederationPlugin options."]},{"l":"Returns","p":["A webpack configuration object tailored for a Squide remote module application in build mode."]},{"l":"Conventions","p":["To fulfill Squide remote module requirements, the defineBuildRemoteModuleConfig function will pre-configure the ModuleFederationPlugin with the following filename and exposes properties.","If the remote module publicPath is http://localhost/8081, the remote module bundle is available at http://localhost:8081/remoteEntry.js."]},{"l":"Default shared dependencies","p":["The defineBuildRemoteModuleConfig function will add the following shared dependencies as singleton by default:","react","react-dom","react-router-dom","@squide/core","@squide/react-router","@squide/module-federation","@squide/msw","For the full shared dependencies configuration, have a look at the defineConfig.ts file on Github."]},{"l":"Usage"},{"l":"Define a webpack config"},{"l":"Activate additional features","p":["Features must be activated on the host application as well as every remote module."]},{"l":"Specify additional shared dependencies","p":["Additional shared dependencies must be configured on the host application as well as every remote module."]},{"l":"Extend a default shared dependency","p":["In the previous code sample, the react shared dependency will be augmented with the newly provided strictVersion option. The resulting shared dependency will be:"]},{"l":"Override a default shared dependency","p":["In the previous code sample, the react shared dependency singleton option will be overrided by the newly provided value. The resulting shared dependency will be:"]},{"l":"Customize module federation configuration","p":["While you could customize the ModuleFederationPlugin configuration by providing your own object literal through the moduleFederationPluginOptions option, we recommend using the defineRemoteModuleFederationPluginOptions(applicationName, options) function as it will take care of merging the custom options with the default plugin options.","applicationName: The host application name.","moduleFederationPluginOptions: An object literal of ModuleFederationPlugin options."]},{"l":"Expose an additional module"}],[{"l":"usePublicDataQueries","p":["Execute the specified Tanstack queries once the modules are ready and, if applicable, Mock Service Worker is also ready.","Use this hook to fetch public global data during the bootstrapping phase of your application. Avoid using it in product feature components."]},{"l":"Reference"},{"l":"Parameters","p":["queries: An array of QueriesOptions."]},{"l":"Returns","p":["An array of query response data. The order returned is the same as the input order."]},{"l":"Throws","p":["If an unmanaged error occur while performing any of the fetch requests, a GlobalDataQueriesError is thrown."]},{"l":"Usage"},{"l":"Define queries","p":["A BootstrappingRoute component is introduced in the following example because this hook must be rendered as a child of rootRoute."]},{"i":"waitforpublicdata--useisbootstrapping","l":"waitForPublicData & useIsBootstrapping","p":["To ensure the AppRouter component wait for the public data to be ready before rendering the requested route, set the waitForPublicData property to true.","Combine this hook with the useIsBootstrapping hook to display a loader until the public data is fetched and the application is ready."]},{"l":"Handle fetch errors","p":["This hook throws GlobalDataQueriesError instances, which are typically unmanaged and should be handled by an error boundary. To assert that an error is an instance of GlobalDataQueriesError, use the isGlobalDataQueriesError function."]}],[{"l":"useProtectedDataQueries","p":["Execute the specified Tanstack queries when the modules are ready, the active route is protected and, when applicable, Mock Service Worker is ready.","Use this hook to fetch protected global data during the bootstrapping phase of your application. Avoid using it in product feature components."]},{"l":"Reference"},{"l":"Parameters","p":["queries: An array of QueriesOptions.","isUnauthorizedError: A function that returns a boolean value indicating whether or not the provided error is a 401 status code."]},{"l":"Returns","p":["An array of query response data. The order returned is the same as the input order."]},{"l":"Throws","p":["If an unmanaged error occur while performing any of the fetch requests, a GlobalDataQueriesError is thrown."]},{"l":"Usage"},{"l":"Define queries","p":["A BootstrappingRoute component is introduced in the following example because this hook must be rendered as a child of rootRoute."]},{"i":"waitforprotecteddata--useisbootstrapping","l":"waitForProtectedData & useIsBootstrapping","p":["To ensure the AppRouter component wait for the protected data to be ready before rendering the requested route, set the waitForProtectedData property to true.","Combine this hook with the useIsBootstrapping hook to display a loader until the protected data is fetched and the application is ready."]},{"l":"Handle fetch errors","p":["This hook throws GlobalDataQueriesError instances, which are typically unmanaged and should be handled by an error boundary. To assert that an error is an instance of GlobalDataQueriesError, use the isGlobalDataQueriesError function."]},{"l":"Handle 401 response","p":["Unauthorized requests are a special case that shouldn't be handled by an error boundary, as this would cause an infinite loop with the application's authentication boundary.","To handle this, when the server returns a 401 status code, the useProtectedDataQueries hook instructs Squide to immediately render the page, triggering the authentication boundary, that will eventually redirect the user to a login page.","Since Squide manages this process behind the scenes, you only need to register an AuthenticationBoundary component and provide an isUnauthorizedError handler to the useProtectedDataQueries hook.","The registerHost function is registered as a local module of the host application."]}],[{"l":"isGlobalDataQueriesError","p":["Indicates whether or not an error is an instance of GlobalDataQueriesError.","GlobalDataQueriesError errors are thrown by either the usePublicDataQueries hook or the useProtectedDataQueries hook and should usually be handled by an error boundary."]},{"l":"Reference"},{"l":"Parameters","p":["error: An Error instance."]},{"l":"Returns","p":["A boolean value indicating whether or not the error is an instance of GlobalDataQueriesError."]},{"l":"Usage"},{"l":"Handle within an error boundary"},{"i":"handle-with-a-trycatch","l":"Handle with a try/catch"},{"l":"GlobalDataQueriesError","p":["message: The error message.","errors: An array of Error instances."]}],[{"l":"setMswAsReady","p":["This function is deprecated, use the bootstrap function instead.","Indicates to the AppRouter that Mock Service Worker is ready and the application can safely be rendered."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["Nothing"]},{"l":"Usage"}],[{"l":"i18nextPlugin","p":["A plugin to faciliate the integration of i18next in a modular application."]},{"l":"Reference"},{"l":"Parameters","p":["supportedLanguages: An array of languages supported by the application.","fallbackLanguage: The language to default to if none of the detected user's languages match any supported language.","queryStringKey: The querystring parameter lookup when detecting the user's language.","options: An optional object literal of options:","detection: An optional object literal accepting any LanguageDetector options."]},{"l":"Usage"},{"l":"Register the plugin"},{"l":"Retrieve the plugin instance","p":["Prefer using getI18nextPlugin when possible"]},{"l":"Register a i18next instance"},{"l":"Retrieve a i18next instance"},{"l":"Detect the user language","p":["Whenever a plugin instance is created, the user's language should always be detected immediatly using the detectUserLanguage function."]},{"l":"Retrieve the current language"},{"l":"Change the current language"},{"l":"Change the language detection order","p":["By default, the detection of the user's language is done first from the specified URL querystring parameter (?language in this example), then from the user's navigator language settings. The detection order can be changed by specifying a new value for the order detection option:"]},{"l":"Add an additional detection source"}],[{"l":"getI18nextPlugin","p":["Return an instance of i18nextPlugin from the list of plugins registered with a Runtime instance."]},{"l":"Reference"},{"l":"Parameters","p":["runtime: A runtime instance."]},{"l":"Returns","p":["An i18nextPlugin instance if the plugin has been registered, otherwise an Error is thrown."]},{"l":"Usage"}],[{"l":"useChangeLanguage","p":["Provide a function to change the current language of every i18next instance registered with the i18nextPlugin instance."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["A function to change the current language of an i18nextPlugin instance: (newLanguage) = void."]},{"l":"Usage"}],[{"l":"useCurrentLanguage","p":["Retrieve the current language of the i18nextPlugin instance."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["The current language of the i18nextPlugin instance."]},{"l":"Usage","p":["Or with a typed language:"]}],[{"l":"useI18nextInstance","p":["Retrieve a registered i18next instance from the i18nextPlugin instance."]},{"l":"Reference"},{"l":"Parameters","p":["key: An instance key."]},{"l":"Returns","p":["An i18next instance."]},{"l":"Usage"},{"l":"Retrieve an instance"},{"l":"Use with the useTranslation hook"},{"l":"Use with the Trans component","p":["Or without the t function:"]}],[{"l":"I18nextNavigationItemLabel","p":["A React component to localize the label of Squide navigation items."]},{"l":"Reference"},{"l":"Properties","p":["i18next: An i18next instance.","namespace: An optional namespace for the localized resource. If no namespace is provided, the default namespace is navigationItems.","resourceKey: A localized resource key."]},{"l":"Usage","p":["Or with a difference resources namespace:"]}],[{"l":"registerHoneycombInstrumentation","p":["Initializes an instance of Honeycomb Web SDK and registers custom instrumentation to monitor the performance of a Squide application."]},{"l":"Reference"},{"l":"Parameters","p":["runtime: A FireflyRuntime instance.","serviceName: Honeycomb application service name.","apiServiceUrls: A RegExp or string that matches the URLs of the application's backend services. If unsure, use the temporary regex /.+/g, to match all URLs.","options: An optional object literal of options:","endpoint: An optional URL to an OpenTelemetry collector. Either endpoint or apiKey option must be provided.","apiKey: An optional Honeycomb ingestion API key. Either endpoint or apiKey option must be provided.","instrumentations: An optional array of instrumentation instances.","spanProcessors: An optional array of span processor instances.","fetchInstrumentation: An optional object literal accepting any @opentelemetry/instrumentation-fetch options or false to disable instrumentation for fetch.","xmlHttpRequestInstrumentation: An optional object literal accepting any @opentelemetry/instrumentation-xml-http-request options. XHR instrumentation is disabled by default.","documentLoadInstrumentation: An optional object literal accepting any @opentelemetry/instrumentation-document-load options or false to disable instrumentation for fetch.","userInteractionInstrumentation: An optional object literal accepting any @opentelemetry/instrumentation-user-interaction options. User interactions instrumentation is disabled by default.","transformers: An optional array of configuration transformers.","debug: An optional boolean value indicating whether or not to log debug information to the console. true by default when the runtime mode is set to development."]},{"l":"Returns","p":["Nothing"]},{"l":"Default instrumentation","p":["The registerHoneycombInstrumentation function registers the following OpenTelemetry instrumentations by default:","@opentelemetry/instrumentation-fetch","@opentelemetry/instrumentation-document-load","For more details, refer to the registerHoneycombInstrumentation.ts file on GitHub."]},{"l":"Usage"},{"l":"Register instrumentation"},{"l":"Use an API key","p":["Prefer using an OpenTelemetry collector over an ingestion API key, as API keys can expose Workleap to potential attacks."]},{"l":"Customize backend URLs","p":["Avoid using /.+/g, in production as it could expose customer data to third parties.","Specify values for the apiServiceUrls argument that matches your application's backend URLs. For example, if your backend services are hosted at https://workleap.com/api:"]},{"l":"Register custom instrumentation"},{"l":"Register a span processor"},{"l":"Customize fetch instrumentation","p":["To extend or replace the default @opentelemetry/instrumentation-fetch options, provide a function that returns an object literal with the desired options. This function will receive an object literal containing the default options, which you can either extend or replace."]},{"l":"Disable fetch instrumentation"},{"l":"Customize DOM instrumentation","p":["To extend or replace the default @opentelemetry/instrumentation-document-load options, provide a function that returns an object literal with the desired options. This function will receive an object literal containing the default options, which you can either extend or replace."]},{"l":"Disable DOM instrumentation"},{"l":"Enable XHR instrumentation","p":["By default, @opentelemetry/instrumentation-xml-http-request is disabled. To enable this instrumentation, provide a function that returns an object literal with the desired options. This function will receive an object literal of default options, which you can extend or replace as needed."]},{"l":"Enable user interactions instrumentation","p":["By default, @opentelemetryinstrumentation-user-interaction is disabled. To enable this instrumentation, provide a function that returns an object literal with the desired options. This function will receive an object literal of default options, which you can extend or replace as needed."]},{"l":"Configuration transformers","p":["We do not guarantee that your configuration transformers won't break after an update. It's your responsibility to keep them up to date with new releases.","The predefined options are useful to quickly customize the default configuration of the Honeycomb Web SDK, but only covers a subset of the options. If you need full control over the configuration, you can provide configuration transformer functions through the transformers option of the registerHoneycombInstrumentation function. Remember, no locked in❤️✌️.","To view the default configuration of registerHoneycombInstrumentation, have a look at the registerHoneycombInstrumentation.ts file on GitHub."]},{"l":"Transformers"},{"l":"Execution context","p":["Generic transformers can use the runtime argument to gather additional information about their execution context, like the mode they are operating in:"]}],[{"l":"setGlobalSpanAttributes","p":["Set global attributes to be included in all Honeycomb Web traces."]},{"l":"Reference"},{"l":"Parameters","p":["attributes: The attributes to include in every trace."]},{"l":"Returns","p":["Nothing"]},{"l":"Usage"}],[{"l":"EnvironmentVariablesPlugin","p":["A plugin to faciliate the usage of environment variables in a modular application."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Usage","p":["Make sure to augment the EnvironmentVariables TypeScript interface with the variables of your module."]},{"l":"Register the plugin"},{"l":"Retrieve the plugin instance","p":["Prefer using getEnvironmentVariablesPlugin when possible"]},{"l":"Register an environment variable","p":["An environment variable with the same key can be registered multiple times (e.g., by multiple modules) as long as the value remains the same. If the value differs, an Error will be thrown."]},{"l":"Register multiple environment variables at once"},{"l":"Retrieve a single environment variable"},{"l":"Retrieve all the environment variables"}],[{"l":"getEnvironmentVariablesPlugin","p":["Return an instance of EnvironmentVariablesPlugin from the list of plugins registered with a Runtime instance."]},{"l":"Reference"},{"l":"Parameters","p":["runtime: A runtime instance."]},{"l":"Returns","p":["An EnvironmentVariablesPlugin instance if the plugin has been registered, otherwise an Error is thrown."]},{"l":"Usage"}],[{"l":"useEnvironmentVariable","p":["Retrieve a specific environment variable registered with the EnvironmentVariablesPlugin instance."]},{"l":"Reference"},{"l":"Parameters","p":["key: The environment variable key."]},{"l":"Returns","p":["The environment variable value if there's a match, otherwise an Error is thrown."]},{"l":"Usage"}],[{"l":"useEnvironmentVariables","p":["Retrieve all the environment variables registered with the EnvironmentVariablesPlugin instance."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["Returns all registered environment variables as an object literal. If no environment variables are registered, an empty object literal is returned."]},{"l":"Usage"}],[{"l":"LocalStorageSessionManager","p":["A local storage session manager (strictly for development purpose)."]},{"l":"Reference"},{"l":"Parameters","p":["options: An optional object literal of options:","key: An optional key identifying the session in localStorage."]},{"l":"Usage"},{"l":"Create a manager instance"},{"l":"Set a session"},{"l":"Get the current session"},{"l":"Clear the current session"}],[{"l":"ReadonlySessionLocalStorage","p":["Read a session object from the local storage (strictly for development purpose)."]},{"l":"Reference"},{"l":"Parameters","p":["options: An optional object literal of options:","key: An optional key identifying the session in localStorage."]},{"l":"Usage"},{"l":"Create an accessor instance"},{"l":"Get the current session"}],[{"l":"Troubleshooting"},{"l":"Set the runtime mode to development","p":["In an effort to optimize the development experience, Squide can be bootstrapped in development or production mode. To troubleshoot a persistent issue, make sure that the runtime mode is development:"]},{"l":"React context values are undefined","p":["If your application utilize remote modules and you are encountering undefined values when providing a React context from the host application and consuming the context in modules, it is likely due to two possible reasons: either you have two instances of React, or you have multiple instances of that React context.","To resolve this issue:","Ensure that the react and react-dom dependencies are shared as singletons between the host application and the remote modules. A React context value cannot be shared between different parts of an application that use different instances of React.","Confirm that the shared React context resides in a library shared as a singleton.","If you are using eager shared dependencies, ensure that ONLY the host application configures these dependencies as eager.","If the issue persists, update your host application and remote module's webpack build configuration with the optimize: false option. Afterward, build the bundles and serve them. Open a web browser, access the DevTools, switch to the Network tab (ensure that JS files are listed), navigate to the application's homepage, and inspect the downloaded bundle files. The problematic React context definition should appear only once; otherwise, you may have multiple instances of the React context.","For additional information on shared dependency versioning, please refer to the add a shared dependency guide."]},{"l":"Console logs","p":["To faciliate the debugging of a Squide application bootstrapping flow, a lot of information is logged into the console when in development. We recommend using these logs if you suspect that something is wrong with the bootstrapping process of your application."]},{"l":"Modules registration"},{"l":"Local modules","p":["[squide] Found 4 local modules to register.","[squide] 1/4 Registering local module.","[squide] 1/4 Local module registration completed."]},{"l":"Remote modules","p":["[squide] Found 1 remote module to register.","[squide] 1/1 Loading module register of remote remote1.","[squide] 1/1 Registering module register of remote remote1.","[squide] 1/1 The registration of the remote remote1 is completed."]},{"l":"Deferred registrations","p":["[squide] 1/1 Registering the deferred registrations for module register of remote remote1.","[squide] 1/1 Registered the deferred registrations for module register of remote remote1.","[squide] 3/3 Updating local module deferred registration.","[squide] 3/3 Updated local module deferred registration."]},{"l":"Ready","p":["[squide] Modules are ready."]},{"l":"Routes registration","p":["[squide] The following route registration is pending until managed-routes-placeholder is registered.","[squide] The following route has been registered as a children of the managed-routes-placeholder route.","[squide] The following route has been registered."]},{"l":"Navigation items registration","p":["[squide] The following static navigation item registration is pending until the officevibe section of the root menu is registered","[squide] The following static navigation item has been registered to the /federated-tabs menu for a total of 2 static items.","[squide] The following deferred navigation item has been registered to the root menu for a total of 4 deferred items."]},{"l":"Mock Service Worker registration","p":["[squide] The following MSW request handlers has been registered: [...]","[squide] MSW is ready."]},{"l":"AppRouter logs","p":["[squide] AppRouter state updated: {...}","[squide] The following action has been dispatched to the AppRouter reducer: {...}"]},{"l":"i18n logs","p":["[squide] Registered a new i18next instance with key shell: {...}","[squide] The language has been changed to fr-CA.","[squide] Detected fr-CA as user language."]},{"l":"env-vars registration","p":["[squide] The following environment variables has been registered: {...}"]},{"l":"Module federation logs","p":["[squide] Module Federation shared scope is available: {...}"]}],[{"l":"Samples"},{"i":"squide-basic-sample","l":"Squide \"basic\" sample","p":["Host application","Remote module","Another remote module","Local module","Shared application shell","Shared library","Host sample"]},{"i":"squide-sample-with-endpoints","l":"Squide sample with \"endpoints\"","p":["Host application","Remote module","Local module","Shared application shell","Layouts library","i18next library","Shared library","Host sample","Isolated remote module sample"]}],[{"l":"About","p":["To ask a question or propose an idea, feel free to start a new discussion on Github. If you found a bug, please open an issue on Github."]},{"l":"Contributing","p":["Have a look at the contributor's documentation."]},{"l":"License","p":["See the LICENSE on Github."]}]] \ No newline at end of file +[[{"i":"#","p":["The documentation for Squide firefly v8 is available here."]},{"l":"Getting started","p":["Welcome to Squide (yes \uD83E\uDD91 with an \"e\"), a shell for Workleap web applications built on top of Module Federation, React Router and TanStack Query. In this getting started section, you'll find an overview of the shell and a quick start guide to create a new application from scratch."]},{"i":"why-squide","l":"Why Squide?","p":["We originally built this shell to facilitate the adoption of federated applications at Workleap by enforcing patterns that we believe are essential for teams to successfully implement a distributed frontend architecture.","While Squide remains a great shell for federated applications, as we experimented with new products, we discovered that Squide also offers significant value for non-federated web applications:","With the power of local modules and the Runtime API, Squide addresses a long-lasting challenge at Workleap: How can we effectively enforce the boundaries of a business subdomain in the frontend? Squide's modular design naturally upholds these boundaries.","With Squide, teams can confidently develop new products as a simple monorepo application, knowing that as new members are onboarded, their development velocity will scale seamlessly. Over time, local modules can be migrated to remote modules without the need to refactor the core application architecture.","For both federated and non-federated web applications, Squide's modular architecture and lightweight API layer provide a significant upside, combining the strengths of industry-leading third-party libraries:"]},{"l":"Module Federation","p":["We identified 2 major challenges with federated applications:","How can we prevent loading the same large dependencies twice when switching between modules?","How can we offer a cohesive experience that doesn't feel modular?","To address the first challenge, we believe that Module Federation provides a solution by offering a mechanism capable of deduping common dependencies shared between the host application and the remote modules at runtime.","With this mechanism in place, all federated parts of an application can now be loaded in the same browsing context instead of nested browsing contexts such as iframes.","By sharing the same browsing context (e.g. the same Document object, the same Window object, and the same DOM), federated parts now form a unified and cohesive single application, addressing the second challenge.","With Module Federation, we hope to develop federated applications that provide the same user experience as monolithic applications \uD83D\uDE80."]},{"l":"React Router","p":["React Router nested routes feature is ideal for modular applications as it enables highly composable and decoupled UI. For a more in-depth explanation, refer to this article."]},{"l":"TanStack Query","p":["TanStack Query simplifies server state management with an innovative approach to data fetching, caching, and synchronization, enhancing both the perceived performance and the user experience.","TanStack Query is particularly well-suited for modular applications due to its ability to manage server state across multiple independent React components. It’s an effective solution for modular applications that requires isolating data and state between independent parts."]},{"l":"Module registration","p":["The most distinctive aspect of this shell is the conventions it enforces for loading and registering remote modules. Here's a brief overview of the flow:","During bootstrap, the host application attempts to load predefined modules and calls a registration function with a specific name and signature for each successfully loaded module.","During registration, a module receives the runtime of the application and use the instance to dynamically register its routes and navigation items.","Once all the modules are registered, the host application will create a React Router instance with the registered routes and renders a navigation menu with the registered navigation items.","This is a high-level overview. Of course, there is more to it, but these are the main ideas."]},{"l":"Guiding principles","p":["While developing the API of Squide, we kept a few guiding principles in mind. Those principles are not settled stones, you might want to diverge from them from time to time, but adhering to those will make your experience more enjoyable:","A module should correspond to a subdomain of the application's business domain.","A module should be autonomous.","A module should not directly reference the other modules of the application. To coordinate with other modules, including the host application, a module should always use Squide's Runtime API.","A modular application should feel cohesive. Different parts of the application should have the ability to communicate with each others and react to changes happening outside of their boundaries (without taking an hard reference on other parts of the application).","Data and state should never be shared between modules. Even if two modules require the same data or the same state values, they should load, store and manage those independently."]},{"l":"Limitations","p":["If you choose to include remote modules to your application, Module Federation comes with a few manageable limitations that are important to consider when architecting a distributed application:","A shared dependency cannot be tree-shaken. Since remote modules are loaded at runtime, module federation cannot infer which parts of a shared dependency will be used by the application modules. Therefore, tree-shaking is disabled for shared dependencies.","Updating a shared dependency to a new major version is not always straightforward and may result in complex deployment processes."]},{"l":"Create your project","p":["To get started, follow the quick start guide to create a new Squide's application from scratch."]}],[{"l":"Create an host application","p":["We highly recommend going through the entire getting started guide. However, if you prefer to scaffold the application we'll be building, a template is available with degit:","Let's begin by creating the application that will serve as the entry point for our modular application and host the application modules."]},{"l":"Install the packages","p":["Create a new application (we'll refer to ours as host), then open a terminal at the root of the new solution and install the following packages:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Setup the application","p":["First, create the following files:","Then, ensure that you are developing your application using ESM syntax by specifying type: module in your package.json file:","Finally, use a dynamic import to add an async boundary:","To learn more about this async boundary and the bootstrap.tsx file, read the following article."]},{"l":"Module registration","p":["Next, to register the modules, instanciate a shell FireflyRuntime instance and register the remote module with the bootstrap function (the configuration of the remote module will be covered in the next section):","Then, render the AppRouter component to define a React Router browser instance configured with the registered routes:"]},{"l":"Navigation items","p":["Next, create a layout component to render the navigation items. In many applications, multiple pages often share a common layout that includes elements such as a navigation bar, a user profile menu, and a main content section. In a React Router application, this shared layout is commonly referred to as a RootLayout:","The RootLayout component created in the previous sample will serves as the default layout for the homepage as well as for every page (route) registered by a module that are not nested under a parent route with either the parentPath or the parentId option."]},{"l":"Homepage","p":["Next, create the HomePage component that will serve as the homepage:","Then, add a local module at the root of the host application to register the homepage:","And an hoisted route to render the RootLayout with the PublicRoutes and ProtectedRoutes placeholders:","The PublicRoutes and ProtectedRoutes placeholders indicates where routes that are neither hoisted or nested with a parentPath or parentId option will be rendered. In this example, the homepage route is considered as a protected route and will be rendered under the ProtectedRoutes placeholder.","Finally, update the bootstrapping code to register the newly created local module:"]},{"i":"not-found-page-404","l":"Not found page (404)","p":["Now, let's ensure that users who enter a wrong URL end up somewhere by registering a custom no-match route. First, create the NotFoundPage component, which will serve as the page for handling not found routes:","Then, register the newly created component as the * route:"]},{"l":"Configure webpack","p":["Squide webpack configuration is built on top of @workleap/webpack-configs, @workleap/browserslist-config and @workleap/swc-configs. If you are having issues with the configuration of these tools, refer to the tools documentation websites.","First, open the public/index.html file created at the beginning of this guide and copy/paste the following HtmlWebpackPlugin template:","Then, open the .browserslist file and copy/paste the following content:"]},{"l":"Development configuration","p":["To configure webpack for a development environment, first open the swc.dev.js file and copy/paste the following code:","Then, open the webpack.dev.js file and use the defineDevHostConfig function to configure webpack:","If you are having issues with the wepack configuration that are not related to module federation, refer to the @workleap/webpack-configs documentation."]},{"l":"Build configuration","p":["To configure webpack for a build environment, first open the swc.build.js file and copy/paste the following code:","Then, open the webpack.build.js file and use the defineBuildHostConfig function to configure webpack:","If you are having issues with the wepack configuration that are not related to module federation, refer to the @workleap/webpack-configs documentation."]},{"l":"Add CLI scripts","p":["To initiate the development server, add the following script to the application package.json file:","To build the application, add the following script to the application package.json file:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script. You should see the homepage. Even if the remote module application is not yet available, the host application will gracefully (and ignore the remote module)."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong:","[squide] Found 4 local modules to register.","[squide] 1/4 Registering local module.","[squide] 1/4 Local module registration completed.","[squide] Found 1 remote module to register.","[squide] 1/1 Loading module register of remote1.","[squide] 1/1 Registering module register of remote remote1.","[squide] 1/1 The registration of the remote remote1 is completed.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Create a remote module","p":["We highly recommend going through the entire getting started guide. However, if you prefer to scaffold the application we'll be building, a template is available with degit:","Remote modules are modules that are not included in the host application build but are instead loaded at runtime from a remote server. They provide a way for teams to be fully autonomous by independently deploying their modules without relying on the other parts of the application.","Let's add our first remote module!"]},{"l":"Install the packages","p":["Create a new application (we'll refer to ours as remote-module), then open a terminal at the root of the new solution and install the following packages:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Setup the application","p":["First, create the following files:","Then, ensure that you are developing your module using ESM syntax by specifying type: module in your package.json file:"]},{"l":"Routes registration","p":["Next, register the remote module routes and navigation items with the registerRoute and registerNavigationItem functions:","Then, create the Page component:"]},{"l":"Configure webpack","p":["Squide webpack configuration is built on top of @workleap/webpack-configs, @workleap/browserslist-config and @workleap/swc-configs. If you are having issues with the configuration of these tools, refer to the tools documentation websites."]},{"l":"Development configuration","p":["To configure webpack for a development environment, first open the swc.dev.js file and copy/paste the following code:","Then, open the webpack.dev.js file and use the defineDevRemoteModuleConfig function to configure webpack:","If you are having issues with the wepack configuration that are not related to module federation, refer to the @workleap/webpack-configs documentation."]},{"l":"Build configuration","p":["To configure webpack for a build environment, first open the swc.build.js file and copy/paste the following code:","Then, open the webpack.build.js file and use the defineBuildRemoteModuleConfig function to configure webpack:","If you are having issues with the wepack configuration that are not related to module federation, refer to the @workleap/webpack-configs documentation."]},{"l":"Add CLI scripts","p":["To initiate the development server, add the following script to the application package.json file:","To build the module, add the following script to the application package.json file:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the host and the remote-module applications in development mode using the dev script. You should notice an additional link labelled Remote/Page in the navigation menu. Click on the link to navigate to the page of your new remote module!"]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong:","[squide] The following route has been registered.","[squide] The following static navigation item has been registered to the root menu for a total of 2 static items.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Create a local module","p":["We highly recommend going through the entire getting started guide. However, if you prefer to scaffold the application we'll be building, a template is available with degit:","Local modules are regular modules that are part of the host application build. They are independent modules that expose a registration function to the host application's bootstrapping code. A local module can be a standalone package, a sibling project (in a monorepo setup), or even a local folder within the host application.","Local modules have many uses but are especially useful when launching a new product with an unrefined business domain or migrating from a monolithic application to a distributed application.","Let's add a local module to demonstrate how it's done!"]},{"l":"Install the packages","p":["Create a new application (we'll refer to ours as local-module), then open a terminal at the root of the new solution and install the following packages:","While you can use any package manager to develop an application with Squide, it is highly recommend that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Setup the application","p":["First, create the following files:","Then, ensure that you are developing your module using ESM syntax by specifying type: module in your package.json file:","Finally, configure the package to be shareable by adding the name, version, and export fields to the package.json file:"]},{"l":"Routes registration","p":["Next, register the local module routes and navigation items with registerRoute and registerNavigationItem functions:","Then, create the Page component:"]},{"l":"Register the local module","p":["Go back to the host application and add a dependency to the @getting-started/local-module package in the host application package.json file:","If your project is set up as a monorepo, use workspace:* for the version instead of 0.0.1.","Then, register the local module with the bootstrap function:"]},{"l":"Configure tsup","p":["If you are having issues with the tsup configuration, refer to the @workleap/tsup-configs documentation."]},{"l":"Development configuration","p":["To configure tsup for a development environment, open the tsup.dev.ts file and copy/paste the following code:"]},{"l":"Build configuration","p":["To configure tsup for a build environment, open the tsup.build.ts file and copy/paste the following code:"]},{"l":"Add CLI scripts","p":["To initiate the development server, add the following script to the application package.json file:","To build the module, add the following script to the application package.json file:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the host, remote-module and local-module applications in development mode using the dev script. You should notice an additional link labelled Local/Page in the navigation menu. Click on the link to navigate to the page of your new local module!"]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong:","[squide] The following route has been registered.","[squide] The following static navigation item has been registered to the root menu for a total of 2 static items.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Learn the API","p":["Now that we've created a host application, loaded a few modules and registered routes and navigation items, let's delve into the APIs provided by this shell."]},{"l":"Runtime mode","p":["In an effort to optimize the development experience, Squide can be bootstrapped in development or production mode:","By default, the Runtime mode is development."]},{"l":"Logging","p":["Squide includes a built-in logging feature that integrates with the FireflyRuntime class and the useLogger hook.","First, register your own custom logger by implementing the Logger interface or register Squide built-in ConsoleLogger:","Then, log entries from any parts of your modular application with the useLogger hook:","Or the useLoggers hook to target specific logger instances:","The logger is also available from the FireflyRuntime instance."]},{"l":"Messaging","p":["It's crucial that the parts of a modular application remains loosely coupled. To help with that, Squide offers a built-in Event Bus.","First, listen to an event with the useEventBusListener hook:","Then, dispatch an event from anywhere with the useEventBusDispatcher hook:","You can use the event bus to enable various communication scenarios, such as notifying components of state changes, broadcasting messages across modules, or triggering actions based on specific events.","The event bus is also available from the FireflyRuntime instance."]},{"l":"Plugins","p":["To keep Squide lightweight, not all functionalities should be integrated as a core functionality. However, to accommodate a broad range of technologies, a plugin system has been implemented to fill the gap.","Plugins can be registered at bootstrapping with the FireflyRuntime instance:","And can be accessed from any parts of the application with the usePlugin hook:","A plugin can also be retrieved from the FireflyRuntime instance.","By default, the FireflyRuntime registers Squide's MSW plugin. An optional i18next plugin is available."]},{"l":"TanStack Query","p":["Hooks are available to retrieve global application data using TanStack Query. To fetch public data, use the usePublicDataQueries hook:","To retrieve protected data, use the useProtectedDataQueries hook instead:","If an unmanaged error occur while retrieving the data, a GlobalDataQueriesError is thrown."]},{"l":"Fakes","p":["Take a look at the fake implementations. These implementations are designed to facilitate the set up of a module isolated environment."]},{"l":"Guides","p":["Explore the guides section to learn about Squide advanced features.","Be sure to read, at a minimum, the following guides:","Setup Mock Service Worker","Fetch global data","Fetch page data","Manage shared state","Isolate module failures","Add authentication","Add a shared dependency"]},{"l":"Reference","p":["For a comprehensive list of the Squide API, refer to the reference section."]},{"l":"Samples","p":["Finally, have a look at the sample applications to see the Squide API in action."]}],[{"l":"Deploy","p":["The deployment process for a modular application can vary depending on various factors, including the chosen hosting provider. Therefore, we do not recommend any specific deployment setup.","However, there are a few essential configurations that need to be made regardless of your architectural and deployment choices."]},{"l":"Add a default redirect","p":["To enable support for direct page hits, add the following redirect rule to your host application's hosting provider:","For Netlify, it can either be with a netlify.toml file at the root of project:","Or by adding a _redirects file into the Netlify publish directory:"]},{"l":"Set the remote URL","p":["If your modular applications includes remote modules, configure the remote modules production URL:"]},{"l":"Update the runtime mode","p":["Don't forget to change the FireflyRuntime mode to production:"]},{"l":"Remove the console logger","p":["Remove the ConsoleLogger from the production build:"]}],[{"l":"Guides","p":["Add a public route","Add a shared dependency","Add authentication","Develop a module in isolation","Fetch global data","Fetch page data","Implement a custom logger","Isolate module failures","Manage shared state","Override a React context","Override the host layout","Setup Honeycomb","Setup i18next","Setup Mock Service Worker","Use environment variables","Use feature flags","Use modular tabs"]}],[{"l":"Setup Mock Service Worker","p":["To speed up frontend development and encourage an API first approach, Squide has built-in support for Mock Service Worker(MSW). MSW offers an API to host fake endpoints directly in the browser. This means that unlike alternative solutions, it doesn't require running an additional process."]},{"l":"Setup the host application","p":["First, open a terminal at the root of the host application and install the msw package:","Then initialize MSW by executing the following command:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Add an environment variable","p":["Then, update the dev PNPM script to define with cross-env an USE_MSW environment variable that will conditionally include MSW code into the application bundles:","Then, update the development webpack configuration file to include the USE_MSW environment variable into the application bundles:","For more information about the environmentVariables predefined option, refer to the webpack configuration documentation.","Don't forget to define the USE_MSW environment variable for the build script and build webpack configuration as well."]},{"l":"Start the service","p":["With the newly added USE_MSW environment variable, the host application bootstrapping code can now be updated to conditionally start MSW when all the request handlers has been registered.","First, define a function to start MSW:","Then, update the bootstrapping code to start MSW when it's enabled:"]},{"l":"Delay routes rendering until the service is started","p":["Finally, update the host application code to delay the rendering of the routes until MSW is started. This is done by setting the waitForMsw property of the AppRouter component to true:"]},{"l":"Setup a remote module","p":["First, open a terminal at the root of the remote module application and install the msw package:","Then, define a request handler:","Finally, register the request handler with the FireflyRuntime instance:"]},{"l":"Setup a local module","p":["Follow the same steps as for a remote module."]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Update a page component code to fetch the /api/character/1 fake API endpoint, then start the application in development mode using the dev script. You should notice that the data has been fetched from the request handler.","In Chrome devtools, the status code for a successful network call that has been handled by an MSW request handler will be 200 OK (from service worker)."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each request handlers registration that occurs and error messages if something went wrong:","[squide] The following MSW request handlers has been registered: [...]","[squide] MSW is ready.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Fetch global data","p":["Before going forward with this guide, make sure that you completed the Setup Mock Service Worker guide.","Retrieving the global data of an application is a crucial aspect that isn't always straightforward to implement. That's why we encourage feature teams to build their global data fetching strategy on top of the Squide AppRouter component."]},{"l":"Challenges with global data","p":["At first glance, one might wonder what could be so complicated about fetching the global data of an application. It's only fetches ...right? Well, there are several concerns to take into account for a Squide application:","When in development, the global data cannot be fetched until the Mock Service Worker (MSW) request handlers are registered and MSW is ready.","To register the MSW request handlers, the modules(including the remote modules) must be registered first.","If the requested page is public, only the global public data should be fetched.","If the requested page is protected, both the global public and protected data should be fetched.","The requested page rendering must be delayed until the global data has been fetched.","A unique loading spinner should be displayed to the user during this process, ensuring there's no flickering due to different spinners being rendered.","To help manage those concerns, Squide offer an AppRouter component that takes care of setuping Squide's primitive and orchestrating the different states."]},{"l":"Fetch public data"},{"l":"Add an endpoint","p":["First, define in the host application an MSW request handler that returns the number of times it has been fetched:","Then, register the request handler using the module registration function:"]},{"l":"Create a shared context","p":["Then, in a shared project, create a React context named FetchCountContext:","Ensure that the shared project is configured as a shared dependency."]},{"l":"Create a custom error class","p":["Then, in the same shared project, create a ApiError class:"]},{"l":"Fetch the data","p":["Finally, update the App component to add the usePublicDataQueries hook. The hook will fetch the data from /api/count and forward the retrieved fetchCount value through FetchCountContext:"]},{"l":"usePublicDataQueries","p":["The usePublicDataQueries hook is a wrapper around TanStack Query's native useQueries hook. This wrapper coordinates the execution of the queries with the AppRouter component's state."]},{"i":"waitforpublicdata--useisbootstrapping","l":"waitForPublicData & useIsBootstrapping","p":["To ensure the AppRouter component wait for the public data to be ready before rendering the requested route, set the waitForPublicData property to true.","Combine the usePublicDataQueries with the useIsBootstrapping hook to display a loader until the public data is fetched and the application is ready."]},{"l":"Use the endpoint data","p":["Now, create a GlobalDataLayout component that uses the count retrieved from FetchCountContext and render pages with a green background color if the value is odd:","Then, create a Page component:","Finally, register both components, either in the host application or within any module:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script and navigate to the /global-data page. Refresh the page a few times, the background color should alternate between transparent and green."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this section of the guide:","Open the DevTools console. You'll find a log entry for each registration that occurs (including MSW request handlers) and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]},{"l":"Fetch protected data","p":["Now, let's load protected data. The process is similar to fetching public data, but this time, we'll use the useProtectedDataQueries hook instead."]},{"i":"add-an-endpoint-1","l":"Add an endpoint","p":["First, define a MSW request handler that returns a user tenant subscription data:","If you've registered the public data request handler, the newly created request handler should be automatically registered."]},{"i":"create-a-shared-context-1","l":"Create a shared context","p":["Then, in a shared project, create a SubscriptionContext:","If you're not adding the SubscriptionContext to the shared project created earlier for the public data example, make sure to configure this new shared project as a shared dependency."]},{"i":"fetch-the-data-1","l":"Fetch the data","p":["Finally, update the App component to add the useProtectedDataQueries hook. The hook will fetch the data from /api/subscription and forward the retrieved subscription data through SubscriptionContext:"]},{"l":"useProtectedDataQueries","p":["The useProtectedDataQueries hook is a wrapper around TanStack Query's native useQueries hook. This wrapper coordinates the execution of the queries with the AppRouter component's state."]},{"l":"waitForProtectedData","p":["To ensure the AppRouter component wait for the protected data to be ready before rendering the requested route, set the waitForProtectedData property to true."]},{"i":"use-the-endpoint-data-1","l":"Use the endpoint data","p":["Now, update the GlobalDataLayout component that was previously created for the public data example to render the user tenant subscription status:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script and navigate to the /global-data page. You should notice the subscription status."]},{"i":"troubleshoot-issues-1","l":"Troubleshoot issues","p":["If you are experiencing issues with this section of the guide:","Open the DevTools console. You'll find a log entry for each registration that occurs (including MSW request handlers) and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Fetch page data","p":["Before going forward with this guide, make sure that you completed the Setup Mock Service Worker guide.","There are various approaches to fetching data for pages. At Workleap, our preference is to develop a backend for frontend (BFF) with a dedicated endpoint per page, returning a data structure specifically tailored for that page. We rely on server state as our single source of truth and leverage TanStack Query to manage data fetching.","Although this approach works well, a few adjustments are necessary for modular applications."]},{"l":"Install TanStack Query","p":["First, open a terminal at the root of the module and install the following packages:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Setup the query client","p":["Then, instanciate a QueryClient instance in the module registration function and wrap the routes element with a QueryClientProvider:","To minimize unexpected situations and faciliate maintenance, the TanStack Query cache shouldn't be shared between the host application and the modules. As the TanStack Query cache is located in the QueryClient, both the host application and the modules should instantiate their own QueryClient instance."]},{"l":"Create a component for providers","p":["If the module register multiple routes, to prevent duplicating registration code, you can create a Providers component:"]},{"l":"Setup the development tools","p":["To faciliate development, TanStack Query provides devtools to help visualize all of the inner workings of TanStack Query.","However, the TanStack Query devtools has not been developed to handle a modular application with multiple QueryClient instances. To use the devtools, you must define a ReactQueryDevtools component for each QueryClient instance:","Then, depending on which page of the application has been rendered, a distinct devtools instance will be accessible. For a better experience, we recommend activating the TanStack Query devtools exclusively when developing a module in isolation:"]},{"l":"Fetch the page data","p":["Now, let's fetch some data. First, add a Mock Service Worker(MSW) request handler to the local module:","Then, register the request handler using the module registration function:","Then, update the Page component to fetch and render the data with useSuspenseQuery:"]},{"l":"Define a fallback element","p":["The previous code sample uses useSuspenseQuery instead of useQuery to fetch data. This enables an application to leverage a React Suspense boundary to render a fallback element in a layout component while the data is being fetched:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the local module in a development environment using the dev-isolated script. If you haven't completed the develop a module in isolation guide, use the dev script instead and skip the part about TanStack Query devtools. Then, navigate to the /page page.","You should notice that the character's data is being fetch from the MSW request handler and rendered on the page. Additionally, you should notice that the TanStack Query devtools are available (a ribbon at the bottom right corner)."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this section of the guide:","Open the DevTools console. You'll find a log entry for each registration that occurs (including MSW request handlers) and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Manage shared state","p":["Proper management of shared state is crucial in a modular application and can become problematic if not handled carefully. As a general rule, a host application and its modules should never share state."]},{"l":"Forward the global data","p":["However, in the lifecycle of a modular application, the host will fetch the global data that should be fordwarded to the modules. Such examples include a user session or a user tenant subscription status.","As shown in the Fetch global data guide, the global data can be forwarded to modules through a React context."]},{"l":"TanStack Query","p":["Lastly, as detailed in the fetch page data guide, the TanStack Query cache should not be shared between the host and its modules. To do so, both the host application and the modules should instantiate their own QueryClient instance."]}],[{"l":"Isolate module failures","p":["One of the key characteristics of micro-frontends implementations like iframes and subdomains is the ability to isolate failures within individual modules, preventing them from breaking the entire application.","However, with a Module Federation implementation, this is not the case as all the modules share the same browsing context (e.g. the same Document object, the same Window object, and the same DOM). A failure in one module can potentially breaks the entire application.","Nevertheless, an application, federated or non-federated, can get very close to iframes failure isolation by utilizing React Router's Outlet component and the errorElement property of a React Router's routes."]},{"l":"Create an error boundary","p":["First, define a React Router's error boundary to catch module errors. For this example we'll name it ModuleErrorBoundary:"]},{"l":"Register the error boundary","p":["Then, update the host application registerHost function to declare the ModuleErrorBoundary component below the RootLayout component but above the routes of the modules. By doing so, if a module encounters an unhandled error, the error boundary will only replace the section rendered by the Outlet component within the root layout rather than the entire page.","A React Router's error boundary is declared with the errorElement of a route:","By implementing this mechanism, the level of failure isolation achieved is comparable to that of an iframes or subdomains implementation. With this mechanism, failure isolation is as good as with an iframes or subdomains implementation."]},{"l":"Hoisted pages","p":["If your application is hoisting pages, it's important to note that they will be rendered outside of the host application's ModuleErrorBoundary component. To prevent breaking the entire application when an hoisted page encounters unhandled errors, it is highly recommended to declare a React Router's error boundary for each hoisted page as well, again using errorElement:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script. Update any of your application routes that is rendered under the newly created error boundary (e.g. that is not hoisted) and throw an Error. The error should be handled by the ModuleErrorBoundary component instead of breaking the whole application."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Add authentication","p":["Before going forward with this guide, make sure that you completed the Setup Mock Service Worker and Fetch global data guides.","Most of Workleap's applications, if not all, will eventually require user authentication. While Squide doesn't offer built-in primitives for this process, it can assist by providing a well-established recipe to integrate an authentication flow with Squide."]},{"l":"Add a login page","p":["First, open a terminal at the root of the host application and install the @squide/fakes package:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM.","Then, add a Mock Service Worker(MSW) request handler to authenticate a user:","In the previous code sample, the endpoint attempts to authenticate the provided credentials against existing users. If there's a match, the user session is stored in the local storage using a LocalStorageSessionManager instance, and a 200 status code is returned.","Our security department reminds you to refrain from using a fake LocalStorageSessionManager in a production application \uD83D\uDE0A","Next, register the request handler using the host application registration function:","Then, create a login page:","After the user logs in, the application is reloaded, this is a requirement of the AppRouter component. Nevertheless, it's not a concern because Workleap's applications use a third-party service for authentication which requires a full refresh of the application."]},{"l":"Create a session manager","p":["Next, create a shared type for the session and the session manager:","Then, create a shared SessionManagerContext along with some utility hooks. This React context will be used to share the SessionManager instance down the components tree:","Finally, let's go back to the host application and create a TanStack Query implementation of the shared SessionManager interface created previously:"]},{"l":"Fetch the session","p":["Next, create an MSW request handler that returns a session object if a user is authenticated:","Then, update the host application App component to load the session with the useProtectedDataQueries hook and create an instance of TanstackQuerySessionManager with the retrieved session to share the sessuib via the SessionManagerContext:","The previous example uses the following implementation of the ApiError class:"]},{"l":"Add an authentication boundary","p":["Next, create an authentication boundary component using the shared useIsAuthenticated hook created earlier to redirect unauthenticated user to the login page:"]},{"l":"Define an authenticated layout","p":["Now, let's add a specific layout for authenticated users that passes through the AuthenticationBoundary component.","First, add a MSW request handler to log out a user:","Then, introduce a new AuthenticatedLayout component displaying the name of the logged-in user along with a logout button. This layout will retrieve the active user session from the shared useSessionManager hook introduced earlier:","By creating a new AuthenticatedLayout component, much of the layout code has been transferred from the RootLayout to the AuthenticatedLayout, leaving the root layout responsible only for styling the outer wrapper of the application for now:"]},{"l":"Setup the routes","p":["Finally, assemble everything:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application using the dev script and attempt navigating to the root page (/). You will be redirected to the /login page. Login with temp/ temp, you will be redirected to the root page."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Add a public route","p":["A route can be registered as either public or protected. This visibility indicator does not determine whether a route is accessible to everyone or restricted to authenticated users; that protection is typically enforced by an authentication boundary.","In a Squide application, the visibility indicator determines whether routes will be rendered as children of either the PublicRoutes or ProtectedRoutes placeholders and whether the usePublicDataQueries or useProtectedDataQueries hooks should execute their requests. If the initially requested route is marked as protected and both hooks are defined, each query hook will execute its respective requests. However, if the route is marked as public, only the usePublicDataQueries hook will execute its requests.","When a route is registered with the registerRoute function, it is considered protected by default. Therefore, if a route does not rely on the application's global protected data, it should be explicitly registered as public using the registerPublicRoute function:","Don't forget to register the PublicRoutes placeholder in the host application:"]}],[{"l":"Override the host layout","p":["The RootLayout component defined in the Create an host application starting guide serves as the default layout for the homepage and all the managed routes.","For most routes, this behavior is what the author expects. However, as an application introduces authentication and adds many session-related features to the default layout, this default layout may no longer be suitable for every route. For example, a login page doesn't require session-related features, as the user isn't authenticated yet. In such cases, the default layout isn't appropriate.","To accomodate pages requiring a different layout, a mechanism is needed to move their route declaration to the root of the React Router instance before RootLayout is declared."]},{"l":"Hoist a module routes","p":["Package managers supporting workspaces such as Yarn and NPM call this mechanism \"hoisting\", which means \"raise (something) by means of ropes and pulleys\". This is exactly what we are trying to achieve here.","Squide has a built-in hoist functionality capable of raising module routes marked as hoist at the root of the routes array, before the RootLayout declaration. Thus, an hoisted route will not be wrapped by the RootLayout component (or any authentication boundaries) and will have full control over its rendering.","To hoist module routes, add the hoist option to the route registration options and optionally use a different layout:","By declaring a route as hoisted, other parts of the application will not be isolated anymore from this route's failures as the route will most likely be rendered outside of the host application's root error boundary. To avoid breaking the entire application when an hoisted route encounters unhandled errors, it is highly recommended to declare a React Router's errorElement property for each hoisted routes.","By declaring a route as hoisted, the route will be rendered at the root of the router, therefore, most certainly outside the authenticated boundary of the application. If the hoisted route requires an authentication, make sure to wrap the route with an authentication boundary or to handle the authentication within the route's page."]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script and navigate to the /login page. The page should be displayed even if you are not authenticated."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Use modular tabs","p":["While it's typically recommended for a Squide application to maintain the boundary of a page within a single domain, there are situations where enhancing the user experience necessitates rendering a page with parts from multiple domains, or at the very least, simulating it \uD83D\uDE0A.","For this guide, we'll take as an example a page for which the parts that are owned by different domains are organized by tabs (modular tabs) and registered by different modules:","Tab 1: Registered by Remote Module 1","Tab 2: Registered by Remote Module 2","Tab 3: Registered by Local Module","Anatomy of a page rendering modular tabs"]},{"l":"Define a nested layout","p":["To build this page while adhering to Squide's constraint of avoiding hard references to elements from other modules, let's start by defining a React Router nested layout. This nested layout will handle rendering all the tab headers and the content of the active tab:","In the previous code sample, the TabsLayout component is similar to the RootLayout component introduced in previous guides. However, the key distinction is that this layout will be bound to the /tabs URL path. By nesting the layout under a specific path, it will only render when the user navigates to one of the modular tab pages (e.g. /tabs, /tabs/tab-1, /tabs/tab-2, /tabs/tab-3).","To register the newly created layout as a nested layout, use the registerRoute function:","With this nested layout in place, thanks to the React Router Outlet component, the content of the tabs can now reside in distinct routes(registered by different modules) while still delivering a cohesive user experience. Whenever a user navigates between the tabs, the URL will be updated, and the tab content will change, but the shared portion of the layout will remain consistent.","As a bonus, each individual tab will have its own dedicated URL! \uD83E\uDD73","It is recommended to define the shared layouts in a standalone package as it's done for the endpoints sample layouts project."]},{"l":"Create the tab routes","p":["Next, let's add the actual tabs to the modules. To do so, we'll use the parentPath option of the registerRoute function to register the routes under the TabsLayout component:","Now that the tabs has been registered, ensure that all four modules (including remote-modules-3) are registered in the host application. Start the development servers using the dev script. Navigate to the /tabs page, you should see the tab headers. Click on each tab header to confirm that the content renders correctly."]},{"l":"Decouple the navigation items","p":["Althought it's functional, the modules are currently coupled by hardcoded URLs within the TabsLayout component.","To decouple the navigation items, similar to what is done for regular module's routes, we'll use the registerNavigationItem function. In this case, we'll specify a menuId option. Defining the menuId option will allow the TabsLayout component to exclusively retrieve the navigation items that belongs to him.","First, let's register the navigation items with the menuId option. For this example the menuId will be /tabs(it can be anything):","Then, update the TabsLayout component to render the registered navigation items instead of the hardcoded URLs:"]},{"l":"Change the display order of the tabs","p":["Similarly to how the display order of regular navigation items can be configured, a modular tab position can be affected with the priority option.","To force Tab 3 to be positioned first, we'll give him a priority of 999:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["To ensure everything is still working correctly, start the development servers using the dev script and navigate to the /tabs page. You should see all three tabs, and you should be able to switch between them by clicking on the tab headers."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong:","[squide] The following route has been registered as a children of the /tabs route.","[squide] The following static navigation item has been registered to the /tabs menu for a total of 1 item.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Use feature flags","p":["Before going forward with this guide, make sure that you completed the Setup Mock Service Worker and Fetch global data guides.","To continuously deliver value to our customers, Workleap has adopted a feature flag system that enables functionalities to be activated or deactivated without requiring a code deployment. While implementing \"in-page\" feature flags in a Squide application is straightforward, feature flags that conditionally register navigation items require a more advanced deferred registration mechanism."]},{"l":"Add an endpoint","p":["First, define a MSW request handler that returns the feature flags:","Finally, register the request handler using the module registration function:"]},{"l":"Create a shared context","p":["Now, in a shared project, create a FeatureFlagsContext:","Ensure that the shared project is configured as a shared dependency."]},{"l":"Fetch the feature flags","p":["Finally, open the host application code and update the App component to fetch the feature flags data with the usePublicDataQueries hook:"]},{"l":"Conditionally render a page section","p":["Now, let's use the featureA flag from FeatureFlagsContext to conditionally render a section of a new Page component. In this example, a section of the Page component will only be rendered if featureA is activated:","Then, register the Page component using the module registration function:","If you've already registered a Page component in a previous guide, use a different name for this component."]},{"l":"Conditionally register a navigation item","p":["Conditionally registering navigation items based on a feature flag is more complex because Squide's default registration mechanism runs before the application has bootstrapped, meaning that the feature flags have not yet been fetched from the server.","To address this, Squide offers an alternate deferred registration mechanism in two-phases:","The first phase allows modules to register their static navigation items that are not dependent on initial data.","The second phase enables modules to register deferred navigation items that are dependent on initial data. We refer to this second phase as deferred registrations.","To defer a registration to the second phase, a module's registration function can return an anonymous function matching the DeferredRegistrationFunction type: (data, operation: register | update) = Promise | void.","Once the modules are registered and the useDeferredRegistrations hook is rendered, the deferred registration functions will be executed with either register or update as the value for the operation argument, depending on whether this is the initial or subsequent execution of the functions.","First, let's define a DeferredRegistrationData interface to a shared project, specifiying the initial data that module's deferred registration functions can expect:","Then, add DeferredRegistrationData to the ModuleRegisterFunction type definition and update the module register function to defer the registration of the Page component navigation item:","Finally, update the host application's App component to use the useDeferredRegistrations hook. By passing the feature flags data to useDeferredRegistrations, this data will be available to the module's deferred registration functions:","A key feature of TanStack Query is its ability to keep the frontend state synchronized with the server state. To fully leverage this, whenever the data passed to useDeferredRegistrations changes, all deferred registration functions are re-executed.","Remember to use useMemo for your deferred registration data and to specify the $id option for your navigation items!"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application using the dev and navigate to the /page page. The page should render with the conditonal section. Now, disable the featureA flag in the endpoint and refresh the page. You shouldn't see the conditonal section anymore. Finally, disable the featureB flag in the endpoint and refresh the page. The menu link labelled \"Page\" shouldn't be available anymore.","If you are experiencing issues with this section of the guide:","Open the DevTools console. You'll find a log entry for each registration that occurs (including MSW request handlers) and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Use environment variables","p":["Before going forward with this guide, make sure that you completed the Setup Mock Service Worker guide.","Environment variables are incredibly useful when working with multiple environments, such as dev, staging, and production, by decoupling configuration from the code. This allows to change an application's behavior without modifying the code itself. A common example is the URLs of dedicated API services, where each environment uses a different URL.","In webpack, environment variables are typically passed from the CLI to the application code using the DefinePlugin and accessed through process.env, e.g. process.env.BASE_API_URL.","While accessing environment variables from process.env works, it has a few downsides:","It's not ideal for testing. Tests relying on global variables can inadvertently affect other tests, introducing potential issues that affect test reliability, maintainability, and isolation.","It complicates module development in isolation. A modular application shell often makes requests to multiple endpoints, which vary depending on the environment. These endpoints require environment variables to define their URLs. When developing modules in isolation, modules should not provide these environment variables to the shell. Instead, to improve DX, the shell library should manage these environment variables internally.","To replace process.env, Squide provides the EnvironmentVariablesPlugin. This plugin acts as a registry and integrates with the Runtime API, allowing modules to register and retrieve environment variables.","Before this plugin, page components would directly rely on process.env:","With the EnvironmentVariablesPlugin, a page component can now retrieve the baseApiUrl from Squide's runtime instance by using the useEnvironmentVariable hook:","Let's go through the setup of the plugin and how to handle a few use cases."]},{"l":"Install the package","p":["First, open an existing Squide application. Then open a terminal at the root of the host application and install the following package:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Setup the plugin","p":["Then, update the host application boostrapping code to register an instance of the EnvironmentVariablesPlugin with the FireflyRuntime instance:"]},{"l":"Module augmentation","p":["Before registering variables, modules must augment the EnvironmentVariables TypeScript interface with the variables they intend to register to ensure type safety and autocompletion.","To do this, first create a types folder:","Then create an env-vars.d.ts file:","Finally, update the module tsconfig.json to include the types folder:"]},{"l":"Register variables","p":["Now, let's register our first variable. We recommend registering environment variables in the module's register function as it's the most logical place to access the runtime instance:","If multiple modules need to use the same environment variable, we recommend that each module register its own instance of the variable to maintain modularity. The EnvironmentVariablesPlugin registry will ignore any subsequent registrations for existing keys, as long as the variable value remains the same."]},{"l":"Retrieve a variable in React code","p":["Then, retrieve the variables in a new DataPage component using either the useEnvironmentVariable or useEnvironmentVariables hook:","Finally, register a route for the component:"]},{"l":"Retrieve a variable for MSW handlers","p":["Next, create an MSW handlers for the DataPage component. An handler can retrieve the variables using either the plugin's getVariable or getVariables function:","Finally, register the new handler:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script and navigate to the /data page. The page should render { foo: bar }."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this section of the guide:","Open the DevTools console. You'll find a log entry for each registration that occurs (including MSW request handlers) and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]},{"l":"Integrate with tests","p":["If the code under test uses environment variables, the EnvironmentVariablesPlugin can be used to mock these variables.","Considering the following utility hook:","You can write the following unit test to mock the value of apiBaseUrl and test the ouput of the useAbsoluteUrl hook:"]},{"l":"Integrate with stories","p":["Components included in Storybook stories often rely on environment variables. The EnvironmentVariablesPlugin can be used to mock these variables:"]},{"l":"Integrate with libraries","p":["Libraries, such as an application Shell, often need to manage environment variables internally to be portable.","Assuming the host application registers the EnvironmentVariablesPlugin into the runtime, and given the following file structure:","To setup such a library, first, create a registerShell function that accepts an argument indicating the current environment (e.g., dev, staging or production):"]},{"i":"register-variables-1","l":"Register variables","p":["Then, update the registerShell function to register the apiBaseUrl environment variable based on the provided env argument:"]},{"i":"module-augmentation-1","l":"Module augmentation","p":["Then, augment the EnvironmentVariables TypeScript interface to include the apiBaseUrl variable:","Then, update the module tsconfig.json to include the types folder:","Finally, when tsc is linting the codebase, it expects every code library that augments the EnvironmentVariables interface to include its typings. To do this, add each code library's types folder to every projects' tsconfig.json file that depends on code libraries:"]},{"i":"troubleshoot-issues-1","l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each environment variable registration that occurs and error messages if something went wrong:","[squide] The following environment variables has been registered: {...}","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Setup i18next","p":["Most Workleap's platform application are either already bilingual or will be in the future. To help feature teams deal with localized resources, Squide provides a native plugin designed to adapt the i18next library for modular applications.","The examples in this guide load all the resources from single localized resources files. For a real Workleap application, you probably want to spread the resources into multiple files and load the files with a i18next backend plugin."]},{"l":"Setup the host application","p":["Let's start by configuring the host application. First, open a terminal at the root of the host application and install the following packages:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Register the i18nextPlugin","p":["Then, update the host application boostrapping code to register an instance of the i18nextplugin with the FireflyRuntime instance:","In the previous code sample, upon creating an i18nextPlugin instance, the user language is automatically detected using the plugin.detectUserLanguage function. Applications should always detect the user language at bootstrapping, even if the current language is expected to be overriden by a preferred language setting once the user session has been loaded."]},{"l":"Define the localized resources","p":["Next, create the localized resource files for the en-US and fr-CA locales:"]},{"l":"Register an i18next instance","p":["Then, update the host application local module's register function to create and register an i18next instance with the retrieved i18nextPlugin instance. Due to how the internals of i18next works, each module (including the host application) must create its own instance of the third-party library. i18nextPlugin will handle synchronizing the language changes across all i18next instances:","In the previous code sample, notice that the i18next instance has been initialized with the current language of the i18nextPlugin instance by providing the lng option. If the user language has been detected during bootstrapping, the i18next instance will then be initialized with the user language which has been deduced from either a ?language querystring parameter or the user navigator language settings. Otherwise, the application instance will be initialized with the fallback language, which is en-US for this guide."]},{"l":"Localize the home page resources","p":["Then, update the HomePage component to use the newly created localized resource:"]},{"l":"Update the webpack configurations","p":["Finally, update the webpack development and build configurations to activate the i18next feature. Enabling this feature will configure the i18next libraries as shared dependencies:"]},{"l":"Setup a remote module","p":["First, open a terminal at the root of the remote module application and install the following packages:"]},{"i":"define-the-localized-resources-1","l":"Define the localized resources","p":["Then, create the localized resource files for the en-US and fr-CA locales:","Notice that this time, a standard navigationItems namespace has been added to the resource files. The resources in the navigationItems namespace will be used later on to localize the navigation items labels."]},{"i":"register-an-i18next-instance-1","l":"Register an i18next instance","p":["Then, update the remote module's register function to create and register an instance of i18next with the i18nextPlugin plugin instance. Similarly to the host application, due to how the internals of i18next works, this local module requires to register its own instance of the third-party library:"]},{"l":"Localize the navigation item labels","p":["Then, localize the navigation items labels using the I18nextNavigationItemLabel component. Since this example resources are in the navigationItems namespace, there's no need to specify a namespace property on the components as it will be inferred:"]},{"l":"Localize the page resources","p":["Then, update the Page component to use the newly created localized resource:"]},{"i":"update-the-webpack-configurations-1","l":"Update the webpack configurations","p":["Finally, update the webpack development and build configurations to activate the i18next feature. Enabling this feature will configure the i18next libraries as shared dependencies:"]},{"l":"Setup a local module","p":["Follow the same steps as for a remote module."]},{"l":"Integrate a backend language setting","p":["For many applications, the displayed language is expected to be derived from an application specific user \"preferred language\" setting stored in a remote database. Therefore, the frontend remains unaware of this setting value until the user session is loaded.","Hence, the strategy to select the displayed language should be as follow:","Use the language detected at bootstrapping for anonymous users (with the detectUserLanguage function).","Upon user authentication and session loading, if a \"preferred language\" setting is available from the session data, update the displayed language to reflect this preference.","This strategy can be implemented with the help of the useChangeLanguage and useProtectedDataQueries hooks:","The previous code sample assumes that your @sample/shared project includes the primitives created in the Add authentication guide as well as the session Mock Server Worker request handlers."]},{"l":"Use the Trans component","p":["The Trans component is useful for scenarios involving interpolation to render a localized resources. To use the Trans component with Squide, pair it with an i18next instance retrieved from useI18nextInstance hook:","The Trans component can also be used without the t function by including a namespace to the i18nKey property value:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script. The homepage and the navigation items should render the english ( en-US) resources. Then append ?language=fr-CA to the URL. The homepage and the navigation items should now render the french ( fr-CA) resources."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Open the DevTools console. You'll find a log entry for each i18next instance that is being registered and another log everytime the language is changed:","[squide] Registered a new i18next instance with key remote-module.","[squide] The language has been changed to fr-CA.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Setup Honeycomb","p":["Before going forward with this guide, make sure that you migrated to v9.3.","To monitor application performance, Workleap has adopted Honeycomb, a tool that helps teams manage and analyze telemetry data from distributed systems. Built on OpenTelemetry, Honeycomb provides a robust API for tracking frontend telemetry.","Honeycomb's in-house HoneycombWebSDK includes great default instrumentation. However, this instrumentation has to be extended to capture traces specific to Squide features. To facilitate this, Squide provides the registerHoneycombInstrumentation function."]},{"l":"Setup the host application","p":["Let's start by configuring the host application. First, open a terminal at the root of the host application and install the following packages:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM."]},{"l":"Register instrumentation","p":["Then, update the host application bootstrapping code to register Honeycomb instrumentation:","Avoid using /.+/g, in production, as it could expose customer data to third parties. Instead, ensure you specify values that accurately matches your application's backend URLs.","We recommend using an OpenTelemetry collector over an ingestion API key, as API keys can expose Workleap to potential attacks.","With instrumentation in place, a few traces are now available \uD83D\uDC47"]},{"l":"Bootstrapping flow","p":["The performance of an application bootstrapping flow can now be monitored:","Bootstrapping flow performance"]},{"l":"Deferred registration update","p":["When a deferred registration is updated, the performance of the operation can be monitored:","Deferred registration update performance"]},{"l":"Fetch requests","p":["Individual fetch request performance can be monitored from end to end:","Fetch instrumentation"]},{"l":"Document load","p":["The loading performance of the DOM can be monitored:","Document load instrumentation"]},{"l":"Unmanaged error","p":["When an unmanaged error occurs, it's automatically recorded:","Recorded error"]},{"i":"real-user-monitoring-rum","l":"Real User Monitoring (RUM)","p":["The default instrumentation will automatically track the appropriate metrics to display RUM information:","Largest Contentful Paint","Cumulative Layout Shift","Interaction to Next Paint"]},{"l":"Set custom user attributes","p":["Most application needs to set custom attributes on traces about the current user environment. To help with that, Squide expose the setGlobalSpanAttributes function.","Update your host application to include the setGlobalSpanAttributes function:","Now, every trace recorded after the session initialization will include the custom attributes app.user_id:","Custom attributes"]},{"l":"Custom traces","p":["Squide does not provide a proprietary API for traces. Applications are expected to use the OpenTelemetry API to send custom traces to Honeycomb:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the application in a development environment using the dev script. Render a page, then navigate to your Honeycomb instance. Go to the \"Query\" page and type name = squide-bootstrapping into the \"Where\" input. Run the query, select the \"Traces\" tab at the bottom of the page and view the detail of a trace. You should view the performance of your application bootstrapping flow."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this guide:","Set the runtime mode to development mode or register the Honeycomb instrumentation in debug.","Open the DevTools console. You'll see a log entry for every for each dispatched event, along with multiple console outputs from Honeycomb's SDK. Squide's bootstrapping instrumentation listens to events to send Honeycomb traces. Most events should match an Honeycomb trace and vice versa.","[squide] Dispatching event squide-local-modules-registration-completed","[squide] Dispatching event squide-remote-modules-registration-completed","[squide] Dispatching event squide-public-data-fetch-started","[squide] Dispatching event squide-public-data-ready","@honeycombio/opentelemetry-web: Honeycomb link: ...","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Develop a module in isolation","p":["To develop their own independent module, a team should not need to install the host application or any other modules of the application they do not own. However, they should have a way to integrate their module with the application shell (e.g., RootLayout, RootErrorBoundary, etc..) while working in isolation.","To achieve this, the first step is to extract the application shell from the host application. There are various ways to accomplish this, but in this guide, we'll transform the host application into a monorepo and introduce a new local package named @sample/shell specifically for this purpose:"]},{"l":"Create a shell package","p":["The implementation details of the RootLayout, RootErrorBoundary and ModuleErrorBoundary components won't be covered by this guide as it already has been covered many times by other guides.","First, create a new package (we'll refer to ours as shell) and add the following fields to the package.json file:","Then, install the package dependencies and configure the new package with tsup.","Then, create an AppRouter component in the shell package to provide a reusable router configuration that can be shared between the host application and the isolated modules. This new AppRouter component should wrap the @squide/firefly AppRouter component:","Finally, create a local module to register the application shell. This module will be used by both the host application and the isolated modules:","This guide only covers the RootLayout, RootErrorBoundary and ModuleErrorBoundary components but the same goes for other shell assets such as an AuthenticationBoundary component."]},{"l":"Update the host application","p":["Now, let's revisit the host application by adding the new @sample/shell package as a dependency:","Then, integrate the AppRouter component from the @sample/shell package into the application:","And finally include the registerShell function to setup the RootLayout and RootErrorBoundary components as well as any other shell assets:"]},{"l":"Setup a remote module","p":["With the new shell package in place, we can now configure the remote module to be developed in isolation. The goal is to start the module development server and render the module pages with the same layout and functionalities as if it was rendered by the host application.","To begin, let's start by adding a dependency to the @sample/shell package:","Then, create the following files in the remote module application:"]},{"i":"indextsx","l":"index.tsx","p":["The index.tsx file is similar to the bootstrap.tsx file of an host application but, tailored for an isolated module. The key distinctions are that all the modules are registered as local modules, and a new registerDev function is introduced to register the development homepage (which will be covered in an upcoming section):"]},{"i":"apptsx","l":"App.tsx","p":["The App.tsx file uses the newly created AppRouter component to setup Squide's primitives with a React Router instance:"]},{"i":"devhometsx","l":"DevHome.tsx","p":["The DevHome component is the homepage when the remote module is developed in isolation:","To register the development homepage, create a new local module specifically for configuring the remote during isolated development:"]},{"l":"Add a new CLI script","p":["Next, add a new dev-isolated script to the package.json file to start the local development server in isolation:","If your project's package.json file does not already include the cross-env dependency, be sure to install cross-env as a development dependency.","The dev-isolated script is similar to the dev script but introduces an ISOLATED environment variable. This variable will be used by the webpack.dev.js file to conditionally configure the development server to either serve the module as an application for isolated development or as a remote endpoint by the host application through the /remoteEntry.js entry point."]},{"l":"Configure webpack","p":["First, open the public/index.html file created at the beginning of this guide and copy/paste the following HtmlWebpackPlugin template:","Then, open the .browserslist file and copy/paste the following content:"]},{"l":"Isolated environment configuration","p":["To configure webpack, open the webpack.dev.js file and update the configuration to incorporate the ISOLATED environment variable and the defineDevHostConfig function:","If you encounter issues configuring webpack, refer to the @workleap/webpack-configs documentation."]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the remote module in isolation by running the dev-isolated script. The application shell should wrap the pages of the module and the default page should be DevHome."]},{"l":"Troubleshoot issues","p":["If you are experiencing issues with this section of the guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]},{"l":"Setup a local module","p":["Similarly to remote modules, local modules can also be set up for isolated development. The key difference is that the webpack.config.js file for a local module strictly serves the purpose of starting a development server for isolated development. Typically, local modules do not depend on webpack or Module Federation.","First, open a terminal at the root of the local module project and install the @squide/firefly-webpack-configs package and its dependencies:","While you can use any package manager to develop an application with Squide, it is highly recommended that you use PNPM as the guides has been developed and tested with PNPM.","Then, add a peer dependency and a dev dependency to the @sample/shell package:","Then, create the following files in the local module application:"]},{"i":"indextsx-1","l":"index.tsx","p":["This file is similar to the index.tsx file of the remote module."]},{"i":"apptsx-1","l":"App.tsx","p":["This file is similar to the App.tsx file of the remote module."]},{"i":"devhometsx-and-registerdev","l":"DevHome.tsx and registerDev","p":["These files are similar to the dev/DevHome.tsx and dev/register.tsx files of the remote module."]},{"i":"configure-webpack-1","l":"Configure webpack","p":["First, open the public/index.html file and copy/paste the following HtmlWebpackPlugin template:","Then, open the .browserslist file and copy/paste the following content:","Then, open the swc.config.js file and copy/paste the following code:","Finally, open the webpack.config.js file and use the the defineDevHostConfig function to configure webpack:","If you encounter issues configuring webpack, refer to the @workleap/webpack-configs documentation."]},{"i":"add-a-new-cli-script-1","l":"Add a new CLI script","p":["Next, add a new dev-isolated script to the package.json file to start the local development server:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the remote module in isolation by running the dev-isolated script. The application shell should wrap the pages of the module and the default page should be DevHome."]},{"i":"troubleshoot-issues-1","l":"Troubleshoot issues","p":["If you are experiencing issues with this section of the guide:","Open the DevTools console. You'll find a log entry for each registration that occurs and error messages if something went wrong.","Refer to a working example on GitHub.","Refer to the troubleshooting page."]}],[{"l":"Override a React context","p":["In a modular application, it's typical to configure various global React context at the root of the host application. These contexts are then used by the layouts and pages of the modules.","Let's explore a simple example using a BackgroundColorContext:","In the previous code samples, the host application provides a value for the BackgroundColorContext, and the ColoredPage component of the remote module uses this value to set its background color (to blue for this example)."]},{"l":"Override the context for the module","p":["Now, suppose the requirements change, and a page of the remote module must have a red background. The context can be overriden for that page by declaring a new provider directly in the routes registration:"]},{"l":"Extract an utility component","p":["Since there are multiple routes to setup with the new provider, an utility component can be extracted:"]},{"l":"Update a singleton dependency version","p":["This section only applies to federated applications (applications including remote modules).","Let's consider a more specific use case where the host application declares a ThemeContext from Workleap's new design system, Hopper:","In this scenario, Hopper's components are used throughout the entire application, including the modules. Moreover, @hopper/components is defined as a singleton shared dependency:","Now, consider a situation where Hopper releases a new version of the package that includes breaking changes, without a \"compatibility\" package to ensure backward compatility with the previous version.","To update the host application without breaking the modules, we recommend to temporary \"break\" the singleton shared dependency by loading two versions of the @hopper/components dependency in parallel (one for the host application and one for the modules that have not been updated yet):","As @hopper/components expose the ThemeContext, the context must be re-declared in each module until every part of the federated application has been updated to the latest version of @hopper/components:","Thankfully, React Router makes it very easy to declare contexts in a module."]}],[{"l":"Add a shared dependency","p":["This guide only applies to federated applications (applications including remote modules).","Shared dependencies is one of the most powerful concepts of Module Federation. However, mastering its configuration can be quite challenging. Failure to configure shared dependencies properly in a federated application using Module Federation can significantly impact both user and developer experiences.","Squide aims to simplify the configuration of shared dependencies by abstracting the shared dependencies necessary for building an application with React, React Router, and optionally MSW and i18next. Nevertheless, every federated application will inevitably have to configure additional custom shared dependencies.","For a comprehensive documentation of the Module Federation APIs, their functionality, and their benefits, please refer to this article."]},{"l":"Understanding singleton dependencies","p":["A singleton shared dependency does exactly what its name suggests: it loads a single instance of a dependency. This means that a dependency will be included in just one bundle file of the federated application."]},{"l":"Strict versioning","p":["Sometimes, a singleton shared dependency is paired with the strictVersion option:","When specified, the strictVersion option will generate a runtime error if a module attempts to load a version of the dependency that is incompatible with the specified version. It's often unnecessary to use a strict version, and omitting it provides greater flexibility when it comes time to update the shared dependency version."]},{"l":"Expected behaviors","p":["Please note that Squide's singleton dependency version resolution algorithm differs from the native Module Federation behavior. By default, Squide registers a runtime plugin that customize the resolution of shared dependencies."]},{"l":"Minor or patch version","p":["When the version difference between a host application and a remote module is a minor or patch version, the higher version of the dependency will be loaded. For example:","If the host application is on 10.1.0 and a remote module is on 10.1.1-> 10.1.1 will be loaded","If the host application is on 10.1.0 and a remote module is on 10.2.0-> 10.2.0 will be loaded"]},{"l":"Major version","p":["If the version difference between a host application and a remote module is a major version, once again, the higher version of the dependency will be loaded only if it's requested by the host application. For example:","If the host application is on 11.0.0 and a remote module is on 10.0.0-> 11.0.0 will be loaded","If the host application is on 10.0.0 and a remote module is on 11.0.0-> 10.0.0 will be loaded"]},{"l":"Additional examples","p":["Let's go through a few additional examples \uD83D\uDC47"]},{"l":"Example 1","p":["The version requested by remote-1 is selected because it only represents a minor difference from the version requested by the host application."]},{"l":"Example 2","p":["The version requested by the host application is selected because remote-1 is requesting a version with a major difference from the one requested by the host application."]},{"l":"Example 3","p":["The version requested by remote-2 is selected because remote-1 is requesting a version with a major difference from the one requested by the host application. Therefore, remote-2 requests the next highest version, which represents only a minor difference from the version requested by the host application."]},{"i":"what-should-be-configured-as-a-shared-dependency","l":"What should be configured as a shared dependency?","p":["Libraries matching the following criterias are strong candidates to be configured as shared dependencies:","Medium to large libraries that are used by multiple modules.","Libraries that requires a single instance to work properly (like react).","Libraries exporting React contexts."]},{"l":"Understanding eager dependencies","p":["An eager shared dependency becomes available as soon as the host application starts. In simple terms, it is included in the host application bundle rather than being loaded lazily when it is first requested.","The key point to remember about eager dependencies is that only one application or remote module should configure a shared dependency as eager. Otherwise, the dependency will be included in the bundle of the host application and of every remote module that set the dependency as eager."]},{"i":"what-should-be-configured-as-an-eager-dependency","l":"What should be configured as an eager dependency?","p":["Any shared dependency that must be loaded to bootstrap the application."]},{"l":"Default shared dependencies","p":["Since Squide has dependencies on React and React Router, the define* functions automatically configure shared dependencies for these packages by default, in addition to Squide own packages. The following shared dependencies are set as eager singleton by default:","react","react-dom","react-router-dom","@squide/core","@squide/react-router","@squide/module-federation","For the full shared dependencies configuration, have a look at the defineConfig.ts file on Github.","You can extend or override the default shared dependencies configuration."]},{"l":"Add custom shared dependencies","p":["To configure shared dependencies, use the sharedDependencies option of any define* function:","When a dependency is shared between a host application and a remote module, the sharing options must be configured on both ends:"]},{"l":"React context limitations","p":["For a React context to be provided by the host application and consumed by the remote modules, the library exporting the React context must be set as a singleton.","To troubleshoot a React context issue or find more information about the limitations, refer to the troubleshooting page."]},{"l":"React dependencies requirements","p":["react and react-dom dependencies must be configured as a singleton, otherwise either an error will be thrown at bootstrapping if the loaded react versions are incompatible, or features like useState will not work.","The react-router-dom dependency must as well be configured as a singleton because it relies on a global React context that needs to be declared in the host application and is consumed by remote modules."]},{"l":"Learn more","p":["To learn more about Module Federation shared dependencies read this article about the shared APIs and refer to this POC on GitHub."]}],[{"l":"Implement a custom logger","p":["Many applications must integrate with specific remote logging solutions such as Honeycomb and Azure Application Insights. To facilitate this integration, the shell runtime accepts any custom loggers implementing the Logger interface."]},{"l":"Create a custom logger class","p":["First, let's define a custom logger:","Then create a FireflyRuntime instance configured with an instance of the new CustomLogger:"]},{"i":"try-it","l":"Try it \uD83D\uDE80","p":["Start the applications and open the developer tools, then, refresh the page. You should see the following console log message:"]}],[{"l":"Updating","p":["Migrate to firefly v9.0","Migrate to firefly v9.3"]}],[{"i":"migrate-to-firefly-v90","l":"Migrate to firefly v9.0","p":["This major version of @squide/firefly introduces TanStack Query as the official library for fetching the global data of a Squide's application and features a complete rewrite of the AppRouter component, which now uses a state machine to manage the application's bootstrapping flow.","Prior to v9.0, Squide applications couldn't use TanStack Query to fetch global data, making it challenging for Workleap's applications to keep their global data in sync with the server state. With v9.0, applications can now leverage custom wrappers of the TanStack Query's useQueries hook to fetch and keep their global data up-to-date with the server state. Additionally, the new deferred registrations update feature allows applications to even keep their conditional navigation items in sync with the server state.","Finally, with v9.0, Squide's philosophy has evolved. We used to describe Squide as a shell for federated applications. Now, we refer to Squide as a shell for modular applications. After playing with Squide's local module feature for a while, we discovered that Squide offers significant value even for non-federated applications, which triggered this shift in philosophy."]},{"l":"Breaking changes"},{"l":"Removed","p":["The useAreModulesRegistered hook has been removed, use the useIsBootstrapping hook instead.","The useAreModulesReady hook has been removed, use the useIsBootstrapping hook instead.","The useIsMswStarted hook has been removed, use the useIsBootstrapping hook instead.","The completeModuleRegistrations function as been removed use the useDeferredRegistrations hook instead.","The completeLocalModulesRegistrations function has been removed use the useDeferredRegistrations hook instead.","The completeRemoteModuleRegistrations function has been removed use the useDeferredRegistrations hook instead.","The useSession hook has been removed, define your own React context instead.","The useIsAuthenticated hook has been removed, define your own React context instead.","The sessionAccessor option has been removed from the FireflyRuntime options, define your own React context instead.","The ManagedRoutes placeholder has been removed, use PublicRoutes and ProtectedRoutes instead."]},{"l":"Renamed","p":["The setMswAsStarted function has been renamed to setMswIsReady.","A route definition $name option has been renamed to $id.","The registerRoute parentName option has been renamed to parentId."]},{"l":"Others","p":["The @squide/firefly package now takes a peerDependency on @tanstack/react-query.","The @squide/firefly package doesn't takes a peerDependency on react-error-boundary anymore."]},{"l":"Removed support for deferred routes","p":["Deferred registration functions no longer support route registration; they are now exclusively used for registering navigation items. Since deferred registration functions can now be re-executed whenever the global data changes, registering routes in deferred registration functions no longer makes sense as updating the routes registry after the application has bootstrapped could lead to issues.","This change is a significant improvement for Squide's internals, allowing us to eliminate quirks like:","Treating unknown routes as protected: When a user initially requested a deferred route, Squide couldn't determine if the route was public or protected because it wasn't registered yet. As a result, for that initial request, the route was considered protected, even if the deferred registration later registered it as public.","Mandatory wildcard * route registration: Previously, Squide's bootstrapping would fail if the application didn't include a wildcard route.","Before:","Now:"]},{"l":"Conditional routes","p":["To handle direct access to a conditional route, each conditional route's endpoint should return a 403 status code if the user is not authorized to view the route. Those 403 errors should then be handled by the nearest error boundary."]},{"i":"plugins-constructors-now-requires-a-runtime-instance","l":"Plugin's constructors now requires a runtime instance","p":["Prior to this release, plugin instances received the current runtime instance through a _setRuntime function. This approach caused issues because some plugins required a reference to the runtime at instantiation. To address this, plugins now receive the runtime instance directly as a constructor argument.","Before:","Now:"]},{"l":"Plugins now registers with a factory function","p":["Prior to this release, the FireflyRuntime accepted plugin instances as options. Now, FireflyRuntime accepts factory functions instead of plugin instances. This change allows plugins to receive the runtime instance as a constructor argument.","Before:","Now:"]},{"l":"Rewrite of the AppRouter component","p":["This release features a full rewrite of the AppRouter component. The AppRouter component used to handle many concerns like global data fetching, deferred registrations, error handling and a loading state. Those concerns have been delegated to the consumer code, supported by the new useIsBootstrapping, usePublicDataQueries, useProtectedDataQueries and useDeferredRegistrations hooks.","Before:","Now:"]},{"l":"New hooks and functions","p":["A new useIsBoostrapping hook is now available.","A new useDeferredRegistrations hook is now available.","A new usePublicDataQueries hook is now available.","A new useProtectedDataQueries hook is now available.","A new isGlobalDataQueriesError function is now available.","A new registerPublicRoute function is now available."]},{"l":"Improvements","p":["Deferred registration functions now always receive a data argument.","Deferred registration functions now receives a new operations argument.","Navigation items now include a $canRender option, enabling modules to control whether a navigation item should be rendered."]},{"i":"new-id-option-for-navigation-items","l":"New $id option for navigation items","p":["Navigation items now supports a new $id option. Previously, most navigation item React elements used a key property generated by concatenating the item's level and index, which goes against React's best practices:","It wasn't that much of a big deal since navigation items never changed once the application was bootstrapped. Now, with the deferred registration functions re-executing when the global data changes, the registered navigation items can be updated post-bootstrapping. The new $id option allows the navigation item to be configured with a unique key at registration, preventing UI shifts.","The configured $id option is then passed as a key argument to the useRenderedNavigationItems rendering functions:","If no $id is configured for a navigation item, the key argument will be a concatenation of the level and index argument."]},{"l":"Migrate an host application","p":["A migration example from v8 to v9 is available for the wl-squide-monorepo-template.","Add a dependency to @tanstack/react-query. View example","Add an $id option to the navigation item registrations. View example","Add or update the AuthenticationBoundary component to use the new useIsAuthenticated hook. Global data fetch request shouldn't be throwing 401 error anymore when the user is not authenticated. View example","Convert all deferred routes into static routes. View example","Create a TanStackSessionManager class and the SessionManagerContext. Replace the session's deprecated hooks by creating the customs useSession and useIsAuthenticated hooks. View example","errorElement is removed and somewhat replaced by a root error boundary","fallbackElement becomes useIsBootstrapping","onCompleteRegistrations becomes useDeferredRegistrations","onLoadProtectedData+ isProtectedDataLoaded becomes useProtectedDataQueries","onLoadPublicData+ isPublicDataLoaded becomes usePublicDataQueries","Remove the sessionAccessor option from the FireflyRuntime instance. Update the BootstrappingRoute component to create a TanStackSessionManager instance and share it down the component tree using a SessionManagedContext provider. View example","Replace the ManagedRoutes placeholder with the new PublicRoutes and ProtectedRoutes placeholders. View example","The v9.0 release introduces several breaking changes affecting the host application code. Follow these steps to migrate an existing host application:","Transition to the new AppRouter component. View example","Update the AuthenticatedLayout component to use the new key argument. View example","Update the AuthenticatedLayout component to use the session manager instance to clear the session. Retrieve the session manager instance from the context defined in the BootstrappingRoute component using the useSessionManager hook. View example"]},{"l":"Root error boundary","p":["When transitioning to the new AppRouter component, make sure to nest the RootErrorBoundary component within the AppRouter component's render function.","Before:","Now:"]},{"l":"Migrate a module","p":["A migration example from v8 to v9 is available for the wl-squide-monorepo-template.","The changes in v9.0 have minimal impact on module code. To migrate an existing module, follow these steps:","Convert all deferred routes into static routes. View example","Add a $id option to the navigation item registrations. View example"]},{"l":"Isolated development","p":["If your module is set up for isolated development, ensure that you also apply the host application migration steps to your isolated setup."]}],[{"i":"migrate-to-firefly-v93","l":"Migrate to firefly v9.3","p":["Before following this guide, make sure that you migrated to v9.0."]},{"l":"Deprecation","p":["The registerLocalModules function has been deprecated, use the bootstrap function instead.","The registerRemoteModules function has been deprecated, use the bootstrap function instead.","The setMswAsReady function has been deprecated, use the bootstrap function instead."]},{"l":"Migrate an host application","p":["The bootstrap function is a new primitive that simplifies the bootstrapping of a Squide application. It replaces the registerLocalModules, registerRemoteModules and setMswAsReady functions."]},{"l":"Modules registration","p":["To update an application's module registration code, replace the registerLocalModules and registerRemoteModules functions with a call to the bootstrap function:","Before:","After:"]},{"l":"Mock Service Worker","p":["The MSW bootstrapping logic has been moved from user code to the bootstrap function. To update an application, replace the user code with the startMsw option of the bootstrap function.","Before:","After:"]}],[{"l":"Reference"},{"l":"Artefacts","p":["Packages"]},{"l":"API"},{"l":"Runtime","p":["FireflyRuntime class","RuntimeContext","useRuntime","useRuntimeMode","useRoutes","useNavigationItems","useLogger","usePlugin"]},{"l":"Registration","p":["bootstrap","registerLocalModules","registerRemoteModules","useDeferredRegistrations","mergeDeferredRegistrations"]},{"l":"Routing","p":["AppRouter","PublicRoutes","ProtectedRoutes","useRenderedNavigationItems","useIsBoostrapping","useRouteMatch","useIsRouteProtected","resolveRouteSegments","isNavigationLink"]},{"l":"Logging","p":["Logger","ConsoleLogger"]},{"l":"Messaging","p":["EventBus","useEventBusDispatcher","useEventBusListener"]},{"l":"Plugins","p":["Plugin"]},{"l":"webpack","p":["defineDevHostConfig","defineDevRemoteModuleConfig","defineBuildHostConfig","defineBuildRemoteModuleConfig"]},{"l":"TanStack Query","p":["usePublicDataQueries","useProtectedDataQueries","isGlobalDataQueriesError"]},{"l":"Mock Service Worker","p":["setMswAsReady"]},{"l":"i18next","p":["i18nextPlugin","getI18nextPlugin","useChangeLanguage","useCurrentLanguage","useI18nextInstance","I18nextNavigationItemLabel"]},{"l":"Honeycomb","p":["registerHoneycombInstrumentation","setGlobalSpanAttributes"]},{"l":"Environment variables","p":["EnvironmentVariablesPlugin","getEnvironmentVariablesPlugin","useEnvironmentVariable","useEnvironmentVariables"]},{"l":"Fakes","p":["Squide offers a collection of fake implementations designed to facilitate the set up of a module isolated environment.","LocalStorageSessionManager","ReadonlySessionLocalStorage"]}],[{"l":"Packages","p":["@squide/core","@squide/env-vars","@squide/fakes","@squide/firefly","@squide/firefly-honeycomb","@squide/firefly-webpack-configs","@squide/i18next","@squide/module-federation","@squide/msw","@squide/react-router","@squide/webpack-configs","A collection of fake implementations to facilitate the development of federated modules.","Add support for environment variables.","Add support for i18next.","Add support for Module Federation.","Add support for MSW.","Core functionalities of Squide.","Description","Honeycomb instrumentation for the Squide firefly technology stack.","Name","NPM","npm version","Specific implementation of the core functionalities to support React Router.","Squide for the firefly technology stack.","Utilities to configure webpack.","webpack configuration helpers for the Squide firefly technology stack."]}],[{"l":"FireflyRuntime class","p":["A runtime instance give modules access to functionalities such as routing, navigation, request handlers and logging."]},{"l":"Reference"},{"l":"Parameters","p":["options: An optional object literal of options:","mode: An optional mode to optimize Squide for production. Values are development(default) and production.","useMsw: An optional boolean value indicating whether or not to create the runtime with Mock Service Work(MSW) support.","loggers: An optional array of Logger instances.","plugins: An optional array of Plugin factory functions."]},{"l":"Methods","p":["registerRoute(route, options?): Register a route.","registerNavigationItem(navigationItem, options?): Register a navigation item.","getNavigationItems(menuId?): Retrieve the registered navigation items.","registerRequestHandlers(handlers): Register the MSW request handlers.","getPlugin(name): Retrieve the registered plugin by the specified name."]},{"l":"Getters","p":["mode: Retrieve the runtime mode.","routes: Retrieve the registered routes.","requestHandlers: Retrieve the registered MSW request handlers.","plugins: Retrieve the registered plugins.","logger: Retrieve the runtime logger.","eventBus: Retrieve the runtime event bus.","isMswEnabled: Indicate whether or not MSW is enabled."]},{"l":"Usage"},{"l":"Create a runtime instance"},{"l":"Change the runtime mode"},{"l":"Use Mock Service Worker"},{"l":"Register routes","p":["route: accept any properties of a React Router Route component with the addition of:","$id: An optional identifier for the route. Usually used to nest routes under a specific route.","$visibility: An optional visibility indicator for the route. Accepted values are public or protected.","options: An optional object literal of options:","hoist: An optional boolean value to register the route at the root of the router. The default value is false.","parentPath: An optional path of a parent route to register this new route under.","parentId: An optional id of a parent route to register this new route under."]},{"l":"Register an hoisted route","p":["Unlike a regular route, a hoisted route is added at the root of the router, outside of the host application's root layout, root error boundary and even root authentication boundary. This means that a hoisted route has full control over its rendering. To mark a route as hoisted, provide an hoist option to the route options.","By declaring a route as hoisted, other parts of the application will not be isolated anymore from this route's failures and the route will not be protected anymore by the application authenticated boundary.","To avoid breaking the entire application when an hoisted route encounters unhandled errors, it is highly recommended to declare a React Router's errorElement property for each hoisted route.","If the hoisted route requires an authentication, make sure to wrap the route with an authentication boundary or to handle the authentication within the route."]},{"l":"Register a public route","p":["When registering a route, a value can be provided indicating whether the route is public or protected. This is especially useful when dealing with code that fetches global data for protected routes(e.g. a session). Although a route definition accepts a $visibility value, we recommended using the runtime registerPublicRoute function to register a root public route instead.","A nested route can also be public:","When no $visibility indicator is provided, a route is considered protected."]},{"l":"Register a route with an id","p":["The registerRoute function accepts a parentId option, allowing a route to be nested under an existing parent route. When searching for the parent route matching the parentId option, the parentId will be matched against the $id option of every route.","A $id option should only be defined for routes that doesn't have a path like an error boundary or an authentication boundary."]},{"l":"Register nested routes","p":["React router nested routes enable applications to render nested layouts at various points within the router tree. This is quite helpful for modular applications as it enables composable and decoupled UI.","To fully harness the power of nested routes, the registerRoute function allows a route to be registered under any previously registered route, even if that route was registered by another module. The only requirement is that the parent route must have been registered with the registerRoute function.","When registering a new route with the registerRoute function, to render the route under a parent route, specify a parentPath option that matches the parent route's path option:","Or a parentId option that matches the parent route's $id option:","Learn more about using nested routes for modular tabs","Likewise any other React Router routes, the path option of a route rendered under an existing parent route must be an absolute path. For example, if a parent route path is /layout, the path option of a route rendered under that parent route and responding to the /page-1 url, should be /layout/page-1."]},{"l":"Retrieve routes","p":["The registered routes are accessible from a FireflyRuntime instance, but keep in mind that the preferred way to retrieve the routes is with the useRoutes hook."]},{"l":"Register navigation items","p":["item: NavigationSection | NavigationLink.","options: An optional object literal of options:","menuId: An optional menu id to associate the item with.","sectionId: An optional section id of a parent navigation section to register this new item under.","A Squide navigation item can either be a NavigationLink or a NavigationSection. Both types can be intertwined to create a multi-level menu hierarchy. A NavigationSection item is used to setup a new level while a NavigationLink define a link."]},{"l":"NavigationLink","p":["Accept any properties of a React Router Link component with the addition of:","$id: An optional identifier for the link. Usually used as the React element key property.","$label: The link text.","$canRender: An optional function accepting an object and returning a boolean indicating whether or not the link should be rendered.","$priority: An order priority affecting the position of the item in the menu (higher first)","$additionalProps: Additional properties to be forwarded to the link renderer."]},{"l":"NavigationSection","p":["$id: An optional identifier for the section. Usually used to nest navigation items under a specific section and as the React element key property.","$label: The section text.","$canRender: An optional function accepting an object and returning a boolean indicating whether or not the section should be rendered.","$priority: An order priority affecting the position of the item in the menu (higher first)","$additionalProps: Additional properties to be forwarded to the section renderer.","children: The section content.","We recommend always providing an $id option for a navigation item, as it ensures the menus doesn't flicker when deferred registrations are updated. Be sure to use a unique identifier.","Setup the host application to render navigation items"]},{"l":"Register a navigation item with an id","p":["The registerNavigationItem function accepts a sectionId option, allowing a navigation item to be nested under an existing navigation section. When searching the parent navigation section matching the sectionId option, the sectionId will be match against the $id option of every navigation item.","Additionally, when combined with the useRenderedNavigationItems function, the $id option will be used as the React element key property."]},{"l":"Register nested navigation items","p":["Similarly to nested routes, a navigation item can be nested under an existing section be specifying a sectionId option that matches the section's $id option:","Navigation items can also be nested by registering multipe items in a single registration block:"]},{"l":"Register navigation items for a specific menu","p":["By default, every navigation item registered with the registerNavigationItem function is registered as part of the root navigation menu. To register a navigation item for a different navigation menu, specify a menuId option when registering the items."]},{"l":"Sort navigation items","p":["A $priority option can be added to a navigation item to affect it's position in the menu. The sorting algorithm is as follow:","By default a navigation item have a priority of 0.","If no navigation item have a priority, the items are positioned according to their registration order.","If an item have a priority 0, the item will be positioned before any other items with a lower priority (or without an explicit priority value).","If an item have a priority 0, the item will be positioned after any other items with a higher priority (or without an explicit priority value)."]},{"l":"Use dynamic segments for navigation items","p":["Learn more about rendering navigation items with dynamic segments"]},{"l":"Use a React element as navigation item label"},{"l":"Style a navigation item"},{"l":"Open a navigation link in a new tab"},{"l":"Conditionally render a navigation item","p":["It's the responsibility of the code rendering the menu to execute the navigation items $canRender function and conditionally render the items based on the return value."]},{"l":"Render additional props on a navigation item","p":["It's the responsibility of the code rendering the menu to handle the additional properties."]},{"l":"Retrieve navigation items","p":["The registered navigation items are accessible from a FireflyRuntime instance, but keep in mind that the preferred way to retrieve the navigation items is with the useNavigationItems hook.","By default, the getNavigationItems will return the navigation items for the root menu:","To retrieve the navigation items for a specific navigation menu, provide a menuId:"]},{"l":"Register request handlers","p":["The registered handlers must be Mock Service Worker request handlers:","Learn more about setuping Mock Service Worker"]},{"l":"Retrieve request handlers"},{"l":"Log a message"},{"l":"Log a message to specific logger instances"},{"l":"Use the event bus"},{"l":"Register a plugin","p":["The plugin factory function receives the Runtime instance as parameter.","Learn more about plugins"]},{"l":"Retrieve a plugin","p":["Learn more about plugins"]}],[{"l":"RuntimeContext","p":["React context to share a FireflyRuntime instance between an host application and the modules."]},{"l":"Reference"},{"l":"Properties","p":["value: A FireflyRuntime instance."]},{"l":"Usage"},{"l":"Provide a runtime instance"},{"l":"Retrieve a runtime instance"}],[{"l":"useRuntime","p":["Retrieve a FireflyRuntime instance.","Consider using useRoutes, useNavigationItems, useLogger instead of useRuntime."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["A FireflyRuntime instance."]},{"l":"Usage"}],[{"l":"useRuntimeMode","p":["Retrieve the runtime mode."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["Either development or production."]},{"l":"Usage"}],[{"l":"useRoutes","p":["Retrieve the registered routes from the FireflyRuntime instance."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["An array of Route."]},{"l":"Usage"}],[{"l":"useNavigationItems","p":["Retrieve the registered navigation items from the FireflyRuntime instance."]},{"l":"Reference"},{"l":"Parameters","p":["options: An optional object literal of options:","menuId: An optional id to retrieve the navigation menu for a specific menu."]},{"l":"Returns","p":["An array of NavigationLink | NavigationSection."]},{"l":"NavigationLink","p":["Accept any properties of a React Router Link component with the addition of:","$id: An optional identifier for the link. Usually used as the React element key property.","$label: The link label. Could either by a string or a ReactNode.","$canRender: An optional function accepting an object and returning a boolean indicating whether or not the link should be rendered.","$additionalProps: An optional object literal of additional props to apply to the link component."]},{"l":"NavigationSection","p":["$id: An optional identifier for the section. Usually used to nest navigation items under a specific section and as the React element key property.","$label: The section label. Could either by a string or a ReactNode.","$canRender: An optional function accepting an object and returning a boolean indicating whether or not the section should be rendered.","$additionalProps: An optional object literal of additional props to apply to the section component.","children: The section items."]},{"l":"Usage"},{"l":"Retrieve the items for the root menu"},{"l":"Retrieve the items for a specific menu"}],[{"l":"useLogger","p":["Retrieve a RuntimeLogger instance from the FireflyRuntime instance. The returned logger will log messages to all registered Logger instances."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["A RuntimeLogger instance."]},{"l":"Usage"}],[{"l":"useLoggers","p":["Retrieve a RuntimeLogger instance from the FireflyRuntime instance. The returned instance will log messages to the specified Logger instances."]},{"l":"Reference"},{"l":"Parameters","p":["names: The name of the logger instances to log messages to."]},{"l":"Returns","p":["A RuntimeLogger instance."]},{"l":"Usage"}],[{"l":"usePlugin","p":["Retrieve a plugin from the FireflyRuntime instance."]},{"l":"Reference"},{"l":"Parameters","p":["pluginName: The name of the plugin."]},{"l":"Returns","p":["A plugin instance if the plugin has been registered, otherwise an Error is thrown."]},{"l":"Usage"}],[{"l":"bootstrap","p":["Register local or remote modules and optionally start MSW. During the registration process, the modules' registration function will be invoked with a FireflyRuntime instance and an optional context object. To defer the registration of specific navigation items, a registration function can return an anonymous function.","A local module is a regular module that is part of the host application build and is bundled at build time, as opposed to a remote module which is loaded at runtime from a remote server.","A remote module is a module that is not part of the current build but is loaded at runtime from a remote server."]},{"l":"Reference"},{"l":"Parameters","p":["runtime: A FireflyRuntime instance.","options: An optional object literal of options:","localModules: An optional array of ModuleRegisterFunction.","remotes: An optional array of RemoteDefinition.","startMsw: An optional function to register MSW request handlers and start MSW service. This function is required if MSW is enabled.","context: An optional context object that will be pass to the registration function."]},{"l":"Returns","p":["A Promise object including LocalModuleRegistrationError and RemoteModuleRegistrationError if any error happens during the registration process."]},{"l":"LocalModuleRegistrationError","p":["error: The original Error object."]},{"l":"RemoteModuleRegistrationError","p":["remoteName: The name of the remote module that failed to load.","moduleName: The name of the module that Squide attempted to recover.","error: The original Error object."]},{"l":"Usage"},{"l":"Register a local module"},{"l":"Register a remote module"},{"l":"Start MSW"},{"l":"Provide a registration context"},{"l":"Handle registration errors"},{"l":"Defer the registration of navigation items","p":["Sometimes, data must be fetched to determine which navigation items should be registered by a given module. To address this, Squide offers a two-phase registration mechanism:","The first phase allows modules to register their navigation items that are not dependent on initial data(in addition to their routes and MSW request handlers when fake endpoints are available).","The second phase enables modules to register navigation items that are dependent on initial data. Such a use case would be determining whether a navigation item should be registered based on a feature flag. We refer to this second phase as deferred registrations.","To defer a registration to the second phase, a module registration function can return an anonymous function matching the DeferredRegistrationFunction type: (data, operation: register | update) = Promise | void.","Once the modules are registered, the deferred registration functions will be executed with the deferred data and register as the value for the operation argument. Afterward, whenever the deferred data changes, the deferred registration functions will be re-executed with the updated deferred data and update as the value for the operation argument.","Routes are always registered, but navigation items can be conditionally registered using a deferred registration function.","useDeferredRegistrations"]},{"l":"Use the deferred registration operation argument"},{"l":"Remote definition","p":["To ease the configuration of remote modules, make sure that you first import the RemoteDefinition type and assign it to your remote definitions array declaration."]},{"l":"name","p":["The name option of a remote definition must match the name option defined in the remote module ModuleFederationPlugin configuration.","If you are using either the Squide defineDevRemoteModuleConfig or defineBuildRemoteModuleConfig functions to add the ModuleFederationPlugin to the remote module webpack configuration object, then the remote module name is the second argument of the function.","In the following exemple, the remote module name is remote1."]}],[{"l":"registerLocalModules","p":["This function is deprecated, use the bootstrap function instead.","Register one or many local module(s). During the registration process, the specified registration function will be invoked with a FireflyRuntime instance and an optional context object. To defer the registration of specific navigation items, a registration function can return an anonymous function.","A local module is a regular module that is part of the host application build and is bundled at build time, as opposed to a remote module which is loaded at runtime from a remote server. Local modules are particularly valuable when launching a new product with an evolving business domain or when undergoing a migration from a monolithic application to a federated application."]},{"l":"Reference"},{"l":"Parameters","p":["registerFunctions: An array of ModuleRegisterFunction.","runtime: A FireflyRuntime instance.","options: An optional object literal of options:","context: An optional context object that will be pass to the registration function."]},{"l":"Returns","p":["A Promise object with an array of LocalModuleRegistrationError if any error happens during the registration."]},{"l":"LocalModuleRegistrationError","p":["error: The original Error object."]},{"l":"Usage"},{"l":"Register a local module"},{"l":"Defer the registration of navigation items","p":["Sometimes, data must be fetched to determine which navigation items should be registered by a given module. To address this, Squide offers a two-phase registration mechanism:","The first phase allows modules to register their navigation items that are not dependent on initial data(in addition to their routes and MSW request handlers when fake endpoints are available).","The second phase enables modules to register navigation items that are dependent on initial data. Such a use case would be determining whether a navigation item should be registered based on a feature flag. We refer to this second phase as deferred registrations.","To defer a registration to the second phase, a module registration function can return an anonymous function matching the DeferredRegistrationFunction type: (data, operation: register | update) = Promise | void.","Once the modules are registered, the deferred registration functions will be executed with the deferred data and register as the value for the operation argument. Afterward, whenever the deferred data changes, the deferred registration functions will be re-executed with the updated deferred data and update as the value for the operation argument.","Routes are always registered, but navigation items can be conditionally registered using a deferred registration function.","useDeferredRegistrations"]},{"l":"Use the deferred registration operation argument"},{"l":"Handle registration errors"}],[{"l":"registerRemoteModules","p":["This function is deprecated, use the bootstrap function instead.","Register one or many remote module(s). During the registration process, the module register function will be invoked with a FireflyRuntime instance and an optional context object. To defer the registration of navigation items, a registration function can return an anonymous function.","A remote module is a module that is not part of the current build but is loaded at runtime from a remote server."]},{"l":"Reference"},{"l":"Parameters","p":["remotes: An array of RemoteDefinition.","runtime: A FireflyRuntime instance.","options: An optional object literal of options:","context: An optional context object that will be pass to the registration function."]},{"l":"Returns","p":["A Promise object with an array of RemoteModuleRegistrationError if any error happens during the registration."]},{"l":"RemoteModuleRegistrationError","p":["remoteName: The name of the remote module that failed to load.","moduleName: The name of the module that Squide attempted to recover.","error: The original Error object."]},{"l":"Usage"},{"l":"Register a remote module"},{"l":"Defer the registration of navigation items","p":["Sometimes, data must be fetched to determine which navigation items should be registered by a given module. To address this, Squide offers a two-phase registration mechanism:","The first phase allows modules to register navigation items that are not dependent on initial data (in addition to their routes and MSW request handlers when fake endpoints are available).","The second phase enables modules to register navigation items that are dependent on initial data. Such a use case would be determining whether a navigation item should be registered based on a feature flag. We refer to this second phase as deferred registrations.","To defer a registration to the second phase, a module registration function can return an anonymous function matching the DeferredRegistrationFunction type: (data, operation: register | update) = Promise | void.","Once the modules are registered, the deferred registration functions will be executed with the deferred data and register as the value for the operation argument. Afterward, whenever the deferred data changes, the deferred registration functions will be re-executed with the updated deferred data and update as the value for the operation argument.","Routes are always registered, but navigation items can be conditionally registered using a deferred registration function.","useDeferredRegistrations"]},{"l":"Use the deferred registration operation argument"},{"l":"Handle registration errors"},{"l":"Remote definition","p":["To ease the configuration of remote modules, make sure that you first import the RemoteDefinition type and assign it to your remote definitions array declaration."]},{"l":"name","p":["The name option of a remote definition must match the name option defined in the remote module ModuleFederationPlugin configuration.","If you are relying on either the Squide defineDevRemoteModuleConfig or defineBuildRemoteModuleConfig functions to add the ModuleFederationPlugin to the remote module webpack configuration object, then the remote module name is the second argument of the function.","In the following exemple, the remote module name is remote1."]}],[{"l":"useDeferredRegistrations","p":["Register the modules deferred registration functions when the global data is initially fetched or update the deferred registration functions whenever the global data change.","This hook should always be used in combination with deferred registration functions and with either the usePublicDataQueries hook or the useProtectedDataQueries hook (can be both)."]},{"l":"Reference"},{"l":"Parameters","p":["data: An object literal of data that will be passed to the deferred registration functions.","options: An optional object literal of options:","onError: An optional function receiving an DeferredRegistrationsErrorsObject object as an argument."]},{"l":"DeferredRegistrationsErrorsObject","p":["localModuleErrors: An array of errors that occured during the deferred registrations of local modules.","error: The original Error object.","remoteModuleErrors: An array of errors that occured during the deferred registrations of remote modules.","remoteName: The name of the remote module that failed to load.","moduleName: The name of the module that Squide attempted to recover."]},{"l":"Returns","p":["Nothing"]},{"l":"Usage"},{"l":"Register or update deferred registrations"},{"l":"Handle registration errors"}],[{"l":"mergeDeferredRegistrations","p":["Utility function that takes an array of deferred registration functions and returns a single function wrapping and merging all the provided deferred registration functions.","If the provided array contains undefined values, they will safely be ignored."]},{"l":"Reference"},{"l":"Parameters","p":["candidates: An array of deferred registration functions."]},{"l":"Returns","p":["A function or undefined:","If multiple deferred registration functions are provided, a single function wrapping and merging all the provided deferred registration functions is returned.","If a single deferred registration function is provided, the provided function is returned.","If no deferred registration functions are provided, undefined is returned."]},{"l":"Usage"}],[{"l":"AppRouter","p":["A component that sets up Squide's primitives with a React Router instance.","The AppRouter component is required for any Squide application."]},{"l":"Reference"},{"l":"Properties","p":["waitForMsw: A boolean value indicating whether or not Squide should delay the rendering of the requested page until the Mock Service Worker request handlers are registered.","waitForPublicData: An optional boolean value indicating whether or not Squide should delay the rendering of the requested page until the public data is ready. The default value is false.","waitForProtectedData: An optional boolean value indicating whether or not Squide should delay the rendering of the requested page until the protected data is ready. The default value is false.","children: A render function defining a RouterProvider component with rootRoute, registeredRoutes and routerProviderProps."]},{"l":"Usage"},{"l":"Define a router provider","p":["The rootRoute component provided as an argument to the AppRouter rendering function must always be rendered as a parent of the registeredRoutes."]},{"l":"Define a loading component","p":["A BootstrappingRoute component is introduced in the following example because the useIsBootstrapping hook must be rendered as a child of rootRoute."]},{"l":"Define a root error boundary","p":["A React Router errorElement retrieves the current error using the useRouteError hook.","The root error boundary should always wrap the registeredRoutes and, when application, the BootstrapingRoute component."]},{"l":"Delay rendering until MSW is ready"},{"l":"Delay rendering until the public data is ready","p":["A BootstrappingRoute component is introduced in the following example because the usePublicDataQueries hook must be rendered as a child of rootRoute."]},{"l":"Delay rendering until the protected data is ready","p":["A BootstrappingRoute component is introduced in the following example because the useProtectedDataQueries hook must be rendered as a child of rootRoute."]}],[{"l":"PublicRoutes","p":["A placeholder indicating where in the routing tree should the public routes be rendered. The PublicRoutes placeholder concept is similar to React Router's outlet, it's a pipeline to inject routes at a predetermined location.","A public route is a route with a public visibility that is not hoisted or nested with either a parentPath or parentId option."]},{"l":"Reference"},{"l":"Properties","p":["None"]},{"l":"Usage","p":["The route defining the PublicRoutes placeholder must be hoisted; otherwise, there will be an infinite loop as the PublicRoutes placeholder will render within itself."]}],[{"l":"ProtectedRoutes","p":["A placeholder indicating where in the routing tree should the protected routes be rendered. The ProtectedRoutes placeholder concept is similar to React Router's outlet, it's a pipeline to inject routes at a predetermined location.","A protected route is a route with a protected visibility that is not hoisted or nested with either a parentPath or parentId option."]},{"l":"Reference"},{"l":"Properties","p":["None"]},{"l":"Usage","p":["The route defining the ProtectedRoutes placeholder must be hoisted; otherwise, there will be an infinite loop as the ProtectedRoutes placeholder will render within itself."]}],[{"l":"useIsBootstrapping","p":["Indicate whether the application is currently being bootstrapped, such as registering modules, handling deferred registrations, preparing Mock Service Worker, fetching global data, etc."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["A boolean value indicating whether or not the application is bootstrapping."]},{"l":"Usage","p":["A BootstrappingRoute component is introduced in the following example because this hook must be rendered as a child of rootRoute."]}],[{"l":"useRenderedNavigationItems","p":["Recursively parse a navigation items structure to transform the items into React Elements.","The useNavigationItems hook returns the navigation items tree structure as is, meaning the consumer has to recursively parse the structure to transform the items into actual React Elements.","As it's a non-trivial process, Squide provides this utility hook."]},{"l":"Reference"},{"l":"Parameters","p":["navigationItems: An array of NavigationLink | NavigationSection to render.","renderItem: A function to render a link from a navigation item","renderSection: A function to render a section from a collection of items."]},{"l":"NavigationLink","p":["Accept any properties of a React Router Link component with the addition of:","$id: An optional identifier for the link. Usually used as the React element key property.","$label: The link label. Could either by a string or a ReactNode.","$canRender: An optional function accepting an object and returning a boolean indicating whether or not the link should be rendered.","$additionalProps: An optional object literal of additional props to apply to the link component."]},{"l":"NavigationSection","p":["$id: An optional identifier the section. Usually used to nest navigation items undern a specific section and as the React element key property.","$label: The section label. Could either by a string or a ReactNode.","$canRender: An optional function accepting an object and returning a boolean indicating whether or not the section should be rendered.","$additionalProps: An optional object literal of additional props to apply to the section component.","children: The section items."]},{"l":"Returns","p":["An array of ReactElement."]},{"l":"Usage"},{"l":"Render nested items","p":["We recommend always providing an $id option for a navigation item, as it ensures the menus doesn't flicker when deferred registrations are updated. Be sure to use a unique key.","When no $id option is provided, a default key argument is computed based on the index and level properties. While this works in most cases, the default key cannot guarantee that the menu won't flicker during updates."]},{"l":"Render dynamic segments","p":["The to option of a navigation item can include dynamic segments (/user-profile/:userId), enabling the rendering of dynamic routes based on contextual values. To resolve a route dynamic segments, use the resolveRouteSegments function."]}],[{"l":"useRouteMatch","p":["Execute React Router's matching algorithm against Squide's routes registry and a given location to determine if any route match the location."]},{"l":"Reference"},{"l":"Parameters","p":["locationArg: The location to match the route paths against.","options: An optional object literal of options:","throwWhenThereIsNoMatch: Whether or not to throw an Error if no route match locationArg."]},{"l":"Returns","p":["A Route object if there's a matching route, otherwise if throwWhenThereIsNoMatch is enabled and no route match the given location, an Error is thrown.","If throwWhenThereIsNoMatch is disabled and there's no route matching locationArg, undefined is returned."]},{"l":"Usage"},{"l":"Using useLocation"},{"i":"using-windowlocation","l":"Using window.location"}],[{"l":"resolveRouteSegments","p":["Replace a route segments (paths starting with :) with the provided values. For a value to be applied to a segment, the value key must match the segment minus the :."]},{"l":"Reference"},{"l":"Parameters","p":["to: A route with segments.","values: An object literal of segment values."]},{"l":"Returns","p":["The resolved route."]},{"l":"Usage"}],[{"l":"useIsRouteProtected","p":["Determine whether or not a route is considered as protected.","To take advantage of this hook, make sure to add a $visibility hint to your public pages."]},{"l":"Reference"},{"l":"Parameters","p":["route: A Route object."]},{"l":"Returns","p":["A boolean value indicating whether or not the matching route is protected."]},{"l":"Usage"}],[{"l":"isNavigationLink","p":["Indicate whether or not a navigation item is a NavigationLink. This utility is particularly handy when rendering a menu with nested items."]},{"l":"Reference"},{"l":"Parameters","p":["item: A navigation item rendering props."]},{"l":"Returns","p":["A boolean value indicating whether or not the navigation item should be rendered as a link."]},{"l":"Usage"}],[{"l":"ConsoleLogger","p":["A basic console logger."]},{"l":"Reference"},{"l":"Parameters","p":["logLevel: An optional minimum level for the logger to output a log entry to the console (default is LogLevel.debug)."]},{"l":"Usage"},{"l":"Log everything"},{"l":"Only log errors","p":["To restrict the logs to error or critical, change the minimum log level to error:"]}],[{"l":"Logger","p":["An abstract base class to define a logger."]},{"l":"Usage"},{"l":"Define a custom logger"}],[{"l":"EventBus","p":["A basic implementation of a pub/sub mechanism enabling loosely coupled between the host application and the modules."]},{"l":"Reference"},{"l":"Parameters","p":["options: An optional object literal of options:","logger: An optional logger to facilitate debugging."]},{"l":"Methods","p":["addListener(eventName, callback, options?): Register the callback event listener for eventName.","removeListener(eventName, callback, options?): Remove the callback event listener for eventName.","dispatch(eventName, payload?): Dispatch an event to the listeners of eventName."]},{"l":"Usage"},{"l":"Create an event bus instance"},{"l":"Add a listener","p":["When possible, prefer useEventBusListener to eventBus.addListener."]},{"l":"Remove a listener"},{"l":"Dispatch an event","p":["When possible, prefer useEventBusDispatcher to eventBus.dispatch."]}],[{"l":"useEventBusDispatcher","p":["Retrieve an EventBus instance from the FireflyRuntime instance provided by RuntimeContext and provide a function to dispatch an event."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["A dispatch function: (eventName: string, payload?: {}) = void."]},{"l":"Usage"}],[{"l":"useEventBusListener"},{"l":"Reference"},{"l":"Parameters","p":["eventName: The name of the event to listen for.","callback: A function to be executed when a event matching the provided name is dispatched.","options: An optional object literal of options:","once: Whether or not the event listener should be automatically removed once an event as been handled."]},{"l":"Returns","p":["Nothing"]},{"l":"Usage"}],[{"l":"Plugin","p":["An abstract base class to define a plugin."]},{"l":"Protected members","p":["_runtime: Access the plugin Runtime instance."]},{"l":"Getters","p":["name: Return the name of the plugin."]},{"l":"Usage"},{"l":"Define a plugin"},{"l":"Register a plugin"},{"l":"Use a plugin runtime instance"},{"l":"Retrieve a plugin from a runtime instance"},{"l":"Retrieve a plugin with a custom function","p":["We recommend pairing a plugin definition with a custom function to retrieve the plugin from a runtime instance.","Retrieving a plugin with a custom function doesn't require the consumer to remember the plugin name, and has the upside of inferring the typings."]}],[{"l":"defineDevHostConfig","p":["Creates a webpack configuration object that is adapted for a Squide host application in development mode.","This function is a wrapper built on top of @workleap/web-configs. Make sure to read the defineDevConfig documentation first."]},{"l":"Reference"},{"l":"Parameters","p":["swcConfig: An SWC configuration object.","port: The host application port.","remotes: An array of RemoteDefinition(view the Remote definition section).","options: An optional object literal of options:","Accepts most of webpack definedDevConfig predefined options.","htmlWebpackPluginOptions: An optional object literal accepting any options of the HtmlWebpackPlugin.","features: An optional object literal of feature switches to define additional shared dependencies.","i18next: Whether or not to add @squide/i18next as a shared dependency.","sharedDependencies: An optional object literal of additional (or updated) module federation shared dependencies.","moduleFederationPluginOptions: An optional object literal of ModuleFederationPlugin options."]},{"l":"Returns","p":["A webpack configuration object tailored for a Squide host application in development mode."]},{"l":"Default shared dependencies","p":["The defineDevHostConfig function will add the following shared dependencies as singleton by default:","react","react-dom","react-router-dom","@squide/core","@squide/react-router","@squide/module-federation","@squide/msw","For the full shared dependencies configuration, have a look at the defineConfig.ts file on Github."]},{"l":"Usage"},{"l":"Define a webpack config"},{"l":"Activate optional features","p":["Features must be activated on the host application as well as every remote module."]},{"l":"Specify additional shared dependencies","p":["Additional shared dependencies must be configured on the host application as well as every remote module."]},{"l":"Extend a default shared dependency","p":["In the previous code sample, the react shared dependency will be augmented with the strictVersion option. The resulting shared dependency will be:"]},{"l":"Override a default shared dependency","p":["In the previous code sample, the react shared dependency singleton option will be overrided by the newly provided value. The resulting shared dependency will be:"]},{"l":"Customize module federation configuration","p":["While you could customize the ModuleFederationPlugin configuration by providing your own object literal through the moduleFederationPluginOptions option, we recommend using the defineHostModuleFederationPluginOptions(options) function as it will take care of merging the custom options with the default plugin options.","applicationName: The host application name.","moduleFederationPluginOptions: An object literal of ModuleFederationPlugin options."]},{"l":"Remote definition"},{"l":"name","p":["The name option of a remote definition must match the name option defined in the remote module ModuleFederationPlugin configuration.","If you are relying on the Squide defineDevRemoteModuleConfig function to add the ModuleFederationPlugin to the remote module webpack configuration object, then the remote module name is the second argument of the function.","In the following exemple, the remote module name is remote1."]},{"l":"url","p":["The url option of a remote definition must match the publicPath of the remote module webpack configuration object.","In the following exemple, the remote module publicPath is http://localhost:8081.","The publicPath is built from the provided host and port values. Therefore, if the port value is 8081, then the generated publicPath would be http://localhost:8081:"]}],[{"l":"defineDevRemoteModuleConfig","p":["Creates a webpack configuration object that is adapted for a Squide remote module application in development mode.","This function is a wrapper built on top of @workleap/web-configs. Make sure to read the defineDevConfig documentation first."]},{"l":"Reference"},{"l":"Parameters","p":["swcConfig: An SWC configuration object.","applicationName: The remote module application name.","port: The remote module application port.","options: An optional object literal of options:","Accepts most of webpack definedDevConfig predefined options.","features: An optional object literal of feature switches to define additional shared dependencies.","i18next: Whether or not to add @squide/i18next as a shared dependency.","sharedDependencies: An optional object literal of additional (or updated) module federation shared dependencies.","moduleFederationPluginOptions: An optional object literal of ModuleFederationPlugin options."]},{"l":"Returns","p":["A webpack configuration object tailored for a Squide remote module application in development mode."]},{"l":"Conventions","p":["To fulfill Squide remote module requirements, the defineDevRemoteModuleConfig function will pre-configure the ModuleFederationPlugin with the following filename and exposes properties.","If the remote module port is 8081, the remote module bundle is available at http://localhost:8081/remoteEntry.js."]},{"l":"Default shared dependencies","p":["The defineDevRemoteModuleConfig function will add the following shared dependencies as singleton by default:","react","react-dom","react-router-dom","@squide/core","@squide/react-router","@squide/module-federation","@squide/msw","For the full shared dependencies configuration, have a look at the defineConfig.ts file on Github."]},{"l":"Usage"},{"l":"Define a webpack config"},{"l":"Activate additional features","p":["Features must be activated on the host application as well as every remote module."]},{"l":"Specify additional shared dependencies","p":["Additional shared dependencies must be configured on the host application as well as every remote module."]},{"l":"Extend a default shared dependency","p":["In the previous code sample, the react shared dependency will be augmented with the newly provided strictVersion option. The resulting shared dependency will be:"]},{"l":"Override a default shared dependency","p":["In the previous code sample, the react shared dependency singleton option will be overrided by the newly provided value. The resulting shared dependency will be:"]},{"l":"Customize module federation configuration","p":["While you could customize the ModuleFederationPlugin configuration by providing your own object literal through the moduleFederationPluginOptions option, we recommend using the defineRemoteModuleFederationPluginOptions(applicationName, options) function as it will take care of merging the custom options with the default plugin options.","applicationName: The host application name.","moduleFederationPluginOptions: An object literal of ModuleFederationPlugin options."]},{"l":"Expose an additional module"}],[{"l":"defineBuildHostConfig","p":["Creates a webpack configuration object that is adapted for a Squide host application in build mode.","This function is a wrapper built on top of @workleap/web-configs. Make sure to read the defineBuildConfig documentation first."]},{"l":"Reference"},{"l":"Parameters","p":["swcConfig: An SWC configuration object.","remotes: An array of RemoteDefinition(view the Remote definition section).","options: An optional object literal of options:","Accepts most of webpack definedBuildConfig predefined options.","htmlWebpackPluginOptions: An optional object literal accepting any options of the HtmlWebpackPlugin.","features: An optional object literal of feature switches to define additional shared dependencies.","i18next: Whether or not to add @squide/i18next as a shared dependency.","sharedDependencies: An optional object literal of additional (or updated) module federation shared dependencies.","moduleFederationPluginOptions: An optional object literal of ModuleFederationPlugin options."]},{"l":"Returns","p":["A webpack configuration object tailored for a Squide host application in build mode."]},{"l":"Default shared dependencies","p":["The defineBuildHostConfig function will add the following shared dependencies as singleton by default:","react","react-dom","react-router-dom","@squide/core","@squide/react-router","@squide/module-federation","@squide/msw","For the full shared dependencies configuration, have a look at the defineConfig.ts file on GitHub."]},{"l":"Usage"},{"l":"Define a webpack config"},{"l":"Activate additional features","p":["Features must be activated on the host application as well as every remote module."]},{"l":"Specify additional shared dependencies","p":["Additional shared dependencies must be configured on the host application as well as every remote module."]},{"l":"Extend a default shared dependency","p":["In the previous code sample, the react shared dependency will be augmented with the strictVersion option. The resulting shared dependency will be:"]},{"l":"Override a default shared dependency","p":["In the previous code sample, the react shared dependency singleton option will be overrided by the newly provided value. The resulting shared dependency will be:"]},{"l":"Customize module federation configuration","p":["While you could customize the ModuleFederationPlugin configuration by providing your own object literal through the moduleFederationPluginOptions option, we recommend using the defineHostModuleFederationPluginOptions(options) function as it will take care of merging the custom options with the default plugin options.","applicationName: The host application name.","moduleFederationPluginOptions: An object literal of ModuleFederationPlugin options."]},{"l":"Remote definition"},{"l":"name","p":["The name option of a remote definition must match the name option defined in the remote module ModuleFederationPlugin configuration.","If you are relying on the Squide defineBuildRemoteModuleConfig function to add the ModuleFederationPlugin to the remote module webpack configuration object, then the remote module name is the second argument of the function.","In the following exemple, the remote module name is remote1."]},{"l":"url","p":["The url option of a remote definition must match the publicPath of the remote module webpack configuration object.","In the following exemple, the remote module publicPath is http://localhost:8081."]}],[{"l":"defineBuildRemoteModuleConfig","p":["Creates a webpack configuration object that is adapted for a Squide remote module application in build mode.","This function is a wrapper built on top of @workleap/web-configs. Make sure to read the defineBuildConfig documentation first."]},{"l":"Reference"},{"l":"Parameters","p":["swcConfig: An SWC configuration object.","applicationName: The remote module application name.","options: An optional object literal of options:","Accepts most of webpack definedDevConfig predefined options.","features: An optional object literal of feature switches to define additional shared dependencies.","i18next: Whether or not to add @squide/i18next as a shared dependency.","sharedDependencies: An optional object literal of additional (or updated) module federation shared dependencies.","moduleFederationPluginOptions: An optional object literal of ModuleFederationPlugin options."]},{"l":"Returns","p":["A webpack configuration object tailored for a Squide remote module application in build mode."]},{"l":"Conventions","p":["To fulfill Squide remote module requirements, the defineBuildRemoteModuleConfig function will pre-configure the ModuleFederationPlugin with the following filename and exposes properties.","If the remote module publicPath is http://localhost/8081, the remote module bundle is available at http://localhost:8081/remoteEntry.js."]},{"l":"Default shared dependencies","p":["The defineBuildRemoteModuleConfig function will add the following shared dependencies as singleton by default:","react","react-dom","react-router-dom","@squide/core","@squide/react-router","@squide/module-federation","@squide/msw","For the full shared dependencies configuration, have a look at the defineConfig.ts file on Github."]},{"l":"Usage"},{"l":"Define a webpack config"},{"l":"Activate additional features","p":["Features must be activated on the host application as well as every remote module."]},{"l":"Specify additional shared dependencies","p":["Additional shared dependencies must be configured on the host application as well as every remote module."]},{"l":"Extend a default shared dependency","p":["In the previous code sample, the react shared dependency will be augmented with the newly provided strictVersion option. The resulting shared dependency will be:"]},{"l":"Override a default shared dependency","p":["In the previous code sample, the react shared dependency singleton option will be overrided by the newly provided value. The resulting shared dependency will be:"]},{"l":"Customize module federation configuration","p":["While you could customize the ModuleFederationPlugin configuration by providing your own object literal through the moduleFederationPluginOptions option, we recommend using the defineRemoteModuleFederationPluginOptions(applicationName, options) function as it will take care of merging the custom options with the default plugin options.","applicationName: The host application name.","moduleFederationPluginOptions: An object literal of ModuleFederationPlugin options."]},{"l":"Expose an additional module"}],[{"l":"usePublicDataQueries","p":["Execute the specified Tanstack queries once the modules are ready and, if applicable, Mock Service Worker is also ready.","Use this hook to fetch public global data during the bootstrapping phase of your application. Avoid using it in product feature components."]},{"l":"Reference"},{"l":"Parameters","p":["queries: An array of QueriesOptions."]},{"l":"Returns","p":["An array of query response data. The order returned is the same as the input order."]},{"l":"Throws","p":["If an unmanaged error occur while performing any of the fetch requests, a GlobalDataQueriesError is thrown."]},{"l":"Usage"},{"l":"Define queries","p":["A BootstrappingRoute component is introduced in the following example because this hook must be rendered as a child of rootRoute."]},{"i":"waitforpublicdata--useisbootstrapping","l":"waitForPublicData & useIsBootstrapping","p":["To ensure the AppRouter component wait for the public data to be ready before rendering the requested route, set the waitForPublicData property to true.","Combine this hook with the useIsBootstrapping hook to display a loader until the public data is fetched and the application is ready."]},{"l":"Handle fetch errors","p":["This hook throws GlobalDataQueriesError instances, which are typically unmanaged and should be handled by an error boundary. To assert that an error is an instance of GlobalDataQueriesError, use the isGlobalDataQueriesError function."]}],[{"l":"useProtectedDataQueries","p":["Execute the specified Tanstack queries when the modules are ready, the active route is protected and, when applicable, Mock Service Worker is ready.","Use this hook to fetch protected global data during the bootstrapping phase of your application. Avoid using it in product feature components."]},{"l":"Reference"},{"l":"Parameters","p":["queries: An array of QueriesOptions.","isUnauthorizedError: A function that returns a boolean value indicating whether or not the provided error is a 401 status code."]},{"l":"Returns","p":["An array of query response data. The order returned is the same as the input order."]},{"l":"Throws","p":["If an unmanaged error occur while performing any of the fetch requests, a GlobalDataQueriesError is thrown."]},{"l":"Usage"},{"l":"Define queries","p":["A BootstrappingRoute component is introduced in the following example because this hook must be rendered as a child of rootRoute."]},{"i":"waitforprotecteddata--useisbootstrapping","l":"waitForProtectedData & useIsBootstrapping","p":["To ensure the AppRouter component wait for the protected data to be ready before rendering the requested route, set the waitForProtectedData property to true.","Combine this hook with the useIsBootstrapping hook to display a loader until the protected data is fetched and the application is ready."]},{"l":"Handle fetch errors","p":["This hook throws GlobalDataQueriesError instances, which are typically unmanaged and should be handled by an error boundary. To assert that an error is an instance of GlobalDataQueriesError, use the isGlobalDataQueriesError function."]},{"l":"Handle 401 response","p":["Unauthorized requests are a special case that shouldn't be handled by an error boundary, as this would cause an infinite loop with the application's authentication boundary.","To handle this, when the server returns a 401 status code, the useProtectedDataQueries hook instructs Squide to immediately render the page, triggering the authentication boundary, that will eventually redirect the user to a login page.","Since Squide manages this process behind the scenes, you only need to register an AuthenticationBoundary component and provide an isUnauthorizedError handler to the useProtectedDataQueries hook.","The registerHost function is registered as a local module of the host application."]}],[{"l":"isGlobalDataQueriesError","p":["Indicates whether or not an error is an instance of GlobalDataQueriesError.","GlobalDataQueriesError errors are thrown by either the usePublicDataQueries hook or the useProtectedDataQueries hook and should usually be handled by an error boundary."]},{"l":"Reference"},{"l":"Parameters","p":["error: An Error instance."]},{"l":"Returns","p":["A boolean value indicating whether or not the error is an instance of GlobalDataQueriesError."]},{"l":"Usage"},{"l":"Handle within an error boundary"},{"i":"handle-with-a-trycatch","l":"Handle with a try/catch"},{"l":"GlobalDataQueriesError","p":["message: The error message.","errors: An array of Error instances."]}],[{"l":"setMswAsReady","p":["This function is deprecated, use the bootstrap function instead.","Indicates to the AppRouter that Mock Service Worker is ready and the application can safely be rendered."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["Nothing"]},{"l":"Usage"}],[{"l":"i18nextPlugin","p":["A plugin to faciliate the integration of i18next in a modular application."]},{"l":"Reference"},{"l":"Parameters","p":["supportedLanguages: An array of languages supported by the application.","fallbackLanguage: The language to default to if none of the detected user's languages match any supported language.","queryStringKey: The querystring parameter lookup when detecting the user's language.","options: An optional object literal of options:","detection: An optional object literal accepting any LanguageDetector options."]},{"l":"Usage"},{"l":"Register the plugin"},{"l":"Retrieve the plugin instance","p":["Prefer using getI18nextPlugin when possible"]},{"l":"Register a i18next instance"},{"l":"Retrieve a i18next instance"},{"l":"Detect the user language","p":["Whenever a plugin instance is created, the user's language should always be detected immediatly using the detectUserLanguage function."]},{"l":"Retrieve the current language"},{"l":"Change the current language"},{"l":"Change the language detection order","p":["By default, the detection of the user's language is done first from the specified URL querystring parameter (?language in this example), then from the user's navigator language settings. The detection order can be changed by specifying a new value for the order detection option:"]},{"l":"Add an additional detection source"}],[{"l":"getI18nextPlugin","p":["Return an instance of i18nextPlugin from the list of plugins registered with a Runtime instance."]},{"l":"Reference"},{"l":"Parameters","p":["runtime: A runtime instance."]},{"l":"Returns","p":["An i18nextPlugin instance if the plugin has been registered, otherwise an Error is thrown."]},{"l":"Usage"}],[{"l":"useChangeLanguage","p":["Provide a function to change the current language of every i18next instance registered with the i18nextPlugin instance."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["A function to change the current language of an i18nextPlugin instance: (newLanguage) = void."]},{"l":"Usage"}],[{"l":"useCurrentLanguage","p":["Retrieve the current language of the i18nextPlugin instance."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["The current language of the i18nextPlugin instance."]},{"l":"Usage","p":["Or with a typed language:"]}],[{"l":"useI18nextInstance","p":["Retrieve a registered i18next instance from the i18nextPlugin instance."]},{"l":"Reference"},{"l":"Parameters","p":["key: An instance key."]},{"l":"Returns","p":["An i18next instance."]},{"l":"Usage"},{"l":"Retrieve an instance"},{"l":"Use with the useTranslation hook"},{"l":"Use with the Trans component","p":["Or without the t function:"]}],[{"l":"I18nextNavigationItemLabel","p":["A React component to localize the label of Squide navigation items."]},{"l":"Reference"},{"l":"Properties","p":["i18next: An i18next instance.","namespace: An optional namespace for the localized resource. If no namespace is provided, the default namespace is navigationItems.","resourceKey: A localized resource key."]},{"l":"Usage","p":["Or with a difference resources namespace:"]}],[{"l":"registerHoneycombInstrumentation","p":["Initialize an instance of Honeycomb Web SDK and registers custom instrumentation to monitor the performance of a Squide application.","This function serves as a wrapper around the @workleap/honeycomb library. Before using it, read the documentation for the registerHoneycombInstrumentation function provided by @workleap/honeycomb."]},{"l":"Reference"},{"l":"Parameters","p":["runtime: A FireflyRuntime instance.","serviceName: Honeycomb application service name.","apiServiceUrls: A RegExp or string that matches the URLs of the application's backend services. If unsure, use the temporary regex /.+/g, to match all URLs.","options: An optional object literal of options:","Accepts most of the predefined options of the registerHoneycombInstrumentation function provided by @workleap/honeycomb.","debug: An optional boolean value indicating whether or not to log debug information to the console. true by default when the runtime mode is set to development."]},{"l":"Returns","p":["Nothing"]},{"l":"Usage"},{"l":"Register instrumentation"},{"l":"Use an API key","p":["Prefer using an OpenTelemetry collector over an ingestion API key, as API keys can expose Workleap to potential attacks."]},{"l":"Customize backend URLs","p":["Avoid using /.+/g, in production as it could expose customer data to third parties.","Specify values for the apiServiceUrls argument that matches your application's backend URLs. For example, if your backend services are hosted at https://workleap.com/api:"]}],[{"l":"setGlobalSpanAttributes","p":["Set global attributes to be included in all Honeycomb Web traces.","This function serves as a wrapper around the @workleap/honeycomb library. Before using it, read the documentation for the setGlobalSpanAttributes function provided by @workleap/honeycomb."]},{"l":"Reference"},{"l":"Parameters","p":["attributes: The attributes to include in every trace."]},{"l":"Returns","p":["Nothing"]},{"l":"Usage"}],[{"l":"EnvironmentVariablesPlugin","p":["A plugin to faciliate the usage of environment variables in a modular application."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Usage","p":["Make sure to augment the EnvironmentVariables TypeScript interface with the variables of your module."]},{"l":"Register the plugin"},{"l":"Retrieve the plugin instance","p":["Prefer using getEnvironmentVariablesPlugin when possible"]},{"l":"Register an environment variable","p":["An environment variable with the same key can be registered multiple times (e.g., by multiple modules) as long as the value remains the same. If the value differs, an Error will be thrown."]},{"l":"Register multiple environment variables at once"},{"l":"Retrieve a single environment variable"},{"l":"Retrieve all the environment variables"}],[{"l":"getEnvironmentVariablesPlugin","p":["Return an instance of EnvironmentVariablesPlugin from the list of plugins registered with a Runtime instance."]},{"l":"Reference"},{"l":"Parameters","p":["runtime: A runtime instance."]},{"l":"Returns","p":["An EnvironmentVariablesPlugin instance if the plugin has been registered, otherwise an Error is thrown."]},{"l":"Usage"}],[{"l":"useEnvironmentVariable","p":["Retrieve a specific environment variable registered with the EnvironmentVariablesPlugin instance."]},{"l":"Reference"},{"l":"Parameters","p":["key: The environment variable key."]},{"l":"Returns","p":["The environment variable value if there's a match, otherwise an Error is thrown."]},{"l":"Usage"}],[{"l":"useEnvironmentVariables","p":["Retrieve all the environment variables registered with the EnvironmentVariablesPlugin instance."]},{"l":"Reference"},{"l":"Parameters","p":["None"]},{"l":"Returns","p":["Returns all registered environment variables as an object literal. If no environment variables are registered, an empty object literal is returned."]},{"l":"Usage"}],[{"l":"LocalStorageSessionManager","p":["A local storage session manager (strictly for development purpose)."]},{"l":"Reference"},{"l":"Parameters","p":["options: An optional object literal of options:","key: An optional key identifying the session in localStorage."]},{"l":"Usage"},{"l":"Create a manager instance"},{"l":"Set a session"},{"l":"Get the current session"},{"l":"Clear the current session"}],[{"l":"ReadonlySessionLocalStorage","p":["Read a session object from the local storage (strictly for development purpose)."]},{"l":"Reference"},{"l":"Parameters","p":["options: An optional object literal of options:","key: An optional key identifying the session in localStorage."]},{"l":"Usage"},{"l":"Create an accessor instance"},{"l":"Get the current session"}],[{"l":"Troubleshooting"},{"l":"Set the runtime mode to development","p":["In an effort to optimize the development experience, Squide can be bootstrapped in development or production mode. To troubleshoot a persistent issue, make sure that the runtime mode is development:"]},{"l":"React context values are undefined","p":["If your application utilize remote modules and you are encountering undefined values when providing a React context from the host application and consuming the context in modules, it is likely due to two possible reasons: either you have two instances of React, or you have multiple instances of that React context.","To resolve this issue:","Ensure that the react and react-dom dependencies are shared as singletons between the host application and the remote modules. A React context value cannot be shared between different parts of an application that use different instances of React.","Confirm that the shared React context resides in a library shared as a singleton.","If you are using eager shared dependencies, ensure that ONLY the host application configures these dependencies as eager.","If the issue persists, update your host application and remote module's webpack build configuration with the optimize: false option. Afterward, build the bundles and serve them. Open a web browser, access the DevTools, switch to the Network tab (ensure that JS files are listed), navigate to the application's homepage, and inspect the downloaded bundle files. The problematic React context definition should appear only once; otherwise, you may have multiple instances of the React context.","For additional information on shared dependency versioning, please refer to the add a shared dependency guide."]},{"l":"Console logs","p":["To faciliate the debugging of a Squide application bootstrapping flow, a lot of information is logged into the console when in development. We recommend using these logs if you suspect that something is wrong with the bootstrapping process of your application."]},{"l":"Modules registration"},{"l":"Local modules","p":["[squide] Found 4 local modules to register.","[squide] 1/4 Registering local module.","[squide] 1/4 Local module registration completed."]},{"l":"Remote modules","p":["[squide] Found 1 remote module to register.","[squide] 1/1 Loading module register of remote remote1.","[squide] 1/1 Registering module register of remote remote1.","[squide] 1/1 The registration of the remote remote1 is completed."]},{"l":"Deferred registrations","p":["[squide] 1/1 Registering the deferred registrations for module register of remote remote1.","[squide] 1/1 Registered the deferred registrations for module register of remote remote1.","[squide] 3/3 Updating local module deferred registration.","[squide] 3/3 Updated local module deferred registration."]},{"l":"Ready","p":["[squide] Modules are ready."]},{"l":"Routes registration","p":["[squide] The following route registration is pending until managed-routes-placeholder is registered.","[squide] The following route has been registered as a children of the managed-routes-placeholder route.","[squide] The following route has been registered."]},{"l":"Navigation items registration","p":["[squide] The following static navigation item registration is pending until the officevibe section of the root menu is registered","[squide] The following static navigation item has been registered to the /federated-tabs menu for a total of 2 static items.","[squide] The following deferred navigation item has been registered to the root menu for a total of 4 deferred items."]},{"l":"Mock Service Worker registration","p":["[squide] The following MSW request handlers has been registered: [...]","[squide] MSW is ready."]},{"l":"AppRouter logs","p":["[squide] AppRouter state updated: {...}","[squide] The following action has been dispatched to the AppRouter reducer: {...}"]},{"l":"i18n logs","p":["[squide] Registered a new i18next instance with key shell: {...}","[squide] The language has been changed to fr-CA.","[squide] Detected fr-CA as user language."]},{"l":"env-vars registration","p":["[squide] The following environment variables has been registered: {...}"]},{"l":"Module federation logs","p":["[squide] Module Federation shared scope is available: {...}"]}],[{"l":"Samples"},{"i":"squide-basic-sample","l":"Squide \"basic\" sample","p":["Host application","Remote module","Another remote module","Local module","Shared application shell","Shared library","Host sample"]},{"i":"squide-sample-with-endpoints","l":"Squide sample with \"endpoints\"","p":["Host application","Remote module","Local module","Shared application shell","Layouts library","i18next library","Shared library","Host sample","Isolated remote module sample"]}],[{"l":"About","p":["To ask a question or propose an idea, feel free to start a new discussion on Github. If you found a bug, please open an issue on Github."]},{"l":"Contributing","p":["Have a look at the contributor's documentation."]},{"l":"License","p":["See the LICENSE on Github."]}]] \ No newline at end of file diff --git a/samples/index.html b/samples/index.html index ec2cf2f00..1c4679a16 100644 --- a/samples/index.html +++ b/samples/index.html @@ -4,7 +4,7 @@ - + @@ -32,11 +32,11 @@ - + - + - + diff --git a/sitemap.xml.gz b/sitemap.xml.gz index 8ba219aef139f78d02cd0ded7b8356a96aed782e..84173a382386835357822becf9566ebc43a15a28 100644 GIT binary patch delta 1249 zcmV<71RneO3Hb?sABzY80000000Y#U!E&QG5Qgu03YYIPv7O1JCz!eHt${YE zA|yr%;ZuRZ_A%Q z{uR6B_rt?$W0ga{pp&(GTbAC}FG+GbomNhIte|!)V~fOpWhL#nWH^{SuJ+6RnwO8# zSL%-|PuuRA^?tukx^I_<^ZXy3H+W!A8)u}g|0Nlb9Dine2|)k z$Dd+KF~?e&GY96=K7t4<&_RH%1dDlq_AJpIg;hGE;A))W2vRkcC$Edb+jUWwM@u?D zol|~1T`lyyH3hxQ1O-2n6nInS9@Wrj$k@MBG)^OACnmZD}VoqX|+HD7s$NGjP_jm zjR7pHT4Co1AhO1JQ_r7`);7$LEDuD`hJ21e#@HJj^HUd45Ed)?lM~z zGuX05*5{6lGJl*7mgmVvim4H-hE^7xKEm9?w5i8pPL1(lr=AV*CH(qQB4_+XR>{yZ z<`7%f8IP}naM+v`E&cpli22g9Xt3kpBjP-KV=*5e=ZU|2J#8M^ZFJgNHHBmuc1D98 zQj5ND#@J!U=C#yyWS&Gk8)VXhbl2XxW}20_1GNpcUw`t87#UJ5`myCzXp4xZ$2yz+ z`2|>XMzupOjYX&p@Nh>OX$6N4+>HHVBvKFBc^XuUUk%!G=hvMJh6&AZNHY0KtRd|v zLW4Le@L9 zHML=anw;b)S<=rU}zZ)F*0z0o`0V?Qo;JdOub}Qf-X?eM*{^*P4y1Y z!=?6xEdJQMX~~kxNEvk*-UT=B4w-(lO5}^ho9G+p?Ls(W(v$kLBA=DglP7zus8gBhdq2qzNz z5jx%puv<9dys=?D4vk4ERQt8)JPB^3igM2$GDM@*dEg%3N<{dsA)`1v{00C3|NjF3 LA@g&JF**PMr)^|O delta 1249 zcmV<71RneO3Hb?sABzY80000000Y#U&32nS5Qg`;3Lo!f{FAnEPU7x*1?}eB4KN0s z2#HDp$9MmY0Nb?5s%PW_8w)VR5Ae>b(MWmu{$8m?i`Ge_UzeNJdbvQInOy4Pb@}V( z5An48et39kta9iVbh37@%hLP$IY~~Z)5=MY71VBJY>~KstfU>63%9KDb_TNTomO}dgMIVs_OH!{b> z;t?%jWAc)OtA^{r`O4&n?RxttHXE^d`nldbZ@)dSAOEBChHv|GYb%YF{(M-ko*rM4 z>uw-Q2Bd#~LMy_joTsG&fAK3m|#^wu<~LRT8&xw-&OK1fZ& z<4-ZAm}9NXnFI52A3=l_=paB>g2g;QdzR>q!YZ9na5YYG1gRR!lh;Mz?YgMTqa_`n z&M7~ht`>UUnu1iXv1!pEZhyvWWLAPLqhm=ROu|SX1 z<5OfEiKBvI+N7vkX^pNZ3luF_38BN9EO9?rk((!t?~@qFup zHDqs;?(&!dE2D#;S{^Xg8pg<8v5?N&z8mOw&~{~kzMo)$-?1jPBX~*)Tqd{(jm-@ykv;;V_zfLgkn{VA#6CX9TEKpLlzb#NxAcZLNYiLZvh*X3Ij?sRMnWI&V8-Y?!imIw zggQ3@>=uqVZ){kPLt|13)qX8HPl6k%qTI8G4AE$H9=ON15)r;@$S4jE{{sL3|NjF3 L42l1dF**PM`vh-e diff --git a/troubleshooting/index.html b/troubleshooting/index.html index c1b38f856..4590b48d6 100644 --- a/troubleshooting/index.html +++ b/troubleshooting/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/upgrading/index.html b/upgrading/index.html index 863efd4e6..15b5f0055 100644 --- a/upgrading/index.html +++ b/upgrading/index.html @@ -4,7 +4,7 @@ - + @@ -32,11 +32,11 @@ - + - + - + diff --git a/upgrading/migrate-to-firefly-v9.0/index.html b/upgrading/migrate-to-firefly-v9.0/index.html index 8549bc52b..e325a33af 100644 --- a/upgrading/migrate-to-firefly-v9.0/index.html +++ b/upgrading/migrate-to-firefly-v9.0/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + + diff --git a/upgrading/migrate-to-firefly-v9.3/index.html b/upgrading/migrate-to-firefly-v9.3/index.html index b087d6f36..d1dabaa1b 100644 --- a/upgrading/migrate-to-firefly-v9.3/index.html +++ b/upgrading/migrate-to-firefly-v9.3/index.html @@ -4,7 +4,7 @@ - + @@ -32,12 +32,12 @@ - + - + - - + +