From aad0b3c157b9cfa36991ad31b5cc6c8718493737 Mon Sep 17 00:00:00 2001 From: Stephen Zhou Date: Wed, 8 Apr 2026 15:26:39 +0800 Subject: [PATCH] build: include vinext in docker build (#34535) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com> Co-authored-by: yyh --- docker/.env.example | 3 +++ docker/docker-compose-template.yaml | 1 + docker/docker-compose.yaml | 2 ++ web/Dockerfile | 10 ++++++---- .../__tests__/use-workflow-interactions.spec.tsx | 8 ++++++-- .../hooks/use-workflow-organize.helpers.ts | 2 +- .../workflow/hooks/use-workflow-organize.ts | 2 +- web/app/components/workflow/utils/elk-layout.ts | 15 +++++++++++---- web/app/components/workflow/utils/index.ts | 1 - web/docker/entrypoint.sh | 6 +++++- web/eslint-suppressions.json | 2 +- 11 files changed, 37 insertions(+), 15 deletions(-) diff --git a/docker/.env.example b/docker/.env.example index f20d57c71a..e32c9108e8 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -1173,6 +1173,9 @@ MAX_ITERATIONS_NUM=99 # The timeout for the text generation in millisecond TEXT_GENERATION_TIMEOUT_MS=60000 +# Enable the experimental vinext runtime shipped in the image. +EXPERIMENTAL_ENABLE_VINEXT=false + # Allow rendering unsafe URLs which have "data:" scheme. ALLOW_UNSAFE_DATA_SCHEME=false diff --git a/docker/docker-compose-template.yaml b/docker/docker-compose-template.yaml index 5234202a62..0e766da878 100644 --- a/docker/docker-compose-template.yaml +++ b/docker/docker-compose-template.yaml @@ -161,6 +161,7 @@ services: NEXT_PUBLIC_COOKIE_DOMAIN: ${NEXT_PUBLIC_COOKIE_DOMAIN:-} SENTRY_DSN: ${WEB_SENTRY_DSN:-} NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0} + EXPERIMENTAL_ENABLE_VINEXT: ${EXPERIMENTAL_ENABLE_VINEXT:-false} TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000} CSP_WHITELIST: ${CSP_WHITELIST:-} ALLOW_EMBED: ${ALLOW_EMBED:-false} diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index d03835e2b0..1a61573446 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -509,6 +509,7 @@ x-shared-env: &shared-api-worker-env MAX_PARALLEL_LIMIT: ${MAX_PARALLEL_LIMIT:-10} MAX_ITERATIONS_NUM: ${MAX_ITERATIONS_NUM:-99} TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000} + EXPERIMENTAL_ENABLE_VINEXT: ${EXPERIMENTAL_ENABLE_VINEXT:-false} ALLOW_UNSAFE_DATA_SCHEME: ${ALLOW_UNSAFE_DATA_SCHEME:-false} MAX_TREE_DEPTH: ${MAX_TREE_DEPTH:-50} PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata} @@ -870,6 +871,7 @@ services: NEXT_PUBLIC_COOKIE_DOMAIN: ${NEXT_PUBLIC_COOKIE_DOMAIN:-} SENTRY_DSN: ${WEB_SENTRY_DSN:-} NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0} + EXPERIMENTAL_ENABLE_VINEXT: ${EXPERIMENTAL_ENABLE_VINEXT:-false} TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000} CSP_WHITELIST: ${CSP_WHITELIST:-} ALLOW_EMBED: ${ALLOW_EMBED:-false} diff --git a/web/Dockerfile b/web/Dockerfile index 030651bf27..4971f86f97 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -42,7 +42,7 @@ COPY . . WORKDIR /app/web ENV NODE_OPTIONS="--max-old-space-size=4096" -RUN pnpm build +RUN pnpm build && pnpm build:vinext # production stage @@ -56,6 +56,7 @@ ENV APP_API_URL=http://127.0.0.1:5001 ENV MARKETPLACE_API_URL=https://marketplace.dify.ai ENV MARKETPLACE_URL=https://marketplace.dify.ai ENV PORT=3000 +ENV EXPERIMENTAL_ENABLE_VINEXT=false ENV NEXT_TELEMETRY_DISABLED=1 # set timezone @@ -73,9 +74,10 @@ RUN addgroup -S -g ${dify_uid} dify && \ WORKDIR /app -COPY --from=builder --chown=dify:dify /app/web/public ./web/public -COPY --from=builder --chown=dify:dify /app/web/.next/standalone ./ -COPY --from=builder --chown=dify:dify /app/web/.next/static ./web/.next/static +COPY --from=builder --chown=dify:dify /app/web/public ./targets/next/web/public +COPY --from=builder --chown=dify:dify /app/web/.next/standalone ./targets/next/ +COPY --from=builder --chown=dify:dify /app/web/.next/static ./targets/next/web/.next/static +COPY --from=builder --chown=dify:dify /app/web/dist/standalone ./targets/vinext COPY --chown=dify:dify --chmod=755 web/docker/entrypoint.sh ./entrypoint.sh diff --git a/web/app/components/workflow/hooks/__tests__/use-workflow-interactions.spec.tsx b/web/app/components/workflow/hooks/__tests__/use-workflow-interactions.spec.tsx index 95dc3dff00..8038fc528d 100644 --- a/web/app/components/workflow/hooks/__tests__/use-workflow-interactions.spec.tsx +++ b/web/app/components/workflow/hooks/__tests__/use-workflow-interactions.spec.tsx @@ -111,12 +111,16 @@ vi.mock('../use-workflow-history', () => ({ vi.mock('../../utils', async importOriginal => ({ ...(await importOriginal()), - getLayoutForChildNodes: (...args: unknown[]) => mockGetLayoutForChildNodes(...args), - getLayoutByELK: (...args: unknown[]) => mockGetLayoutByELK(...args), initialNodes: (nodes: unknown[], edges: unknown[]) => mockInitialNodes(nodes, edges), initialEdges: (edges: unknown[], nodes: unknown[]) => mockInitialEdges(edges, nodes), })) +vi.mock('../../utils/elk-layout', async importOriginal => ({ + ...(await importOriginal()), + getLayoutForChildNodes: (...args: unknown[]) => mockGetLayoutForChildNodes(...args), + getLayoutByELK: (...args: unknown[]) => mockGetLayoutByELK(...args), +})) + describe('use-workflow-interactions exports', () => { it('re-exports the split workflow interaction hooks', () => { expect(workflowInteractionExports.useWorkflowInteractions).toBeTypeOf('function') diff --git a/web/app/components/workflow/hooks/use-workflow-organize.helpers.ts b/web/app/components/workflow/hooks/use-workflow-organize.helpers.ts index c95e003e7f..850aa403ef 100644 --- a/web/app/components/workflow/hooks/use-workflow-organize.helpers.ts +++ b/web/app/components/workflow/hooks/use-workflow-organize.helpers.ts @@ -1,5 +1,5 @@ import type { Node } from '../types' -import type { LayoutResult } from '../utils' +import type { LayoutResult } from '../utils/elk-layout' import { produce } from 'immer' import { CUSTOM_NODE, diff --git a/web/app/components/workflow/hooks/use-workflow-organize.ts b/web/app/components/workflow/hooks/use-workflow-organize.ts index da158a4214..1acaa07fbc 100644 --- a/web/app/components/workflow/hooks/use-workflow-organize.ts +++ b/web/app/components/workflow/hooks/use-workflow-organize.ts @@ -4,7 +4,7 @@ import { useWorkflowStore } from '../store' import { getLayoutByELK, getLayoutForChildNodes, -} from '../utils' +} from '../utils/elk-layout' import { useNodesSyncDraft } from './use-nodes-sync-draft' import { useNodesReadOnly } from './use-workflow' import { useWorkflowHistory, WorkflowHistoryEvent } from './use-workflow-history' diff --git a/web/app/components/workflow/utils/elk-layout.ts b/web/app/components/workflow/utils/elk-layout.ts index 781416f3c4..950074a965 100644 --- a/web/app/components/workflow/utils/elk-layout.ts +++ b/web/app/components/workflow/utils/elk-layout.ts @@ -6,7 +6,6 @@ import type { Edge, Node, } from '@/app/components/workflow/types' -import ELK from 'elkjs/lib/elk.bundled.js' import { cloneDeep } from 'es-toolkit/object' import { CUSTOM_NODE, @@ -19,7 +18,15 @@ import { BlockEnum, } from '@/app/components/workflow/types' -const elk = new ELK() +let elk: import('elkjs/lib/elk-api').ELK | undefined + +async function getELK() { + if (!elk) { + const { default: ELK } = await import('elkjs/lib/elk.bundled.js') + elk = new ELK() + } + return elk +} const DEFAULT_NODE_WIDTH = 244 const DEFAULT_NODE_HEIGHT = 100 @@ -473,7 +480,7 @@ export const getLayoutByELK = async (originNodes: Node[], originEdges: Edge[]): edges: elkEdges, } - const layoutedGraph = await elk.layout(graph) + const layoutedGraph = await (await getELK()).layout(graph) const layout = collectLayout(layoutedGraph, () => true) return normaliseBounds(layout) } @@ -571,7 +578,7 @@ export const getLayoutForChildNodes = async ( edges: elkEdges, } - const layoutedGraph = await elk.layout(graph) + const layoutedGraph = await (await getELK()).layout(graph) const layout = collectLayout(layoutedGraph, () => true) return normaliseChildLayout(layout, nodes) } diff --git a/web/app/components/workflow/utils/index.ts b/web/app/components/workflow/utils/index.ts index 715ce081a3..641deec695 100644 --- a/web/app/components/workflow/utils/index.ts +++ b/web/app/components/workflow/utils/index.ts @@ -1,7 +1,6 @@ export * from './common' export * from './data-source' export * from './edge' -export * from './elk-layout' export * from './gen-node-meta-data' export * from './node' export * from './tool' diff --git a/web/docker/entrypoint.sh b/web/docker/entrypoint.sh index 034ed96491..50681910d2 100755 --- a/web/docker/entrypoint.sh +++ b/web/docker/entrypoint.sh @@ -43,4 +43,8 @@ export NEXT_PUBLIC_MAX_PARALLEL_LIMIT=${MAX_PARALLEL_LIMIT} export NEXT_PUBLIC_MAX_ITERATIONS_NUM=${MAX_ITERATIONS_NUM} export NEXT_PUBLIC_MAX_TREE_DEPTH=${MAX_TREE_DEPTH} -exec node /app/web/server.js +if [ "${EXPERIMENTAL_ENABLE_VINEXT:-}" = "true" ]; then + exec node /app/targets/vinext/server.js +fi + +exec node /app/targets/next/web/server.js diff --git a/web/eslint-suppressions.json b/web/eslint-suppressions.json index 37417e7aa4..d334d7a153 100644 --- a/web/eslint-suppressions.json +++ b/web/eslint-suppressions.json @@ -11278,7 +11278,7 @@ }, "app/components/workflow/utils/index.ts": { "no-barrel-files/no-barrel-files": { - "count": 10 + "count": 9 } }, "app/components/workflow/utils/node-navigation.ts": {