diff --git a/.changeset/cool-rocks-joke.md b/.changeset/cool-rocks-joke.md new file mode 100644 index 0000000000000..c0c767ff1b716 --- /dev/null +++ b/.changeset/cool-rocks-joke.md @@ -0,0 +1,6 @@ +--- +"@gradio/app": minor +"gradio": minor +--- + +feat:Fix the Lite custom element to initialize the app in the connected callback and dispose the app in the disconnected callback diff --git a/js/app/src/lite/custom-element/index.ts b/js/app/src/lite/custom-element/index.ts index 3a548cecdc531..4ed1faa2e19c0 100644 --- a/js/app/src/lite/custom-element/index.ts +++ b/js/app/src/lite/custom-element/index.ts @@ -1,6 +1,10 @@ // NOTE: We should only import the types from ".." to avoid the circular dependency of implementations, // which causes repeated executions of the ".." module in †he dev mode and can lead to multiple instances of the dev app. -import type { create as createLiteAppFunc, Options } from ".."; +import type { + create as createLiteAppFunc, + Options, + GradioAppController +} from ".."; interface GradioComponentOptions { info: Options["info"]; @@ -40,24 +44,33 @@ export function bootstrap_custom_element( } class GradioLiteAppElement extends HTMLElement { - constructor() { - super(); - - const gradioComponentOptions = this.parseGradioComponentOptions(); - const gradioLiteAppOptions = this.parseGradioLiteAppOptions(); - - this.innerHTML = ""; - - create({ - target: this, // Same as `js/app/src/main.ts` - code: gradioLiteAppOptions.code, - requirements: gradioLiteAppOptions.requirements, - files: gradioLiteAppOptions.files, - entrypoint: gradioLiteAppOptions.entrypoint, - ...gradioComponentOptions + controller: GradioAppController | null = null; + + connectedCallback(): void { + // At the time of connectedCallback, the child elements of the custom element are not yet parsed, + // so we need to defer the initialization to the next frame. + // Ref: https://stackoverflow.com/q/70949141/13103190 + window.requestAnimationFrame(() => { + const gradioComponentOptions = this.parseGradioComponentOptions(); + const gradioLiteAppOptions = this.parseGradioLiteAppOptions(); + + this.innerHTML = ""; + + this.controller = create({ + target: this, // Same as `js/app/src/main.ts` + code: gradioLiteAppOptions.code, + requirements: gradioLiteAppOptions.requirements, + files: gradioLiteAppOptions.files, + entrypoint: gradioLiteAppOptions.entrypoint, + ...gradioComponentOptions + }); }); } + disconnectedCallback(): void { + this.controller?.unmount(); + } + parseGradioComponentOptions(): GradioComponentOptions { // Parse the options from the attributes of the element. // The following attributes are supported: diff --git a/js/app/src/lite/index.ts b/js/app/src/lite/index.ts index 0e046e8dcddeb..5b295938fa0a1 100644 --- a/js/app/src/lite/index.ts +++ b/js/app/src/lite/index.ts @@ -35,7 +35,7 @@ declare let GRADIO_VERSION: string; // As a result, the users of the Wasm app will have to load the CSS file manually. // const ENTRY_CSS = "__ENTRY_CSS__"; -interface GradioAppController { +export interface GradioAppController { run_code: (code: string) => Promise; run_file: (path: string) => Promise; write: (