From 64afd91ad2d7c2120850fdcd70476ec4ed8937e4 Mon Sep 17 00:00:00 2001 From: sdeshpande3 <46719950+sdeshpande3@users.noreply.github.com> Date: Tue, 5 Apr 2022 11:34:44 -0700 Subject: [PATCH] Replace ICodeLoader with ICodeDetailsLoader (#9697) The usage of ICodeLoader is replaced with ICodeDetailsLoader in the entire repo. The old interface is not yet removed. --- BREAKING.md | 26 +++++++++++++ api-report/container-loader.api.md | 5 +-- api-report/test-utils.api.md | 7 ++-- api-report/web-code-loader.api.md | 10 ++--- examples/hosts/iframe-host/src/inframehost.ts | 14 +++++-- examples/hosts/iframe-host/src/inner.ts | 12 ++++-- .../get-container/src/getContainer.ts | 19 +++++++-- .../src/getSessionStorageContainer.ts | 11 +++++- .../framework/azure-client/src/AzureClient.ts | 16 ++++++-- .../src/TinyliciousClient.ts | 16 ++++++-- .../container-loader/src/containerContext.ts | 11 ++++-- .../loader/container-loader/src/loader.ts | 5 +-- .../src/test/containerContext.spec.ts | 39 ++++++++++++++----- .../loader/web-code-loader/src/webLoader.ts | 14 ++++--- .../test/test-utils/src/localCodeLoader.ts | 16 +++++--- packages/test/test-utils/src/localLoader.ts | 4 +- .../replay-tool/src/replayLoaderObject.ts | 12 ++++-- .../tools/webpack-fluid-loader/src/loader.ts | 19 ++++++--- 18 files changed, 188 insertions(+), 68 deletions(-) diff --git a/BREAKING.md b/BREAKING.md index a9dd0f2d11c2..8d1b41ed959f 100644 --- a/BREAKING.md +++ b/BREAKING.md @@ -17,12 +17,17 @@ There are a few steps you can take to write a good change note and avoid needing # 0.59 ## 0.59 Upcoming changes +- [Remove ICodeLoader interface](#Remove-ICodeLoader-interface) + +### Remove ICodeLoader interface +ICodeLoader interface was deprecated a while ago and will be removed in the next release. Please refer to [replace ICodeLoader with ICodeDetailsLoader interface](#Replace-ICodeLoader-with-ICodeDetailsLoader-interface) for more details. ## 0.59 Breaking changes - [Removing Commit from TreeEntry and commits from SnapShotTree](#Removing-Commit-from-TreeEntry-and-commits-from-SnapShotTree) - [raiseContainerWarning removed from IContainerContext](#raiseContainerWarning-removed-from-IContainerContext) - [Remove `@fluidframework/core-interface#fluidPackage.ts`](#Remove-fluidframeworkcore-interfacefluidPackagets) - [getAbsoluteUrl() argument type changed](#getAbsoluteUrl-argument-type-changed) +- [Replace ICodeLoader with ICodeDetailsLoader interface](#Replace-ICodeLoader-with-ICodeDetailsLoader-interface) ### Removing Commit from TreeEntry and commits from SnapShotTree Cleaning up properties that are not being used in the codebase: `TreeEntry.Commit` and `ISnapshotTree.commits`. @@ -67,6 +72,27 @@ The `packageInfoSource` argument in `getAbsoluteUrl()` on `@fluidframework/odsp- + ): Promise; ``` +### Replace ICodeLoader with ICodeDetailsLoader interface +The interface `ICodeLoader` was deprecated a while ago in previous releases. The alternative for `ICodeLoader` interface is the `ICodeDetailsLoader` interface which can be imported from `@fluidframework/container-definitions`. `ICodeLoader` interface will be removed in the next release. + +In particular, note the `ILoaderService` and `ILoaderProps` interfaces used with the `Loader` class now only support `ICodeDetailsLoader`. If you were using an `ICodeLoader` with these previously, you'll need to update to an `ICodeDetailsLoader`. + +```ts +export interface ICodeDetailsLoader + extends Partial { + /** + * Load the code module (package) that is capable to interact with the document. + * + * @param source - Code proposal that articulates the current schema the document is written in. + * @returns - Code module entry point along with the code details associated with it. + */ + load(source: IFluidCodeDetails): Promise; +} +``` +All codeloaders are now expected to return the object including both the runtime factory and code details of the package that was actually loaded. These code details may be used later then to check whether the currently loaded package `.satisfies()` a constraint. + +You can start by returning default code details that were passed into the code loader which used to be our implementation on your behalf if code details were not passed in. Later on, this gives an opportunity to implement more sophisticated code loading where the code loader now can inform about the actual loaded module via the returned details. + # 0.58 ## 0.58 Upcoming changes diff --git a/api-report/container-loader.api.md b/api-report/container-loader.api.md index 24d88e01affd..1b717953a6cb 100644 --- a/api-report/container-loader.api.md +++ b/api-report/container-loader.api.md @@ -10,7 +10,6 @@ import { FluidObject } from '@fluidframework/core-interfaces'; import { IAudience } from '@fluidframework/container-definitions'; import { IClientConfiguration } from '@fluidframework/protocol-definitions'; import { IClientDetails } from '@fluidframework/protocol-definitions'; -import { ICodeLoader } from '@fluidframework/container-definitions'; import { IConfigProviderBase } from '@fluidframework/telemetry-utils'; import { IContainer } from '@fluidframework/container-definitions'; import { IContainerEvents } from '@fluidframework/container-definitions'; @@ -155,7 +154,7 @@ export interface ILoaderOptions extends ILoaderOptions_2 { // @public export interface ILoaderProps { - readonly codeLoader: ICodeDetailsLoader | ICodeLoader; + readonly codeLoader: ICodeDetailsLoader; readonly configProvider?: IConfigProviderBase; readonly detachedBlobStorage?: IDetachedBlobStorage; readonly documentServiceFactory: IDocumentServiceFactory; @@ -168,7 +167,7 @@ export interface ILoaderProps { // @public export interface ILoaderServices { - readonly codeLoader: ICodeDetailsLoader | ICodeLoader; + readonly codeLoader: ICodeDetailsLoader; readonly detachedBlobStorage?: IDetachedBlobStorage; readonly documentServiceFactory: IDocumentServiceFactory; readonly options: ILoaderOptions; diff --git a/api-report/test-utils.api.md b/api-report/test-utils.api.md index 2ad54529dc14..cb14fc61b21e 100644 --- a/api-report/test-utils.api.md +++ b/api-report/test-utils.api.md @@ -7,7 +7,7 @@ import { ContainerRuntime } from '@fluidframework/container-runtime'; import { FluidDataStoreRuntime } from '@fluidframework/datastore'; import { IChannelFactory } from '@fluidframework/datastore-definitions'; -import { ICodeLoader } from '@fluidframework/container-definitions'; +import { ICodeDetailsLoader } from '@fluidframework/container-definitions'; import { IContainer } from '@fluidframework/container-definitions'; import { IContainerContext } from '@fluidframework/container-definitions'; import { IContainerRuntime } from '@fluidframework/container-runtime-definitions'; @@ -21,6 +21,7 @@ import { IFluidDataStoreRuntime } from '@fluidframework/datastore-definitions'; import { IFluidHandle } from '@fluidframework/core-interfaces'; import { IFluidLoadable } from '@fluidframework/core-interfaces'; import { IFluidModule } from '@fluidframework/container-definitions'; +import { IFluidModuleWithDetails } from '@fluidframework/container-definitions'; import { IHostLoader } from '@fluidframework/container-definitions'; import { ILoaderOptions } from '@fluidframework/container-definitions'; import { ILoaderProps } from '@fluidframework/container-loader'; @@ -194,9 +195,9 @@ export class LoaderContainerTracker implements IOpProcessingController { } // @public -export class LocalCodeLoader implements ICodeLoader { +export class LocalCodeLoader implements ICodeDetailsLoader { constructor(packageEntries: Iterable<[IFluidCodeDetails, fluidEntryPoint]>, runtimeOptions?: IContainerRuntimeOptions); - load(source: IFluidCodeDetails): Promise; + load(source: IFluidCodeDetails): Promise; } // @public diff --git a/api-report/web-code-loader.api.md b/api-report/web-code-loader.api.md index d29aea162a62..8f763d398031 100644 --- a/api-report/web-code-loader.api.md +++ b/api-report/web-code-loader.api.md @@ -5,10 +5,10 @@ ```ts import { ICodeAllowList } from '@fluidframework/container-definitions'; -import { ICodeLoader } from '@fluidframework/container-definitions'; +import { ICodeDetailsLoader } from '@fluidframework/container-definitions'; import { IFluidCodeDetails } from '@fluidframework/container-definitions'; import { IFluidCodeResolver } from '@fluidframework/container-definitions'; -import { IFluidModule } from '@fluidframework/container-definitions'; +import { IFluidModuleWithDetails } from '@fluidframework/container-definitions'; import { IFluidPackage } from '@fluidframework/container-definitions'; import { IFluidPackageEnvironment } from '@fluidframework/container-definitions'; import { IResolvedFluidCodeDetails } from '@fluidframework/container-definitions'; @@ -47,14 +47,14 @@ export class SemVerCdnCodeResolver implements IFluidCodeResolver { } // @public (undocumented) -export class WebCodeLoader implements ICodeLoader { +export class WebCodeLoader implements ICodeDetailsLoader { constructor(codeResolver: IFluidCodeResolver, allowList?: ICodeAllowList | undefined); // (undocumented) - load(source: IFluidCodeDetails): Promise; + load(source: IFluidCodeDetails): Promise; // (undocumented) preCache(source: IFluidCodeDetails): Promise; // (undocumented) - seedModule(source: IFluidCodeDetails, maybeFluidModule?: Promise | IFluidModule): Promise; + seedModule(source: IFluidCodeDetails, maybeFluidModule?: Promise | IFluidModuleWithDetails): Promise; } diff --git a/examples/hosts/iframe-host/src/inframehost.ts b/examples/hosts/iframe-host/src/inframehost.ts index 4cac540f3b7b..65e3035b9f1a 100644 --- a/examples/hosts/iframe-host/src/inframehost.ts +++ b/examples/hosts/iframe-host/src/inframehost.ts @@ -6,12 +6,13 @@ import * as Comlink from "comlink"; import { AttachState, - ICodeLoader, IContainerContext, IRuntime, IProxyLoaderFactory, ILoaderOptions, IContainer, + ICodeDetailsLoader, + IFluidCodeDetails, } from "@fluidframework/container-definitions"; import { Loader } from "@fluidframework/container-loader"; import { IRequest, IResponse, FluidObject } from "@fluidframework/core-interfaces"; @@ -104,9 +105,14 @@ class ProxyChaincode extends RuntimeFactoryHelper { } } -class ProxyCodeLoader implements ICodeLoader { - async load() { - return Promise.resolve({ fluidExport: new ProxyChaincode() }); +class ProxyCodeLoader implements ICodeDetailsLoader { + async load(source: IFluidCodeDetails) { + return { + module: { + fluidExport: new ProxyChaincode(), + }, + details: source, + }; } } diff --git a/examples/hosts/iframe-host/src/inner.ts b/examples/hosts/iframe-host/src/inner.ts index 83b47e850519..ac87d7b76aac 100644 --- a/examples/hosts/iframe-host/src/inner.ts +++ b/examples/hosts/iframe-host/src/inner.ts @@ -5,7 +5,7 @@ import * as Comlink from "comlink"; import { fluidExport as TodoContainer } from "@fluid-example/todo"; -import { IContainer } from "@fluidframework/container-definitions"; +import { IContainer, IFluidModuleWithDetails } from "@fluidframework/container-definitions"; import { Loader } from "@fluidframework/container-loader"; import { IFluidResolvedUrl } from "@fluidframework/driver-definitions"; import { FluidObject, IRequest } from "@fluidframework/core-interfaces"; @@ -51,8 +51,14 @@ async function loadContainer( const documentServiceFactory = await InnerDocumentServiceFactory.create(innerPort); const urlResolver = await InnerUrlResolver.create(innerPort); - const module = { fluidExport: TodoContainer }; - const codeLoader = { load: async () => module }; + const load = async (): Promise => { + return { + module: { fluidExport: TodoContainer }, + details: { package: "no-dynamic-package", config: {} }, + }; + }; + + const codeLoader = { load }; const loader = new Loader({ urlResolver, diff --git a/experimental/framework/get-container/src/getContainer.ts b/experimental/framework/get-container/src/getContainer.ts index 6d5ffe7ad12d..2be32e551446 100644 --- a/experimental/framework/get-container/src/getContainer.ts +++ b/experimental/framework/get-container/src/getContainer.ts @@ -5,6 +5,7 @@ import { IContainer, + IFluidModuleWithDetails, IRuntimeFactory, } from "@fluidframework/container-definitions"; import { Loader } from "@fluidframework/container-loader"; @@ -24,9 +25,14 @@ export interface IGetContainerParams { export async function createContainer( params: IGetContainerParams, ): Promise { - const module = { fluidExport: params.containerRuntimeFactory }; - const codeLoader = { load: async () => module }; + const load = async (): Promise => { + return { + module: { fluidExport: params.containerRuntimeFactory }, + details: { package: "no-dynamic-package", config: {} }, + }; + }; + const codeLoader = { load }; const loader = new Loader({ urlResolver: params.urlResolver, documentServiceFactory: params.documentServiceFactory, @@ -45,9 +51,14 @@ export async function createContainer( export async function getContainer( params: IGetContainerParams, ): Promise { - const module = { fluidExport: params.containerRuntimeFactory }; - const codeLoader = { load: async () => module }; + const load = async (): Promise => { + return { + module: { fluidExport: params.containerRuntimeFactory }, + details: { package: "no-dynamic-package", config: {} }, + }; + }; + const codeLoader = { load }; const loader = new Loader({ urlResolver: params.urlResolver, documentServiceFactory: params.documentServiceFactory, diff --git a/experimental/framework/get-container/src/getSessionStorageContainer.ts b/experimental/framework/get-container/src/getSessionStorageContainer.ts index 6002fbe50a10..fa31ed8785c4 100644 --- a/experimental/framework/get-container/src/getSessionStorageContainer.ts +++ b/experimental/framework/get-container/src/getSessionStorageContainer.ts @@ -5,6 +5,7 @@ import { IContainer, + IFluidModuleWithDetails, IRuntimeFactory, } from "@fluidframework/container-definitions"; import { Loader } from "@fluidframework/container-loader"; @@ -37,8 +38,14 @@ export async function getSessionStorageContainer( // To bypass proposal-based loading, we need a codeLoader that will return our already-in-memory container factory. // The expected format of that response is an IFluidModule with a fluidExport. - const module = { fluidExport: containerRuntimeFactory }; - const codeLoader = { load: async () => module }; + const load = async (): Promise => { + return { + module: { fluidExport: containerRuntimeFactory }, + details: { package: "no-dynamic-package", config: {} }, + }; + }; + + const codeLoader = { load }; const loader = new Loader({ urlResolver, diff --git a/packages/framework/azure-client/src/AzureClient.ts b/packages/framework/azure-client/src/AzureClient.ts index a93ff8284b5b..05e913d8655e 100644 --- a/packages/framework/azure-client/src/AzureClient.ts +++ b/packages/framework/azure-client/src/AzureClient.ts @@ -7,7 +7,11 @@ import { IDocumentServiceFactory, IUrlResolver, } from "@fluidframework/driver-definitions"; -import { AttachState, IContainer } from "@fluidframework/container-definitions"; +import { + AttachState, + IContainer, + IFluidModuleWithDetails, +} from "@fluidframework/container-definitions"; import { RouterliciousDocumentServiceFactory } from "@fluidframework/routerlicious-driver"; import { requestFluidObject } from "@fluidframework/runtime-utils"; import { ensureFluidResolvedUrl } from "@fluidframework/driver-utils"; @@ -138,8 +142,14 @@ export class AzureClient { const runtimeFactory = new DOProviderContainerRuntimeFactory( containerSchema, ); - const module = { fluidExport: runtimeFactory }; - const codeLoader = { load: async () => module }; + const load = async (): Promise => { + return { + module: { fluidExport: runtimeFactory }, + details: { package: "no-dynamic-package", config: {} }, + }; + }; + + const codeLoader = { load }; return new Loader({ urlResolver: this.urlResolver, documentServiceFactory: this.documentServiceFactory, diff --git a/packages/framework/tinylicious-client/src/TinyliciousClient.ts b/packages/framework/tinylicious-client/src/TinyliciousClient.ts index 77b333d4d20f..62709857b284 100644 --- a/packages/framework/tinylicious-client/src/TinyliciousClient.ts +++ b/packages/framework/tinylicious-client/src/TinyliciousClient.ts @@ -7,7 +7,11 @@ import { IDocumentServiceFactory, IUrlResolver, } from "@fluidframework/driver-definitions"; -import { AttachState, IContainer } from "@fluidframework/container-definitions"; +import { + AttachState, + IContainer, + IFluidModuleWithDetails, +} from "@fluidframework/container-definitions"; import { RouterliciousDocumentServiceFactory } from "@fluidframework/routerlicious-driver"; import { createTinyliciousCreateNewRequest, @@ -119,8 +123,14 @@ export class TinyliciousClient { const containerRuntimeFactory = new DOProviderContainerRuntimeFactory( containerSchema, ); - const module = { fluidExport: containerRuntimeFactory }; - const codeLoader = { load: async () => module }; + const load = async (): Promise => { + return { + module: { fluidExport: containerRuntimeFactory }, + details: { package: "no-dynamic-package", config: {} }, + }; + }; + + const codeLoader = { load }; const loader = new Loader({ urlResolver: this.urlResolver, documentServiceFactory: this.documentServiceFactory, diff --git a/packages/loader/container-loader/src/containerContext.ts b/packages/loader/container-loader/src/containerContext.ts index 7e38089ea425..c23aa8af66b6 100644 --- a/packages/loader/container-loader/src/containerContext.ts +++ b/packages/loader/container-loader/src/containerContext.ts @@ -15,11 +15,12 @@ import { AttachState, ILoaderOptions, IRuntimeFactory, - ICodeLoader, IProvideRuntimeFactory, IFluidCodeDetails, IFluidCodeDetailsComparer, IProvideFluidCodeDetailsComparer, + ICodeDetailsLoader, + IFluidModuleWithDetails, } from "@fluidframework/container-definitions"; import { IFluidObject, @@ -44,7 +45,6 @@ import { } from "@fluidframework/protocol-definitions"; import { PerformanceEvent } from "@fluidframework/telemetry-utils"; import { Container } from "./container"; -import { ICodeDetailsLoader, IFluidModuleWithDetails } from "./loader"; const PackageNotFactoryError = "Code package does not implement IRuntimeFactory"; @@ -52,7 +52,7 @@ export class ContainerContext implements IContainerContext { public static async createOrLoad( container: Container, scope: FluidObject, - codeLoader: ICodeDetailsLoader | ICodeLoader, + codeLoader: ICodeDetailsLoader, codeDetails: IFluidCodeDetails, baseSnapshot: ISnapshotTree | undefined, deltaManager: IDeltaManager, @@ -157,7 +157,7 @@ export class ContainerContext implements IContainerContext { constructor( private readonly container: Container, public readonly scope: IFluidObject & FluidObject, - private readonly codeLoader: ICodeDetailsLoader | ICodeLoader, + private readonly codeLoader: ICodeDetailsLoader, private readonly _codeDetails: IFluidCodeDetails, private readonly _baseSnapshot: ISnapshotTree | undefined, public readonly deltaManager: IDeltaManager, @@ -329,6 +329,9 @@ export class ContainerContext implements IContainerContext { details: details ?? codeDetails, }; } else { + // If "module" is not in the result, we are using a legacy ICodeLoader. Fix the result up with details. + // Once usage drops to 0 we can remove this compat path. + this.taggedLogger.sendTelemetryEvent({ eventName: "LegacyCodeLoader" }); return { module: loadCodeResult, details: codeDetails }; } } diff --git a/packages/loader/container-loader/src/loader.ts b/packages/loader/container-loader/src/loader.ts index 2b4f71c077cb..358d45cfa3c8 100644 --- a/packages/loader/container-loader/src/loader.ts +++ b/packages/loader/container-loader/src/loader.ts @@ -13,7 +13,6 @@ import { IResponse, } from "@fluidframework/core-interfaces"; import { - ICodeLoader, IContainer, IFluidModule, IHostLoader, @@ -187,7 +186,7 @@ export interface ILoaderProps { * The code loader handles loading the necessary code * for running a container once it is loaded. */ - readonly codeLoader: ICodeDetailsLoader | ICodeLoader; + readonly codeLoader: ICodeDetailsLoader; /** * A property bag of options used by various layers @@ -243,7 +242,7 @@ export interface ILoaderServices { * The code loader handles loading the necessary code * for running a container once it is loaded. */ - readonly codeLoader: ICodeDetailsLoader | ICodeLoader; + readonly codeLoader: ICodeDetailsLoader; /** * A property bag of options used by various layers diff --git a/packages/loader/container-loader/src/test/containerContext.spec.ts b/packages/loader/container-loader/src/test/containerContext.spec.ts index 42b24919a56f..0ebc9f23c7b5 100644 --- a/packages/loader/container-loader/src/test/containerContext.spec.ts +++ b/packages/loader/container-loader/src/test/containerContext.spec.ts @@ -9,6 +9,8 @@ import { ILoader, IRuntime, IRuntimeFactory, + ICodeDetailsLoader, + IFluidModuleWithDetails, IFluidCodeDetails, } from "@fluidframework/container-definitions"; import { @@ -23,7 +25,6 @@ import { } from "@fluidframework/telemetry-utils"; import { Container } from "../container"; import { ContainerContext } from "../containerContext"; -import { ICodeDetailsLoader } from "../loader"; describe("ContainerContext Tests", () => { let sandbox: Sinon.SinonSandbox; @@ -57,13 +58,13 @@ describe("ContainerContext Tests", () => { })(defaultErrorHandler); const createTestContext = async ( - codeLoader: unknown, /* ICodeDetailsLoader */ + codeLoader: ICodeDetailsLoader, existing: boolean = true, ) => { return ContainerContext.createOrLoad( (mockContainer as unknown) as Container, (sandbox.stub() as unknown) as FluidObject, - codeLoader as ICodeDetailsLoader, + codeLoader, quorumCodeDetails, undefined, sandbox.stub() as any, @@ -89,14 +90,20 @@ describe("ContainerContext Tests", () => { it("Should load code using legacy loader", async () => { // Arrange const proposedCodeDetails = codeDetailsForVersion("2.0.0"); + const load = async (): Promise => { + return { + module: { fluidExport: { } }, + details: proposedCodeDetails, + }; + }; - const simpleCodeLoader = { load: async () => {} }; + const simpleCodeLoader = { load }; const mockCodeLoader = sandbox.mock(simpleCodeLoader); // emulate legacy ICodeLoader mockCodeLoader .expects("load") .once() - .resolves({ fluidExport: mockRuntimeFactory }); + .resolves({ module: { fluidExport: mockRuntimeFactory }, details: proposedCodeDetails }); // Act const testContext = await createTestContext(simpleCodeLoader); @@ -117,16 +124,23 @@ describe("ContainerContext Tests", () => { it("Should load code without details", async () => { // Arrange const proposedCodeDetails = codeDetailsForVersion("2.0.0"); + const load = async (): Promise => { + return { + module: { fluidExport: { } }, + details: { package: "no-dynamic-package", config: {} }, + }; + }; const codeDetailsLoader = { - load: async () => {}, + load, get IFluidCodeDetailsComparer() { return this; }, satisfies: async ( candidate: IFluidCodeDetails, constraint: IFluidCodeDetails, - ) => {}, + ) => { return true; }, + compare: async () => { return 0; }, }; const mockCodeLoader = sandbox.mock(codeDetailsLoader); mockCodeLoader @@ -157,16 +171,23 @@ describe("ContainerContext Tests", () => { // Arrange const proposedCodeDetails = codeDetailsForVersion("2.0.0"); const moduleCodeDetails = codeDetailsForVersion("3.0.0"); + const load = async (): Promise => { + return { + module: { fluidExport: { } }, + details: proposedCodeDetails, + }; + }; const codeDetailsLoader = { - load: async () => {}, + load, get IFluidCodeDetailsComparer() { return this; }, satisfies: async ( candidate: IFluidCodeDetails, constraint: IFluidCodeDetails, - ) => {}, + ) => { return true; }, + compare: async () => { return 0; }, }; const mockCodeLoader = sandbox.mock(codeDetailsLoader); mockCodeLoader diff --git a/packages/loader/web-code-loader/src/webLoader.ts b/packages/loader/web-code-loader/src/webLoader.ts index fc1717f10b5c..7a909f64c7b7 100644 --- a/packages/loader/web-code-loader/src/webLoader.ts +++ b/packages/loader/web-code-loader/src/webLoader.ts @@ -4,18 +4,19 @@ */ import { - ICodeLoader, ICodeAllowList, IFluidModule, IFluidCodeResolver, IResolvedFluidCodeDetails, isFluidBrowserPackage, IFluidCodeDetails, + ICodeDetailsLoader, + IFluidModuleWithDetails, } from "@fluidframework/container-definitions"; import { ScriptManager } from "./scriptManager"; -export class WebCodeLoader implements ICodeLoader { - private readonly loadedModules = new Map | IFluidModule>(); +export class WebCodeLoader implements ICodeDetailsLoader { + private readonly loadedModules = new Map | IFluidModuleWithDetails>(); private readonly scriptManager = new ScriptManager(); constructor( @@ -24,7 +25,7 @@ export class WebCodeLoader implements ICodeLoader { public async seedModule( source: IFluidCodeDetails, - maybeFluidModule?: Promise | IFluidModule, + maybeFluidModule?: Promise | IFluidModuleWithDetails, ): Promise { const resolved = await this.codeResolver.resolveCodeDetails(source); if (resolved.resolvedPackageCacheId !== undefined @@ -50,7 +51,7 @@ export class WebCodeLoader implements ICodeLoader { */ public async load( source: IFluidCodeDetails, - ): Promise { + ): Promise { const resolved = await this.codeResolver.resolveCodeDetails(source); if (resolved.resolvedPackageCacheId !== undefined) { const maybePkg = this.loadedModules.get(resolved.resolvedPackageCacheId); @@ -60,6 +61,7 @@ export class WebCodeLoader implements ICodeLoader { } const fluidModuleP = this.loadModuleFromResolvedCodeDetails(resolved); + if (resolved.resolvedPackageCacheId !== undefined) { this.loadedModules.set(resolved.resolvedPackageCacheId, fluidModuleP); } @@ -91,6 +93,6 @@ export class WebCodeLoader implements ICodeLoader { if (fluidModule?.fluidExport === undefined) { throw new Error("Entry point of loaded code package not a Fluid module"); } - return fluidModule; + return { module: fluidModule, details: resolved }; } } diff --git a/packages/test/test-utils/src/localCodeLoader.ts b/packages/test/test-utils/src/localCodeLoader.ts index a6e68e9badce..bb2b79fe0036 100644 --- a/packages/test/test-utils/src/localCodeLoader.ts +++ b/packages/test/test-utils/src/localCodeLoader.ts @@ -6,11 +6,12 @@ import assert from "assert"; import { ContainerRuntimeFactoryWithDefaultDataStore } from "@fluidframework/aqueduct"; import { - ICodeLoader, IProvideRuntimeFactory, IFluidModule, IProvideFluidCodeDetailsComparer, IFluidCodeDetails, + ICodeDetailsLoader, + IFluidModuleWithDetails, } from "@fluidframework/container-definitions"; import { IRequest } from "@fluidframework/core-interfaces"; import { IContainerRuntimeBase, IProvideFluidDataStoreFactory, @@ -31,8 +32,8 @@ export type fluidEntryPoint = SupportedExportInterfaces | IFluidModule; * A simple code loader that caches a mapping of package name to a Fluid entry point. * On load, it retrieves the entry point matching the package name in the given code details. */ -export class LocalCodeLoader implements ICodeLoader { - private readonly fluidPackageCache = new Map(); +export class LocalCodeLoader implements ICodeDetailsLoader { + private readonly fluidPackageCache = new Map(); constructor( packageEntries: Iterable<[IFluidCodeDetails, fluidEntryPoint]>, @@ -77,7 +78,12 @@ export class LocalCodeLoader implements ICodeLoader { } } - this.fluidPackageCache.set(pkgId, fluidModule); + const runtimeFactory = { + module: fluidModule, + details: source, + }; + + this.fluidPackageCache.set(pkgId, runtimeFactory); } } @@ -88,7 +94,7 @@ export class LocalCodeLoader implements ICodeLoader { */ public async load( source: IFluidCodeDetails, - ): Promise { + ): Promise { // Get the entry point for from the fluidPackageCache for the given code details. // For code details containing a package name, use the package name as the id. // For code details containing a Fluid package, create a unique id from the package name and version. diff --git a/packages/test/test-utils/src/localLoader.ts b/packages/test/test-utils/src/localLoader.ts index 9cdc16505ca2..a327150b1ad0 100644 --- a/packages/test/test-utils/src/localLoader.ts +++ b/packages/test/test-utils/src/localLoader.ts @@ -4,7 +4,7 @@ */ import { - ICodeLoader, + ICodeDetailsLoader, IContainer, IHostLoader, ILoaderOptions, @@ -30,7 +30,7 @@ export function createLoader( logger?: ITelemetryBaseLogger, options?: ILoaderOptions, ): IHostLoader { - const codeLoader: ICodeLoader = new LocalCodeLoader(packageEntries); + const codeLoader: ICodeDetailsLoader = new LocalCodeLoader(packageEntries); return new Loader({ urlResolver, diff --git a/packages/tools/replay-tool/src/replayLoaderObject.ts b/packages/tools/replay-tool/src/replayLoaderObject.ts index b836ba3763c2..d115884c6c8c 100644 --- a/packages/tools/replay-tool/src/replayLoaderObject.ts +++ b/packages/tools/replay-tool/src/replayLoaderObject.ts @@ -4,11 +4,12 @@ */ import { - ICodeLoader, + ICodeDetailsLoader, IFluidModule, IProvideRuntimeFactory, IFluidCodeDetails, IFluidCodeDetailsComparer, + IFluidModuleWithDetails, } from "@fluidframework/container-definitions"; import { IRequest } from "@fluidframework/core-interfaces"; import { IResolvedUrl, IUrlResolver } from "@fluidframework/driver-definitions"; @@ -36,7 +37,7 @@ import { IResolvedUrl, IUrlResolver } from "@fluidframework/driver-definitions"; } /** Simple code loader that loads the runtime factory provided during creation. */ -export class ReplayCodeLoader implements ICodeLoader, IFluidCodeDetailsComparer { +export class ReplayCodeLoader implements ICodeDetailsLoader, IFluidCodeDetailsComparer { private readonly fluidModule: IFluidModule; constructor(runtimeFactory: IProvideRuntimeFactory) { @@ -47,8 +48,11 @@ export class ReplayCodeLoader implements ICodeLoader, IFluidCodeDetailsComparer return this; } - public async load(source: IFluidCodeDetails): Promise { - return Promise.resolve(this.fluidModule); + public async load(source: IFluidCodeDetails): Promise { + return { + module: this.fluidModule, + details: source, + }; } public async satisfies(candidate: IFluidCodeDetails, constraint: IFluidCodeDetails): Promise { diff --git a/packages/tools/webpack-fluid-loader/src/loader.ts b/packages/tools/webpack-fluid-loader/src/loader.ts index a6a1c7a381f9..9746df7d2b78 100644 --- a/packages/tools/webpack-fluid-loader/src/loader.ts +++ b/packages/tools/webpack-fluid-loader/src/loader.ts @@ -9,7 +9,6 @@ import { ContainerRuntimeFactoryWithDefaultDataStore } from "@fluidframework/aqu import { assert, BaseTelemetryNullLogger, Deferred } from "@fluidframework/common-utils"; import { AttachState, - IFluidModule, IFluidCodeResolver, IResolvedFluidCodeDetails, isFluidBrowserPackage, @@ -17,6 +16,8 @@ import { IContainer, IFluidPackage, IFluidCodeDetails, + IFluidModuleWithDetails, + IFluidModule, } from "@fluidframework/container-definitions"; import { Loader } from "@fluidframework/container-loader"; import { prefetchLatestSnapshot } from "@fluidframework/odsp-driver"; @@ -92,7 +93,8 @@ export type RouteOptions = | ITinyliciousRouteOptions | IOdspRouteOptions; -function wrapWithRuntimeFactoryIfNeeded(packageJson: IFluidPackage, fluidModule: IFluidModule): IFluidModule { +function wrapWithRuntimeFactoryIfNeeded(packageJson: IFluidPackage, fluidModule: IFluidModule): + IFluidModuleWithDetails { const fluidModuleExport: FluidObject = fluidModule.fluidExport; if (fluidModuleExport.IRuntimeFactory === undefined) { @@ -107,12 +109,19 @@ function wrapWithRuntimeFactoryIfNeeded(packageJson: IFluidPackage, fluidModule: ]), ); return { - fluidExport: { - IRuntimeFactory: runtimeFactory, + module: { + fluidExport: { + IRuntimeFactory: runtimeFactory, + }, }, + details: { package: packageJson.name, config: { } }, }; } - return fluidModule; + + return { + module: fluidModule, + details: { package: packageJson.name, config: { } }, + }; } // Invoked by `start()` when the 'double' option is enabled to create the side-by-side panes.