From 677d1d309bcc34f2d71620d395ddc6f8d1a1c3cd Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 18 Aug 2025 16:53:05 +0800 Subject: [PATCH 1/3] chore: support dynamic inject env --- .gitignore | 3 +- deploy.env | 2 +- dev.env | 1 - docker/Dockerfile | 8 +++-- docker/docker-compose.example.yml | 14 ++++++++ docker/entrypoint.sh | 35 +++++++++++++++++++ index.html | 1 + .../gallery-preview/GalleryPreview.tsx | 3 +- .../cell/file-media/PreviewImage.tsx | 3 +- .../cell/file-media/UnPreviewFile.tsx | 3 +- .../database-row/file-media/FileMediaItem.tsx | 5 +-- .../components/blocks/file/FileBlock.tsx | 3 +- .../blocks/gallery/GalleryBlock.tsx | 3 +- .../components/blocks/image/ImageBlock.tsx | 3 +- src/components/main/app.hooks.ts | 8 ++--- src/components/ws/useAppflowyWebSocket.ts | 3 +- src/utils/runtime-config.ts | 31 ++++++++++++++++ 17 files changed, 111 insertions(+), 18 deletions(-) create mode 100644 docker/docker-compose.example.yml create mode 100755 docker/entrypoint.sh create mode 100644 src/utils/runtime-config.ts diff --git a/.gitignore b/.gitignore index aee5e21a..d1d9d2ec 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,5 @@ coverage .nyc_output cypress/snapshots/**/__diff_output__/ -**/.claude \ No newline at end of file +**/.claude +cypress/screenshots \ No newline at end of file diff --git a/deploy.env b/deploy.env index 1943513a..d2044de7 100644 --- a/deploy.env +++ b/deploy.env @@ -1,3 +1,3 @@ AF_BASE_URL=http://localhost AF_GOTRUE_URL=http://localhost/gotrue -AF_WS_URL=ws://localhost/ws/v1 +AF_WS_V2_URL=ws://localhost/ws/v2 \ No newline at end of file diff --git a/dev.env b/dev.env index dcde6f63..d1323d60 100644 --- a/dev.env +++ b/dev.env @@ -1,4 +1,3 @@ AF_BASE_URL=http://localhost:8000 AF_GOTRUE_URL=http://localhost:9999 -AF_WS_URL=ws://localhost:8000/ws/v1 AF_WS_V2_URL=ws://localhost:8000/ws/v2 \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile index 09cf5452..9cc5145f 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -9,10 +9,14 @@ COPY . . RUN corepack enable RUN pnpm install - -RUN sed -i 's|https://test.appflowy.cloud||g' src/components/main/app.hooks.ts +# Build without environment variables - they will be injected at runtime RUN pnpm run build FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html/ COPY --from=builder /app/docker/nginx.conf /etc/nginx/nginx.conf +COPY --from=builder /app/docker/entrypoint.sh /docker-entrypoint.sh +RUN chmod +x /docker-entrypoint.sh + +# Set the entrypoint +ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/docker/docker-compose.example.yml b/docker/docker-compose.example.yml new file mode 100644 index 00000000..90a7791a --- /dev/null +++ b/docker/docker-compose.example.yml @@ -0,0 +1,14 @@ +version: '3.8' + +services: + appflowy-web: + image: appflowy/appflowy_web:latest + ports: + - "80:80" + environment: + # REQUIRED: Configure these to match your AppFlowy backend URLs + # The container will fail to start if these are not set + - AF_BASE_URL=https://your-backend.example.com + - AF_GOTRUE_URL=https://your-backend.example.com/gotrue + - AF_WS_V2_URL=wss://your-backend.example.com/ws/v2 + restart: unless-stopped \ No newline at end of file diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100755 index 00000000..b0018ad5 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,35 @@ +#!/bin/sh +set -e + +# Check required environment variables +if [ -z "${AF_BASE_URL}" ]; then + echo "ERROR: AF_BASE_URL environment variable is required but not set" + echo "Please set AF_BASE_URL to your AppFlowy backend URL (e.g., https://your-backend.example.com)" + exit 1 +fi + +if [ -z "${AF_GOTRUE_URL}" ]; then + echo "ERROR: AF_GOTRUE_URL environment variable is required but not set" + echo "Please set AF_GOTRUE_URL to your GoTrue authentication service URL (e.g., https://your-backend.example.com/gotrue)" + exit 1 +fi + +if [ -z "${AF_WS_V2_URL}" ]; then + echo "ERROR: AF_WS_V2_URL environment variable is required but not set" + echo "Please set AF_WS_V2_URL to your WebSocket v2 URL (e.g., wss://your-backend.example.com/ws/v2)" + exit 1 +fi + +# Create inline config script +CONFIG_SCRIPT="" + +# Inject the config script into index.html before the closing head tag +sed -i "s||${CONFIG_SCRIPT}|g" /usr/share/nginx/html/index.html + +echo "Runtime configuration injected:" +echo " AF_BASE_URL: ${AF_BASE_URL}" +echo " AF_GOTRUE_URL: ${AF_GOTRUE_URL}" +echo " AF_WS_V2_URL: ${AF_WS_V2_URL}" + +# Start nginx +exec nginx -g 'daemon off;' \ No newline at end of file diff --git a/index.html b/index.html index cbb2c55e..7df96c47 100644 --- a/index.html +++ b/index.html @@ -69,6 +69,7 @@ rel="stylesheet" > <%- cdnLinks %> + diff --git a/src/components/_shared/gallery-preview/GalleryPreview.tsx b/src/components/_shared/gallery-preview/GalleryPreview.tsx index 142c5be3..f7fdd27c 100644 --- a/src/components/_shared/gallery-preview/GalleryPreview.tsx +++ b/src/components/_shared/gallery-preview/GalleryPreview.tsx @@ -13,6 +13,7 @@ import { ReactComponent as DownloadIcon } from '@/assets/icons/save_as.svg'; import { notify } from '@/components/_shared/notify'; import { copyTextToClipboard } from '@/utils/copy'; import isURL from 'validator/lib/isURL'; +import { getConfigValue } from '@/utils/runtime-config'; export interface GalleryImage { src: string; @@ -101,7 +102,7 @@ function GalleryPreview({ images, open, onClose, previewIndex, workspaceId }: Ga const fileId = images[index].src; - return import.meta.env.AF_BASE_URL + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId; + return getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId; }, [images, index, workspaceId]); if (!open) { diff --git a/src/components/database/components/cell/file-media/PreviewImage.tsx b/src/components/database/components/cell/file-media/PreviewImage.tsx index 4504589e..80a9201b 100644 --- a/src/components/database/components/cell/file-media/PreviewImage.tsx +++ b/src/components/database/components/cell/file-media/PreviewImage.tsx @@ -3,6 +3,7 @@ import isURL from 'validator/lib/isURL'; import { useDatabaseContext } from '@/application/database-yjs'; import { FileMediaCellDataItem } from '@/application/database-yjs/cell.type'; +import { getConfigValue } from '@/utils/runtime-config'; function PreviewImage({ file, onClick }: { file: FileMediaCellDataItem; onClick: () => void }) { const { workspaceId } = useDatabaseContext(); @@ -11,7 +12,7 @@ function PreviewImage({ file, onClick }: { file: FileMediaCellDataItem; onClick: let fileUrl = file.url; if (!isURL(file.url)) { - fileUrl = import.meta.env.AF_BASE_URL + '/api/file_storage/' + workspaceId + '/v1/blob/' + file.url; + fileUrl = getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + file.url; } const url = new URL(fileUrl); diff --git a/src/components/database/components/cell/file-media/UnPreviewFile.tsx b/src/components/database/components/cell/file-media/UnPreviewFile.tsx index f524c95f..a40cb012 100644 --- a/src/components/database/components/cell/file-media/UnPreviewFile.tsx +++ b/src/components/database/components/cell/file-media/UnPreviewFile.tsx @@ -6,6 +6,7 @@ import FileIcon from '@/components/database/components/cell/file-media/FileIcon' import { Button } from '@/components/ui/button'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { openUrl } from '@/utils/url'; +import { getConfigValue } from '@/utils/runtime-config'; function UnPreviewFile({ file }: { file: FileMediaCellDataItem }) { const { workspaceId } = useDatabaseContext(); @@ -25,7 +26,7 @@ function UnPreviewFile({ file }: { file: FileMediaCellDataItem }) { } const fileId = file.url; - const newUrl = import.meta.env.AF_BASE_URL + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId; + const newUrl = getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId; void openUrl(newUrl, '_blank'); }} diff --git a/src/components/database/components/database-row/file-media/FileMediaItem.tsx b/src/components/database/components/database-row/file-media/FileMediaItem.tsx index a0c10e36..f2cc8e81 100644 --- a/src/components/database/components/database-row/file-media/FileMediaItem.tsx +++ b/src/components/database/components/database-row/file-media/FileMediaItem.tsx @@ -8,6 +8,7 @@ import FileMediaMore from '@/components/database/components/cell/file-media/File import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { cn } from '@/lib/utils'; import { openUrl } from '@/utils/url'; +import { getConfigValue } from '@/utils/runtime-config'; function FileMediaItem({ file, @@ -53,7 +54,7 @@ function FileMediaItem({ const fileId = file.url; - return import.meta.env.AF_BASE_URL + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId; + return getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId; }, [file.url, workspaceId]); const [hover, setHover] = useState(false); @@ -70,7 +71,7 @@ function FileMediaItem({ } const fileId = file.url; - const newUrl = import.meta.env.AF_BASE_URL + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId; + const newUrl = getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId; void openUrl(newUrl, '_blank'); } diff --git a/src/components/editor/components/blocks/file/FileBlock.tsx b/src/components/editor/components/blocks/file/FileBlock.tsx index b43a125e..a667ca2f 100644 --- a/src/components/editor/components/blocks/file/FileBlock.tsx +++ b/src/components/editor/components/blocks/file/FileBlock.tsx @@ -16,6 +16,7 @@ import { EditorElementProps, FileNode } from '@/components/editor/editor.type'; import { useEditorContext } from '@/components/editor/EditorContext'; import { notify } from '@/components/_shared/notify'; import { FileHandler } from '@/utils/file'; +import { getConfigValue } from '@/utils/runtime-config'; import { openUrl } from '@/utils/url'; export const FileBlock = memo( @@ -41,7 +42,7 @@ export const FileBlock = memo( const fileId = dataUrl; - return import.meta.env.AF_BASE_URL + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId; + return getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId; }, [dataUrl, workspaceId]); const className = useMemo(() => { diff --git a/src/components/editor/components/blocks/gallery/GalleryBlock.tsx b/src/components/editor/components/blocks/gallery/GalleryBlock.tsx index 32453c4f..f0252fbc 100644 --- a/src/components/editor/components/blocks/gallery/GalleryBlock.tsx +++ b/src/components/editor/components/blocks/gallery/GalleryBlock.tsx @@ -13,6 +13,7 @@ import { useEditorContext } from '@/components/editor/EditorContext'; import { GalleryPreview } from '@/components/_shared/gallery-preview'; import { notify } from '@/components/_shared/notify'; import { copyTextToClipboard } from '@/utils/copy'; +import { getConfigValue } from '@/utils/runtime-config'; const GalleryBlock = memo( forwardRef>(({ node, children, ...attributes }, ref) => { @@ -34,7 +35,7 @@ const GalleryBlock = memo( let imageUrl = image.url; if (!isURL(image.url)) { - imageUrl = import.meta.env.AF_BASE_URL + '/api/file_storage/' + workspaceId + '/v1/blob/' + image.url; + imageUrl = getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + image.url; } const url = new URL(imageUrl); diff --git a/src/components/editor/components/blocks/image/ImageBlock.tsx b/src/components/editor/components/blocks/image/ImageBlock.tsx index 71d23a18..8df293ea 100644 --- a/src/components/editor/components/blocks/image/ImageBlock.tsx +++ b/src/components/editor/components/blocks/image/ImageBlock.tsx @@ -17,6 +17,7 @@ import { FileHandler } from '@/utils/file'; import ImageEmpty from './ImageEmpty'; import ImageRender from './ImageRender'; +import { getConfigValue } from '@/utils/runtime-config'; export const ImageBlock = memo( forwardRef>(({ node, children, ...attributes }, ref) => { @@ -43,7 +44,7 @@ export const ImageBlock = memo( const fileId = dataUrl; - return import.meta.env.AF_BASE_URL + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId; + return getConfigValue('AF_BASE_URL', '') + '/api/file_storage/' + workspaceId + '/v1/blob/' + fileId; }, [dataUrl, workspaceId]); const containerRef = useRef(null); diff --git a/src/components/main/app.hooks.ts b/src/components/main/app.hooks.ts index 7a8db85a..a9a697a7 100644 --- a/src/components/main/app.hooks.ts +++ b/src/components/main/app.hooks.ts @@ -1,16 +1,16 @@ import { AFService, AFServiceConfig } from '@/application/services/services.type'; import { User } from '@/application/types'; +import { getConfigValue } from '@/utils/runtime-config'; import { createContext, useContext } from 'react'; -const baseURL = import.meta.env.AF_BASE_URL || 'https://test.appflowy.cloud'; -const gotrueURL = import.meta.env.AF_GOTRUE_URL || 'https://test.appflowy.cloud/gotrue'; -const wsURL = import.meta.env.AF_WS_URL || 'wss://test.appflowy.cloud/ws/v1'; +const baseURL = getConfigValue('AF_BASE_URL', 'https://test.appflowy.cloud'); +const gotrueURL = getConfigValue('AF_GOTRUE_URL', 'https://test.appflowy.cloud/gotrue'); export const defaultConfig: AFServiceConfig = { cloudConfig: { baseURL, gotrueURL, - wsURL, + wsURL: '', // Legacy field - not used, keeping for backward compatibility }, }; diff --git a/src/components/ws/useAppflowyWebSocket.ts b/src/components/ws/useAppflowyWebSocket.ts index 31a91ce6..407a5d5c 100644 --- a/src/components/ws/useAppflowyWebSocket.ts +++ b/src/components/ws/useAppflowyWebSocket.ts @@ -3,9 +3,10 @@ import { useCallback, useMemo, useState } from 'react'; import useWebSocket from 'react-use-websocket'; import { getTokenParsed } from '@/application/session/token'; +import { getConfigValue } from '@/utils/runtime-config'; import { messages } from '@/proto/messages'; -const wsURL = import.meta.env.AF_WS_V2_URL || 'ws://localhost:8000/ws/v2'; +const wsURL = getConfigValue('AF_WS_V2_URL', 'ws://localhost:8000/ws/v2'); // WebSocket close code enum enum CloseCode { diff --git a/src/utils/runtime-config.ts b/src/utils/runtime-config.ts new file mode 100644 index 00000000..4c84a94f --- /dev/null +++ b/src/utils/runtime-config.ts @@ -0,0 +1,31 @@ +interface RuntimeConfig { + AF_BASE_URL?: string; + AF_GOTRUE_URL?: string; + AF_WS_V2_URL?: string; +} + +declare global { + interface Window { + __APP_CONFIG__?: RuntimeConfig; + } +} + +export function getConfigValue(key: keyof RuntimeConfig, defaultValue: string): string { + // First check runtime config (injected by Docker entrypoint) + if (typeof window !== 'undefined' && window.__APP_CONFIG__) { + const runtimeValue = window.__APP_CONFIG__[key]; + + if (runtimeValue && !runtimeValue.startsWith('${')) { + return runtimeValue; + } + } + + // Fall back to build-time environment variables from Vite + const envValue = import.meta.env[key]; + + if (envValue) { + return envValue; + } + + return defaultValue; +} \ No newline at end of file From c28aae5ca393454ebb2fa82a2a1451efce4780ac Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 18 Aug 2025 17:12:40 +0800 Subject: [PATCH 2/3] chore: update web ci --- .github/workflows/web_ci.yaml | 45 +++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/.github/workflows/web_ci.yaml b/.github/workflows/web_ci.yaml index f0c7b1fb..e5f5363b 100644 --- a/.github/workflows/web_ci.yaml +++ b/.github/workflows/web_ci.yaml @@ -65,3 +65,48 @@ jobs: name: stats.html path: dist/stats.html retention-days: 30 + + docker-runtime-test: + if: github.event.pull_request.draft != true + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Build Docker image (runtime env injection test) + run: | + docker build -t appflowy-web-test:ci -f docker/Dockerfile . + + - name: Run container with injected env vars + run: | + docker run -d --rm --name appflowy-web-test -p 8080:80 \ + -e AF_BASE_URL=https://ci-backend.example.com \ + -e AF_GOTRUE_URL=https://ci-backend.example.com/gotrue \ + -e AF_WS_V2_URL=wss://ci-backend.example.com/ws/v2 \ + appflowy-web-test:ci + + - name: Wait for server to be ready + run: | + for i in $(seq 1 30); do + if curl -fsS http://localhost:8080/ >/dev/null 2>&1; then + echo "Server is up"; break; fi; sleep 1; done + curl -fsS http://localhost:8080/ >/dev/null + + - name: Verify injected runtime config in index.html + run: | + set -e + HTML=$(curl -fsS http://localhost:8080/index.html) + echo "$HTML" | grep -q "window.__APP_CONFIG__" || (echo "Missing __APP_CONFIG__" && exit 1) + echo "$HTML" | grep -q "AF_BASE_URL: 'https://ci-backend.example.com'" || (echo "AF_BASE_URL not injected" && exit 1) + echo "$HTML" | grep -q "AF_GOTRUE_URL: 'https://ci-backend.example.com/gotrue'" || (echo "AF_GOTRUE_URL not injected" && exit 1) + echo "$HTML" | grep -q "AF_WS_V2_URL: 'wss://ci-backend.example.com/ws/v2'" || (echo "AF_WS_V2_URL not injected" && exit 1) + + - name: Show container logs on failure + if: failure() + run: | + docker logs appflowy-web-test || true + + - name: Cleanup container + if: always() + run: | + docker rm -f appflowy-web-test || true From d3d373df2585f33a6a24b7eb366747598f477dd1 Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 18 Aug 2025 19:24:19 +0800 Subject: [PATCH 3/3] chore: update web ci --- .github/workflows/web_ci.yaml | 47 +++++++++++++++++++++++++++++++---- docker/entrypoint.sh | 6 ++--- index.html | 1 - 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/.github/workflows/web_ci.yaml b/.github/workflows/web_ci.yaml index e5f5363b..a4427d1f 100644 --- a/.github/workflows/web_ci.yaml +++ b/.github/workflows/web_ci.yaml @@ -77,6 +77,14 @@ jobs: run: | docker build -t appflowy-web-test:ci -f docker/Dockerfile . + - name: Test container fails without required env vars + run: | + set -e + echo "Testing container fails without environment variables..." + OUTPUT=$(docker run --rm appflowy-web-test:ci 2>&1 || true) + echo "$OUTPUT" | grep -q "ERROR: AF_BASE_URL environment variable is required" || (echo "ERROR: Container should fail without env vars" && exit 1) + echo "✓ Container correctly fails without required env vars" + - name: Run container with injected env vars run: | docker run -d --rm --name appflowy-web-test -p 8080:80 \ @@ -95,11 +103,40 @@ jobs: - name: Verify injected runtime config in index.html run: | set -e - HTML=$(curl -fsS http://localhost:8080/index.html) - echo "$HTML" | grep -q "window.__APP_CONFIG__" || (echo "Missing __APP_CONFIG__" && exit 1) - echo "$HTML" | grep -q "AF_BASE_URL: 'https://ci-backend.example.com'" || (echo "AF_BASE_URL not injected" && exit 1) - echo "$HTML" | grep -q "AF_GOTRUE_URL: 'https://ci-backend.example.com/gotrue'" || (echo "AF_GOTRUE_URL not injected" && exit 1) - echo "$HTML" | grep -q "AF_WS_V2_URL: 'wss://ci-backend.example.com/ws/v2'" || (echo "AF_WS_V2_URL not injected" && exit 1) + echo "Fetching HTML content..." + HTML=$(curl -fsS http://localhost:8080/) + + echo "Checking for __APP_CONFIG__ injection..." + echo "$HTML" | grep -q "window.__APP_CONFIG__" || (echo "ERROR: Missing window.__APP_CONFIG__" && exit 1) + echo "✓ Found window.__APP_CONFIG__" + + echo "Verifying injected values..." + # Note: The config is injected as a single line with format: {AF_BASE_URL:'value',AF_GOTRUE_URL:'value',AF_WS_V2_URL:'value'} + echo "$HTML" | grep -q "AF_BASE_URL:'https://ci-backend.example.com'" || (echo "ERROR: AF_BASE_URL not correctly injected" && exit 1) + echo "✓ AF_BASE_URL correctly injected" + + echo "$HTML" | grep -q "AF_GOTRUE_URL:'https://ci-backend.example.com/gotrue'" || (echo "ERROR: AF_GOTRUE_URL not correctly injected" && exit 1) + echo "✓ AF_GOTRUE_URL correctly injected" + + echo "$HTML" | grep -q "AF_WS_V2_URL:'wss://ci-backend.example.com/ws/v2'" || (echo "ERROR: AF_WS_V2_URL not correctly injected" && exit 1) + echo "✓ AF_WS_V2_URL correctly injected" + + echo "All runtime configuration values verified successfully!" + + - name: Verify config format and structure + run: | + set -e + echo "Extracting and verifying configuration structure..." + + # Extract the config object from HTML + CONFIG=$(curl -fsS http://localhost:8080/ | grep -o "window.__APP_CONFIG__={[^}]*}") + echo "Extracted config: $CONFIG" + + # Verify it's a valid JavaScript object format + echo "$CONFIG" | grep -q "window.__APP_CONFIG__={AF_BASE_URL:'[^']*',AF_GOTRUE_URL:'[^']*',AF_WS_V2_URL:'[^']*'}" || \ + (echo "ERROR: Config format is invalid" && exit 1) + + echo "✓ Configuration format and structure verified" - name: Show container logs on failure if: failure() diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index b0018ad5..510b1696 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -21,10 +21,10 @@ if [ -z "${AF_WS_V2_URL}" ]; then fi # Create inline config script -CONFIG_SCRIPT="" +CONFIG_SCRIPT="" -# Inject the config script into index.html before the closing head tag -sed -i "s||${CONFIG_SCRIPT}|g" /usr/share/nginx/html/index.html +# Inject the config script into index.html right before +sed -i "s||${CONFIG_SCRIPT}|g" /usr/share/nginx/html/index.html echo "Runtime configuration injected:" echo " AF_BASE_URL: ${AF_BASE_URL}" diff --git a/index.html b/index.html index 7df96c47..cbb2c55e 100644 --- a/index.html +++ b/index.html @@ -69,7 +69,6 @@ rel="stylesheet" > <%- cdnLinks %> -