Prebuild lite css (#4788)

* Customize scripts/generate_theme.py to reuse for the CSS generation for @gradio/lite

* Build theme.css at the build time of Gradio-lite and update the frontend app to load it at the initialization phase

* Add changeset

---------

Co-authored-by: pngwn <hello@pngwn.io>
This commit is contained in:
Yuichiro Tachibana (Tsuchiya) 2023-07-06 19:38:15 +09:00 committed by GitHub
parent ea889fa8c4
commit 8d0d4e0a8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 42 additions and 12 deletions

View File

@ -0,0 +1,5 @@
---
"@gradio/lite": patch
---
Generate a prebuilt themed CSS file at build time

View File

@ -74,14 +74,14 @@ jobs:
- name: install gradio
run: python -m pip install gradio==$(cat gradio/version.txt)
- name: generate theme.css
run: python scripts/generate_theme.py
run: python scripts/generate_theme.py --outfile js/storybook/theme.css
- name: install dependencies
uses: "./.github/actions/install-all-deps"
with:
always-install-pnpm: true
skip_build: 'true'
- name: build storybook
run: pnpm build-storybook --quiet
run: pnpm build-storybook --quiet
- name: publish to chromatic
id: publish-chromatic
uses: chromaui/action@v1
@ -99,4 +99,3 @@ jobs:
GITHUB_TOKEN: ${{ secrets.COMMENT_TOKEN }}
comment_tag: chromatic-build
pr_number: ${{ env.pr_number }}

1
js/app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/src/lite/theme.css

View File

@ -31,7 +31,7 @@ def upload_file(files):
file_paths = [file.name for file in files]
return file_paths
with gr.Blocks() as demo:
with gr.Blocks(theme=gr.themes.Soft()) as demo:
name = gr.Textbox(label="Name")
output = gr.Textbox(label="Output Box")
greet_btn = gr.Button("Greet")

View File

@ -11,10 +11,11 @@
"build:cdn": "vite build --mode production:cdn --emptyOutDir",
"build:website": "vite build --mode production:website --emptyOutDir",
"build:local": "vite build --mode production:local --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",
"pybuild": "run-p pybuild:*",
"build:lite": "pnpm pybuild && pnpm --filter @gradio/client build && pnpm --filter @gradio/wasm build && vite build --mode production:lite --emptyOutDir",
"build:lite": "pnpm pybuild && pnpm cssbuild && pnpm --filter @gradio/client build && pnpm --filter @gradio/wasm build && vite build --mode production:lite --emptyOutDir",
"preview": "vite preview",
"test:snapshot": "pnpm exec playwright test snapshots/ --config=../../.config/playwright.config.js",
"test:browser": "pnpm exec playwright test test/ --config=../../.config/playwright.config.js",
@ -59,4 +60,4 @@
"msw": {
"workerDirectory": "public"
}
}
}

View File

@ -2,11 +2,21 @@ import type { WorkerProxy } from "@gradio/wasm";
import { is_self_origin } from "./url";
import { mount_css as default_mount_css } from "../css";
// In the Wasm mode, we use a prebuilt CSS file `/static/css/theme.css` to apply the styles in the initialization phase,
// because it will take a long time for `theme.css` to be available after opening the app and loading the Pyodide and the server code.
// The prebuild CSS will be replaced with the dynamic `theme.css` when it is available and `wasm_proxied_mount_css()` is called with its URL.
const PREBUILT_CSS_URL = new URL("./theme.css", import.meta.url).href;
const DYNAMIC_THEME_CSS_URL_PATH = "/theme.css";
export async function mount_prebuilt_css(target: HTMLElement): Promise<void> {
return default_mount_css(PREBUILT_CSS_URL, target);
}
export async function wasm_proxied_mount_css(
worker_proxy: WorkerProxy,
url_string: string,
target: HTMLElement
) {
): Promise<void> {
const request = new Request(url_string); // Resolve a relative URL.
const url = new URL(request.url);
@ -28,6 +38,12 @@ export async function wasm_proxied_mount_css(
);
if (existing_link) return;
if (url.pathname === DYNAMIC_THEME_CSS_URL_PATH) {
console.debug("Unmount the prebuilt theme.css before mounting the dynamic theme.css");
const existing_prebuilt_css = document.querySelector(`link[href='${PREBUILT_CSS_URL}']`);
existing_prebuilt_css?.remove();
}
const style = document.createElement("style");
style.setAttribute("data-wasm-path", url_string);
style.textContent = css;

View File

@ -2,7 +2,7 @@ import "@gradio/theme";
import { WorkerProxy, type WorkerProxyOptions } from "@gradio/wasm";
import { api_factory } from "@gradio/client";
import { wasm_proxied_fetch } from "./fetch";
import { wasm_proxied_mount_css } from "./css";
import { wasm_proxied_mount_css, mount_prebuilt_css } from "./css";
import type { mount_css } from "../css";
import Index from "../Index.svelte";
import type { ThemeMode } from "../components/types";
@ -73,6 +73,8 @@ export function create(options: Options): GradioAppController {
// So we don't await this promise because we want to mount the `Index` immediately and start the app initialization asynchronously.
worker_proxy.runPythonAsync(options.pyCode);
mount_prebuilt_css(document.head);
const overridden_fetch: typeof fetch = (input, init?) => {
return wasm_proxied_fetch(worker_proxy, input, init);
};

View File

@ -1,6 +1,12 @@
from gradio.themes.default import Default
import argparse
from gradio import themes
css = Default()._get_theme_css()
parser = argparse.ArgumentParser(description='Generate themed CSS which is normally served from the /theme.css endpoint of a Gradio server.')
parser.add_argument('--outfile', type=argparse.FileType('w', encoding='latin-1'), default="-")
parser.add_argument('--theme', choices=["default", "glass", "monochrome", "soft"], default="default")
args = parser.parse_args()
with open("js/storybook/theme.css", "w") as file1:
file1.write(css)
ThemeClass = getattr(themes, args.theme.capitalize())
css = ThemeClass()._get_theme_css()
args.outfile.write(css)