mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
## Summary
Establishes distribution-specific code pattern using compile-time
constants and dead code elimination. Demonstrates with Help Center by
hiding extension manager and update buttons in cloud distribution.
Below commentary makes assumption that minifcation and tree-shaking is
enabled (which isn't true yet, but will be eventually).
## Changes
- **What**: Added `src/platform/distribution/types.ts` with distribution
detection via `__DISTRIBUTION__` variable
- **Build**: Vite replaces `__DISTRIBUTION__` at build time using
environment variables
- **Tree-shaking**: All code not relevant to target distribution is
DCR'd and eliminated from bundle
- **Example**: Help Center hides "Manager Extension" menu item and
"Update" buttons in cloud builds
## Pattern
This PR defines a `__DISTRIBUTION__` variable which gets replaced at
build time by Vite using environment variables. All code not relevant to
the given distribution is then DCR'd and tree-shaken.
For simple cases (like this Help Center PR), import `isCloud` and use
compile-time conditionals:
```typescript
import { isCloud } from '@/platform/distribution/types'
if (!isCloud) {
items.push({
key: 'manager',
action: async () => {
await useManagerState().openManager({ ... })
}
})
}
```
The code is DCR'd at build time so there's zero runtime overhead - we
don't even incur the `if (isCloud)` cost because Terser eliminates it.
For complex services later, we'll add interfaces and use an index.ts
that exports different implementations under the same alias per
distribution. It will resemble a DI container but simpler since we don't
need runtime discovery like backend devs do. This guarantees types and
makes testing easier.
Example for services:
```typescript
// src/platform/storage/index.ts
import { isCloud } from '@/platform/distribution/types'
if (isCloud) {
export { CloudStorage as StorageService } from './cloud'
} else {
export { LocalStorage as StorageService } from './local'
}
```
Example for component variants:
```typescript
// src/components/downloads/index.ts
import { isCloud } from '@/platform/distribution/types'
if (isCloud) {
export { default as DownloadButton } from './DownloadButton.cloud.vue'
} else {
export { default as DownloadButton } from './DownloadButton.desktop.vue'
}
```
## Implementation Details
Distribution types (`src/platform/distribution/types.ts`):
```typescript
type Distribution = 'desktop' | 'localhost' | 'cloud'
declare global {
const __DISTRIBUTION__: Distribution
}
const DISTRIBUTION: Distribution = __DISTRIBUTION__
export const isCloud = DISTRIBUTION === 'cloud'
```
Vite configuration adds the define:
```typescript
const DISTRIBUTION = (process.env.DISTRIBUTION || 'localhost') as
| 'desktop'
| 'localhost'
| 'cloud'
export default defineConfig({
define: {
__DISTRIBUTION__: JSON.stringify(DISTRIBUTION)
}
})
```
## Build Commands
```bash
pnpm build # localhost (default)
DISTRIBUTION=cloud pnpm build # cloud
DISTRIBUTION=desktop pnpm build # desktop
```
## Future Applications
This pattern can be used with auth or telemetry services - which will
guarantee all the telemetry code, for example, is not even in the code
distributed in OSS Comfy whatsoever while still being able to develop
off `main`.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6028-Add-distribution-detection-pattern-28a6d73d365081b08767d395472cd1bc)
by [Unito](https://www.unito.io)
65 lines
1.4 KiB
JSON
65 lines
1.4 KiB
JSON
{
|
|
"compilerOptions": {
|
|
"target": "ES2023",
|
|
"useDefineForClassFields": true,
|
|
"module": "ESNext",
|
|
"lib": [
|
|
"ES2023",
|
|
"ES2023.Array",
|
|
"DOM",
|
|
"DOM.Iterable"
|
|
],
|
|
"skipLibCheck": true,
|
|
"incremental": true,
|
|
"sourceMap": true,
|
|
"esModuleInterop": true,
|
|
"moduleResolution": "bundler",
|
|
"experimentalDecorators": true,
|
|
"emitDecoratorMetadata": true,
|
|
"resolveJsonModule": true,
|
|
"strict": true,
|
|
"noUnusedLocals": true,
|
|
"noUnusedParameters": true,
|
|
"noFallthroughCasesInSwitch": true,
|
|
"downlevelIteration": true,
|
|
"noImplicitOverride": true,
|
|
"allowJs": true,
|
|
"verbatimModuleSyntax": true,
|
|
"baseUrl": ".",
|
|
"paths": {
|
|
"@/*": [
|
|
"src/*"
|
|
],
|
|
"@/utils/formatUtil": [
|
|
"packages/shared-frontend-utils/src/formatUtil.ts"
|
|
],
|
|
"@/utils/networkUtil": [
|
|
"packages/shared-frontend-utils/src/networkUtil.ts"
|
|
]
|
|
},
|
|
"typeRoots": [
|
|
"src/types",
|
|
"node_modules/@types",
|
|
"./node_modules"
|
|
],
|
|
"types": [
|
|
"vitest/globals"
|
|
],
|
|
"outDir": "./dist",
|
|
"rootDir": "./"
|
|
},
|
|
"include": [
|
|
".storybook/**/*",
|
|
"eslint.config.ts",
|
|
"global.d.ts",
|
|
"knip.config.ts",
|
|
"src/**/*.vue",
|
|
"src/**/*",
|
|
"src/types/**/*.d.ts",
|
|
"tailwind.config.ts",
|
|
"tests-ui/**/*",
|
|
"vite.config.mts",
|
|
"vitest.config.ts",
|
|
// "vitest.setup.ts",
|
|
]
|
|
} |