diff --git a/.changeset/purple-areas-see.md b/.changeset/purple-areas-see.md new file mode 100644 index 000000000000..801d451bc674 --- /dev/null +++ b/.changeset/purple-areas-see.md @@ -0,0 +1,7 @@ +--- +"@gradio/app": minor +"@gradio/preview": minor +"gradio": minor +--- + +feat:Improve Embed and CDN handling and fix a couple of related bugs diff --git a/.config/basevite.config.ts b/.config/basevite.config.ts index 378aa1bf963b..3bc5f18da0fa 100644 --- a/.config/basevite.config.ts +++ b/.config/basevite.config.ts @@ -27,10 +27,7 @@ const version = JSON.parse(readFileSync(version_path, { encoding: "utf-8" })) //@ts-ignore export default defineConfig(({ mode }) => { - const production = - mode === "production:cdn" || - mode === "production:local" || - mode === "production:website"; + const production = mode === "production"; return { server: { diff --git a/build_pypi.sh b/build_pypi.sh index f54d6798bc24..32c76e1f58cd 100755 --- a/build_pypi.sh +++ b/build_pypi.sh @@ -9,12 +9,9 @@ new_version=$(python -c "import json; f = open('$FILE', 'r'); data = json.load(f GRADIO_VERSION=$new_version rm -rf gradio/templates/frontend -rm -rf gradio/templates/cdn pnpm i --frozen-lockfile --ignore-scripts GRADIO_VERSION=$new_version pnpm build -GRADIO_VERSION=$new_version pnpm build:cdn -aws s3 cp gradio/templates/cdn "s3://gradio/${new_version}/" --recursive --region us-west-2 -cp gradio/templates/cdn/index.html gradio/templates/frontend/share.html +aws s3 cp gradio/templates/frontend "s3://gradio/${new_version}/" --recursive --region us-west-2 rm -rf dist/* rm -rf build/* diff --git a/js/app/build_plugins.ts b/js/app/build_plugins.ts index 3b6818a48b7e..f642574837c7 100644 --- a/js/app/build_plugins.ts +++ b/js/app/build_plugins.ts @@ -17,54 +17,17 @@ export function inject_ejs(): Plugin { }; } -interface PatchDynamicImportOptionms { - mode: "cdn" | "local"; - gradio_version: string; - cdn_url: string; -} - -export function patch_dynamic_import({ - mode, - gradio_version, - cdn_url -}: PatchDynamicImportOptionms): Plugin { - return { - name: "patch-dynamic-import", - enforce: "post", - writeBundle(config, bundle) { - // const import_re = /import\(((?:'|")[\.\/a-zA-Z0-9]*(?:'|"))\)/g; - // const import_meta = `${"import"}.${"meta"}.${"url"}`; - // for (const file in bundle) { - // const chunk = bundle[file]; - // if (chunk.type === "chunk") { - // if (chunk.code.indexOf("import(") > -1) { - // const fix_fn = `const VERSION_RE = new RegExp("${gradio_version}\/", "g");function import_fix(mod, base) {const url = new URL(mod, base); return import(\`${cdn_url}\${url.pathname?.startsWith('/') ? url.pathname.substring(1).replace(VERSION_RE, "") : url.pathname.replace(VERSION_RE, "")}\`);}`; - // chunk.code = - // fix_fn + - // chunk.code.replace(import_re, `import_fix($1, ${import_meta})`); - // if (!config.dir) break; - // const output_location = join(config.dir, chunk.fileName); - // writeFileSync(output_location, chunk.code); - // } - // } - // } - } - }; -} - export function generate_cdn_entry({ - enable, - cdn_url + version, + cdn_base }: { - enable: boolean; - cdn_url: string; + version: string; + cdn_base: string; }): Plugin { return { name: "generate-cdn-entry", enforce: "post", writeBundle(config, bundle) { - if (!enable) return; - if ( !config.dir || !bundle["index.html"] || @@ -72,15 +35,29 @@ export function generate_cdn_entry({ ) return; - const tree = parse(bundle["index.html"].source as string); - const script = - Array.from(tree.querySelectorAll("script[type=module]")).find( - (node) => node.attributes.src?.startsWith(cdn_url) - )?.attributes.src || ""; + const source = bundle["index.html"].source as string; + const tree = parse(source); + + const script = Array.from( + tree.querySelectorAll("script[type=module]") + ).find((node) => node.attributes.src?.includes("assets")); const output_location = join(config.dir, "gradio.js"); - writeFileSync(output_location, make_entry(script)); + writeFileSync(output_location, make_entry(script?.attributes.src || "")); + + if (!script) return; + + const transformed_html = + (bundle["index.html"].source as string).substring(0, script?.range[0]) + + `` + + (bundle["index.html"].source as string).substring( + script?.range[1], + source.length + ); + + const share_html_location = join(config.dir, "share.html"); + writeFileSync(share_html_location, transformed_html); } }; } @@ -93,6 +70,7 @@ export function generate_dev_entry({ enable }: { enable: boolean }): Plugin { name: "generate-dev-entry", transform(code, id) { if (!enable) return; + const new_code = code.replace(RE_SVELTE_IMPORT, (str, $1, $2) => { return `const ${$1.replace( " as ", @@ -109,18 +87,7 @@ export function generate_dev_entry({ enable }: { enable: boolean }): Plugin { } function make_entry(script: string): string { - const make_script = ` -function make_script(src) { - const script = document.createElement('script'); - script.type = 'module'; - script.setAttribute("crossorigin", ""); - script.src = src; - document.head.appendChild(script); -}`; - - return ` -${make_script} -make_script("${script}"); + return `import("${script}"); `; } @@ -174,14 +141,6 @@ export function handle_ce_css(): Plugin { } ); - const transformed_html = - (bundle["index.html"].source as string).substring(0, style!.range[0]) + - (bundle["index.html"].source as string).substring( - style!.range[1], - bundle["index.html"].source.length - ); - const html_location = join(config.dir, "index.html"); - writeFileSync( file_to_insert.filename, file_to_insert.source @@ -192,7 +151,19 @@ export function handle_ce_css(): Plugin { ) ); - writeFileSync(html_location, transformed_html); + const share_html_location = join(config.dir, "share.html"); + const share_html = readFileSync(share_html_location, "utf8"); + const share_tree = parse(share_html); + const node = Array.from( + share_tree.querySelectorAll("link[rel=stylesheet]") + ).find((node) => /.*\/index(.*?)\.css/.test(node.attributes.href)); + + if (!node) return; + const transformed_html = + share_html.substring(0, node.range[0]) + + share_html.substring(node.range[1], share_html.length); + + writeFileSync(share_html_location, transformed_html); } }; } diff --git a/js/app/package.json b/js/app/package.json index b3eda37d4762..af8395005be5 100644 --- a/js/app/package.json +++ b/js/app/package.json @@ -8,10 +8,7 @@ "dev:lite": "run-p dev:lite:*", "dev:lite:self": "vite --port 9876 --mode development:lite", "dev:lite:worker": "pnpm --filter @gradio/wasm dev", - "build:cdn": "vite build --mode production:cdn --emptyOutDir", - "build:website": "vite build --mode production:website --emptyOutDir", - "build:local": "vite build --mode production:local --emptyOutDir", - "build:cc": "cross-env NODE_ENV=development vite build --mode dev:custom --emptyOutDir", + "build": "vite build --mode production --emptyOutDir", "cssbuild": "python ../../scripts/generate_theme.py --outfile ./src/lite/theme.css", "pybuild:gradio": "cd ../../ && rm -rf gradio/templates/frontend && python -m build", "pybuild:gradio-client": "cd ../../client/python && python -m build", diff --git a/js/app/src/css.ts b/js/app/src/css.ts index 2899e1e15dc5..22258c6c5ab1 100644 --- a/js/app/src/css.ts +++ b/js/app/src/css.ts @@ -1,16 +1,18 @@ export function mount_css(url: string, target: HTMLElement): Promise { - const existing_link = document.querySelector(`link[href='${url}']`); + const base = new URL(import.meta.url).origin; + const _url = new URL(url, base).href; + const existing_link = document.querySelector(`link[href='${_url}']`); if (existing_link) return Promise.resolve(); const link = document.createElement("link"); link.rel = "stylesheet"; - link.href = url; + link.href = _url; return new Promise((res, rej) => { link.addEventListener("load", () => res()); link.addEventListener("error", () => { - console.error(`Unable to preload CSS for ${url}`); + console.error(`Unable to preload CSS for ${_url}`); res(); }); target.appendChild(link); diff --git a/js/app/src/main.ts b/js/app/src/main.ts index 76aedb37386f..1e5381aa7f81 100644 --- a/js/app/src/main.ts +++ b/js/app/src/main.ts @@ -21,6 +21,15 @@ let FONTS: string | []; FONTS = "__FONTS_CSS__"; let IndexComponent: typeof Index; +let _res: (value?: unknown) => void; +let pending = new Promise((res) => { + _res = res; +}); +async function get_index(): Promise { + IndexComponent = (await import("./Index.svelte")).default; + _res(); +} + function create_custom_element(): void { const o = { SvelteComponent: svelte.SvelteComponent @@ -72,7 +81,7 @@ function create_custom_element(): void { } async connectedCallback(): Promise { - IndexComponent = (await import("./Index.svelte")).default; + await get_index(); this.loading = true; if (this.app) { @@ -136,11 +145,12 @@ function create_custom_element(): void { return ["src", "space", "host"]; } - attributeChangedCallback( + async attributeChangedCallback( name: string, old_val: string, new_val: string - ): void { + ): Promise { + await pending; if ( (name === "host" || name === "space" || name === "src") && new_val !== old_val diff --git a/js/app/vite.config.ts b/js/app/vite.config.ts index 520216312362..b60881274664 100644 --- a/js/app/vite.config.ts +++ b/js/app/vite.config.ts @@ -28,7 +28,6 @@ const client_version_raw = JSON.parse( import { inject_ejs, - patch_dynamic_import, generate_cdn_entry, generate_dev_entry, handle_ce_css, @@ -36,32 +35,23 @@ import { resolve_svelte } from "./build_plugins"; -const GRADIO_VERSION = version || "asd_stub_asd"; -const TEST_CDN = !!process.env.TEST_CDN; -const CDN = TEST_CDN - ? "http://localhost:4321/" - : `https://gradio.s3-us-west-2.amazonaws.com/${version_raw}/`; +const GRADIO_VERSION = version_raw || "asd_stub_asd"; +const CDN_BASE = "https://gradio.s3-us-west-2.amazonaws.com"; const TEST_MODE = process.env.TEST_MODE || "jsdom"; //@ts-ignore export default defineConfig(({ mode }) => { console.log(mode); const targets = { - "production:cdn": "../../gradio/templates/cdn", - "production:local": "../../gradio/templates/frontend", + production: "../../gradio/templates/frontend", "dev:custom": "../../gradio/templates/frontend" }; - const CDN_URL = mode === "production:cdn" ? CDN : "/"; - const production = - mode === "production:cdn" || - mode === "production:local" || - mode === "production:website" || - mode === "production:lite"; - const is_cdn = mode === "production:cdn" || mode === "production:website"; + const production = mode === "production" || mode === "production:lite"; const is_lite = mode.endsWith(":lite"); return { - base: is_cdn ? CDN_URL : "./", + base: "./", + server: { port: 9876, open: is_lite ? "/lite.html" : "/" @@ -70,7 +60,8 @@ export default defineConfig(({ mode }) => { build: { sourcemap: true, target: "esnext", - minify: production, + // minify: production, + minify: false, outDir: is_lite ? resolve(__dirname, "../lite/dist") : targets[mode], // To build Gradio-lite as a library, we can't use the library mode // like `lib: is_lite && {}` @@ -161,12 +152,7 @@ export default defineConfig(({ mode }) => { }), generate_dev_entry({ enable: mode !== "development" && mode !== "test" }), inject_ejs(), - patch_dynamic_import({ - mode: is_cdn ? "cdn" : "local", - gradio_version: GRADIO_VERSION, - cdn_url: CDN_URL - }), - generate_cdn_entry({ enable: is_cdn, cdn_url: CDN_URL }), + generate_cdn_entry({ version: GRADIO_VERSION, cdn_base: CDN_BASE }), handle_ce_css(), inject_component_loader() ], diff --git a/js/preview/rollup.config.js b/js/preview/rollup.config.js index 62b6d4c49e5e..ceaaa7a328b8 100644 --- a/js/preview/rollup.config.js +++ b/js/preview/rollup.config.js @@ -18,7 +18,6 @@ const vite_client = require.resolve("vite/dist/client/client.mjs"); const hmr = require.resolve("svelte-hmr"); const output_svelte_dir = "../../gradio/templates/frontend/assets/svelte"; -const output_svelte_dir_cdn = "../../gradio/templates/cdn/assets/svelte"; const onwarn = (warning, warn) => { if (warning.plugin === "typescript") return; @@ -153,32 +152,21 @@ export default [ }, { input: "src/svelte-submodules.ts", - output: [ - { - file: join(output_svelte_dir, "svelte-submodules.js"), - format: "esm" - }, - { - file: join(output_svelte_dir_cdn, "svelte-submodules.js"), - format: "esm" - } - ], + output: { + file: join(output_svelte_dir, "svelte-submodules.js"), + format: "esm" + }, + onwarn, plugins }, { input: "src/svelte-internal.ts", - output: [ - { - file: join(output_svelte_dir, "svelte.js"), - format: "esm" - }, - { - file: join(output_svelte_dir_cdn, "svelte.js"), - format: "esm" - } - ], + output: { + file: join(output_svelte_dir, "svelte.js"), + format: "esm" + }, onwarn, plugins }, diff --git a/package.json b/package.json index 91ba4d397941..3e0b4967370d 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,8 @@ "scripts": { "dev": "pnpm css && pnpm --filter @gradio/client build && pnpm --filter @gradio/preview build && pnpm --filter @gradio/app dev", "css": "pnpm --filter @gradio/theme generate", - "build": "pnpm css && pnpm --filter @gradio/client build && pnpm --filter @gradio/app build:local --emptyOutDir && pnpm --filter @gradio/preview build", - "build:cdn": "pnpm --filter @gradio/client build && pnpm --filter @gradio/app build:cdn --emptyOutDir && pnpm --filter @gradio/preview build", - "build:website": "pnpm --filter @gradio/app build:website --emptyOutDir", - "build:cdn-local": "TEST_CDN=TRUE pnpm build:cdn", - "preview:cdn-server": "sirv ./gradio/templates/cdn --single --port=4321 --cors", + "build": "pnpm css && pnpm --filter @gradio/client build && pnpm --filter @gradio/app build --emptyOutDir && pnpm --filter @gradio/preview build", + "preview:cdn-server": "sirv ./gradio/templates/frontend --single --port=4321 --cors", "preview:cdn-app": "pnpm --filter @gradio/cdn-test dev", "preview:cdn-local": "run-p preview:cdn-server preview:cdn-app", "format:check": "prettier --ignore-path .config/.prettierignore --check --config .config/.prettierrc.json --plugin prettier-plugin-svelte .",