1
import type { Plugin } from "vite";
2
import { parse, HTMLElement } from "node-html-parser";
4
import { join } from "path";
5
import { writeFileSync } from "fs";
7
export function inject_ejs(): Plugin {
11
transformIndexHtml: (html) => {
14
`<script>window.gradio_config = {{ config | toorjson }};</script>`
20
export function generate_cdn_entry({
28
name: "generate-cdn-entry",
30
writeBundle(config, bundle) {
33
!bundle["index.html"] ||
34
bundle["index.html"].type !== "asset"
38
const source = bundle["index.html"].source as string;
39
const tree = parse(source);
41
const script = Array.from(
42
tree.querySelectorAll("script[type=module]")
43
).find((node) => node.attributes.src?.includes("assets"));
45
const output_location = join(config.dir, "gradio.js");
47
writeFileSync(output_location, make_entry(script?.attributes.src || ""));
51
const transformed_html =
52
(bundle["index.html"].source as string).substring(0, script?.range[0]) +
53
`<script type="module" crossorigin src="${cdn_base}/${version}/gradio.js"></script>` +
54
(bundle["index.html"].source as string).substring(
59
const share_html_location = join(config.dir, "share.html");
60
writeFileSync(share_html_location, transformed_html);
65
const RE_SVELTE_IMPORT =
66
/import\s+([\w*{},\s]+)\s+from\s+['"](svelte|svelte\/internal)['"]/g;
68
export function generate_dev_entry({ enable }: { enable: boolean }): Plugin {
70
name: "generate-dev-entry",
74
const new_code = code.replace(RE_SVELTE_IMPORT, (str, $1, $2) => {
75
return `const ${$1.replace(
78
)} = window.__gradio__svelte__internal;`;
89
function make_entry(script: string): string {
90
return `import("${script}");
94
export function handle_ce_css(): Plugin {
97
name: "custom-element-css",
99
writeBundle(config, bundle) {
100
let file_to_insert = {
107
!bundle["index.html"] ||
108
bundle["index.html"].type !== "asset"
112
for (const key in bundle) {
113
const chunk = bundle[key];
114
if (chunk.type === "chunk") {
115
const _chunk = chunk;
117
const found = _chunk.code?.indexOf("ENTRY_CSS");
121
filename: join(config.dir, key),
127
const tree = parse(bundle["index.html"].source as string);
129
const { style, fonts } = Array.from(
130
tree.querySelectorAll("link[rel=stylesheet]")
133
if (/.*\/index(.*?)\.css/.test(next.attributes.href)) {
134
return { ...acc, style: next };
136
return { ...acc, fonts: [...acc.fonts, next.attributes.href] };
138
{ fonts: [], style: undefined } as {
140
style: HTMLElement | undefined;
145
file_to_insert.filename,
146
file_to_insert.source
147
.replace("__ENTRY_CSS__", style!.attributes.href)
150
`[${fonts.map((f) => `"${f}"`).join(",")}]`
154
const share_html_location = join(config.dir, "share.html");
155
const share_html = readFileSync(share_html_location, "utf8");
156
const share_tree = parse(share_html);
157
const node = Array.from(
158
share_tree.querySelectorAll("link[rel=stylesheet]")
159
).find((node) => /.*\/index(.*?)\.css/.test(node.attributes.href));
162
const transformed_html =
163
share_html.substring(0, node.range[0]) +
164
share_html.substring(node.range[1], share_html.length);
166
writeFileSync(share_html_location, transformed_html);
171
// generate component importsy
173
import * as url from "url";
174
const __filename = url.fileURLToPath(import.meta.url);
175
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
177
import { readdirSync, existsSync, readFileSync, statSync } from "fs";
179
function get_export_path(
182
pkg_json: Record<string, any>
183
): string | undefined {
184
if (!pkg_json.exports) return undefined;
185
const _path = join(root, "..", `${pkg_json.exports[`${path}`]}`);
187
return existsSync(_path) ? _path : undefined;
212
function generate_component_imports(): string {
213
const exports = readdirSync(join(__dirname, ".."))
215
if (ignore_list.includes(dir)) return undefined;
216
if (!statSync(join(__dirname, "..", dir)).isDirectory()) return undefined;
218
const package_json_path = join(__dirname, "..", dir, "package.json");
219
if (existsSync(package_json_path)) {
220
const package_json = JSON.parse(
221
readFileSync(package_json_path, "utf8")
224
const component = get_export_path(".", package_json_path, package_json);
225
const example = get_export_path(
231
if (!component && !example) return undefined;
234
name: package_json.name,
241
.filter((x) => x !== undefined);
243
const imports = exports.reduce((acc, _export) => {
244
if (!_export) return acc;
246
const example = _export.example
247
? `example: () => import("${_export.name}/example"),\n`
249
return `${acc}"${_export.name.replace("@gradio/", "")}": {
251
component: () => import("${_export.name}")
258
function load_virtual_component_loader(): string {
259
const loader_path = join(__dirname, "component_loader.js");
260
const component_map = `
261
const component_map = {
262
${generate_component_imports()}
265
return `${component_map}\n\n${readFileSync(loader_path, "utf8")}`;
268
export function inject_component_loader(): Plugin {
269
const v_id = "virtual:component-loader";
270
const resolved_v_id = "\0" + v_id;
273
name: "inject-component-loader",
275
resolveId(id: string) {
276
if (id === v_id) return resolved_v_id;
279
if (id === resolved_v_id) {
280
return load_virtual_component_loader();
286
export function resolve_svelte(enable: boolean): Plugin {
289
name: "resolve-svelte",
290
async resolveId(id: string) {
294
id === "./svelte/svelte.js" ||
296
id === "svelte/internal"
309
return { id: mod, external: "absolute" };