From b794d96effa5e7fac0a226f0be81dc44e4fec40d Mon Sep 17 00:00:00 2001 From: Chenlei Hu Date: Mon, 17 Jun 2024 12:18:53 -0400 Subject: [PATCH] Bundle frontend app (#15) * Add shim in vite build * shim * Move public back to src --- package-lock.json | 126 ++++++++++++++++++++++++++++++++++++++++++--- package.json | 2 +- src/scripts/app.ts | 9 +++- vite.config.mts | 98 +++++++++++++++++++++++++++++------ 4 files changed, 210 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index f4489bb93..0f4dc8702 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "tsx": "^4.15.6", "typescript": "^5.4.5", "vite": "^5.2.0", - "vite-plugin-no-bundle": "^4.0.0" + "vite-plugin-static-copy": "^1.0.5" } }, "node_modules/@ampproject/remapping": { @@ -3648,6 +3648,18 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3790,6 +3802,30 @@ "node": ">=10" } }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -4417,6 +4453,29 @@ "node": ">= 6" } }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs-extra/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -4683,6 +4742,18 @@ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-core-module": { "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", @@ -6543,6 +6614,27 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonfile/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -7088,6 +7180,18 @@ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -8326,14 +8430,22 @@ } } }, - "node_modules/vite-plugin-no-bundle": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/vite-plugin-no-bundle/-/vite-plugin-no-bundle-4.0.0.tgz", - "integrity": "sha512-DXsJGXtp/QLWNFBfBqr+arxaTHEgiPCAgf9bcOPGv4n3AsFigsFj+oL95nFdMt8cRbgRDtvyTX802IZNBGg3Xg==", + "node_modules/vite-plugin-static-copy": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-1.0.5.tgz", + "integrity": "sha512-02k0Rox+buYdEOfeilKZSgs1gXfPf9RjVztZEIYZgVIxjsVZi6AXssjzdi+qW6zYt00d3bq+tpP2voVXN2fKLw==", "dev": true, "dependencies": { - "fast-glob": "^3.3.2", - "micromatch": "^4.0.5" + "chokidar": "^3.5.3", + "fast-glob": "^3.2.11", + "fs-extra": "^11.1.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0" } }, "node_modules/w3c-xmlserializer": { diff --git a/package.json b/package.json index fd70690f3..f202add72 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,6 @@ "tsx": "^4.15.6", "typescript": "^5.4.5", "vite": "^5.2.0", - "vite-plugin-no-bundle": "^4.0.0" + "vite-plugin-static-copy": "^1.0.5" } } diff --git a/src/scripts/app.ts b/src/scripts/app.ts index c13ed4fd7..0566b98c3 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -6,8 +6,9 @@ import { defaultGraph } from "./defaultGraph"; import { getPngMetadata, getWebpMetadata, importA1111, getLatentMetadata } from "./pnginfo"; import { addDomClippingSetting } from "./domWidget"; import { createImageHost, calculateImageGrid } from "./ui/imagePreview" +import { applyTextReplacements, addStylesheet } from "./utils"; import type { ComfyExtension } from "/types/comfy"; -import type { IWidget, LGraph, LGraphCanvas, LGraphNode } from "/types/litegraph"; +import type { LGraph, LGraphCanvas, LGraphNode } from "/types/litegraph"; export const ANIM_PREVIEW_WIDGET = "$$comfy_animation_preview" @@ -51,6 +52,12 @@ export class ComfyApp { static open_maskeditor = null; static clipspace_return_node = null; + // Force vite to import utils.ts as part of index. + static utils = { + applyTextReplacements, + addStylesheet, + }; + ui: ComfyUI; logging: ComfyLogging; extensions: ComfyExtension[]; diff --git a/vite.config.mts b/vite.config.mts index 2288e6bcb..d3261d041 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -1,7 +1,76 @@ -import { defineConfig } from 'vite'; -import noBundlePlugin from 'vite-plugin-no-bundle'; +import { defineConfig, Plugin } from 'vite'; +import { viteStaticCopy } from 'vite-plugin-static-copy' +import path from 'path'; +interface ShimResult { + code: string; + exports: string[]; +} + +function comfyAPIPlugin(): Plugin { + return { + name: 'comfy-api-plugin', + transform(code: string, id: string) { + if (id.endsWith('.ts')) { + const result = transformExports(code, id); + + if (result.exports.length > 0) { + const projectRoot = process.cwd(); + const relativePath = path.relative(path.join(projectRoot, 'src'), id); + const shimFileName = relativePath.replace(/\.ts$/, '.js'); + + const shimComment = `// Shim for ${relativePath}\n`; + + this.emitFile({ + type: "asset", + fileName: shimFileName, + source: shimComment + result.exports.join(""), + }); + } + + return { + code: result.code, + map: null // If you're not modifying the source map, return null + }; + } + } + }; +} + +function transformExports(code: string, id: string): ShimResult { + const moduleName = getModuleName(id); + const exports: string[] = []; + let newCode = code; + + // Regex to match different types of exports + const regex = /export\s+(const|let|var|function|class|async function)\s+([a-zA-Z$_][a-zA-Z\d$_]*)(\s|\()/g; + let match; + + while ((match = regex.exec(code)) !== null) { + const name = match[2]; + // All exports should be bind to the window object as new API endpoint. + if (exports.length == 0) { + newCode += `\nwindow.comfyAPI = window.comfyAPI || {};`; + newCode += `\nwindow.comfyAPI.${moduleName} = window.comfyAPI.${moduleName} || {};`; + } + newCode += `\nwindow.comfyAPI.${moduleName}.${name} = ${name};`; + exports.push(`export const ${name} = window.comfyAPI.${moduleName}.${name};\n`); + } + + return { + code: newCode, + exports, + }; +} + +function getModuleName(id: string): string { + // Simple example to derive a module name from the file path + const parts = id.split('/'); + const fileName = parts[parts.length - 1]; + return fileName.replace(/\.\w+$/, ''); // Remove file extension +} + export default defineConfig({ server: { open: true, @@ -13,22 +82,19 @@ export default defineConfig({ } } }, - plugins: [noBundlePlugin({ - copy: [ - '**/*.css', - 'lib/*.js', - // Make sure to include all core extensions, as they are loaded dynamically - 'extensions/core/*.js', - // Include modules only used by core extensions - 'scripts/ui/draggableList.js', - ] - })], + plugins: [ + comfyAPIPlugin(), + viteStaticCopy({ + targets: [ + {src: "src/lib/*", dest: "lib/"}, + {src: "src/extensions/*", dest: "extensions/"}, + {src: "src/scripts/ui/draggableList.js", dest: "scripts/ui/"}, + ], + }), + ], build: { - lib: { - formats: ['es'], - entry: 'index.html', - }, minify: false, + sourcemap: true, rollupOptions: { // Disabling tree-shaking // Prevent vite remove unused exports