[GH-ISSUE #11559] feat: base_path support #31801

Closed
opened 2026-04-25 05:42:46 -05:00 by GiteaMirror · 5 comments
Owner

Originally created by @marius-gherghief on GitHub (Mar 11, 2025).
Original GitHub issue: https://github.com/open-webui/open-webui/issues/11559

Check Existing Issues

  • I have searched the existing issues and discussions.

Problem Description

If you need to be able to host the open_webui UI & backend at https://example.com/my_ai_portal, I want to publish this way a short script that will add this enhancement.

Mainly the script finds and replaces all the code that chnages the relative path from '/' to 'my_ai_portal', or any path you desire. After running this script from the base of the repository, you just need to rebuild the UI and that is all.

Desired Solution you'd like

The attached script is executed as follows:

  • dry run:
    node ./prepare_openwebui.js ./open-webui/ --dry-run --path my_ai_portal
  • replacement mode:
    node ./prepare_openwebui.js ./open-webui/ --path my_ai_portal

Note that the current dir for the script execution is the parent dir of the cloned repository.

prepare_openwebui.js:

#!/usr/bin/env node

import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import ignore from "ignore";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const args = process.argv.slice(2);
const TARGET_DIR = args.find((arg) => !arg.startsWith("--") && !arg.startsWith("--path")) || ".";
const DRY_RUN = args.includes("--dry-run");
const PATH_ARG_INDEX = args.findIndex((arg) => arg === "--path");
const BASE_PATH = PATH_ARG_INDEX !== -1 ? args[PATH_ARG_INDEX + 1] : "my_ai"; // Default: "my_ai"

if (!TARGET_DIR) {
  console.error("❌ Error: Please provide a folder to scan.");
  console.error("Usage: node updateFiles.js /path/to/folder [--path 'custom_path'] [--dry-run]");
  process.exit(1);
}

// ✅ Load `.gitignore` rules (if available)
const gitignorePath = path.join(TARGET_DIR, ".gitignore");
const ig = ignore();
if (fs.existsSync(gitignorePath)) {
  const gitignoreContent = fs.readFileSync(gitignorePath, "utf8");
  ig.add(gitignoreContent.split("\n"));
}

// ✅ General Ignore Rules
const GENERAL_IGNORES = [
  ".git",
  ".github",
  "*.jpg",
  "*.gif",
  "*.png",
  "*.ttf",
  "cypress",
  "**/testdata",
  "**/swagger-ui",
  "backend/open_webui/test",
];

// ✅ Extend ignore set
ig.add(GENERAL_IGNORES);

const RULES = [
  { pattern: `goto\\((['"\`])\\/(?!${BASE_PATH})`, replacement: `goto($1/${BASE_PATH}/` },
  { pattern: `href\\s*=\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `href=$1/${BASE_PATH}/` },
  { pattern: `href\\s*=\\s*{(['"\`])\\/(?!${BASE_PATH})`, replacement: `href={$1/${BASE_PATH}/` },
  { pattern: `app\\.mount\\(\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `app.mount($1/${BASE_PATH}/` },
  { pattern: `router,\\s*prefix\\s*=\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `router, prefix=$1/${BASE_PATH}/` },
  { pattern: `@app\\.(get|post|put)\\(\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `@app.$1($2/${BASE_PATH}/` },
  { pattern: `_url\\s*=\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `_url=$1/${BASE_PATH}/` },
  { pattern: `_url\\s*:\\s*str\\s*=\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `_url:str=$1/${BASE_PATH}/` },
  { pattern: `return\\s*(['"\`])\\/(?!${BASE_PATH}|['"\`].join)`, replacement: `return $1/${BASE_PATH}/` },
  { pattern: `socketio_path\\s*=\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `socketio_path=$1/${BASE_PATH}/` },
  { pattern: `src\\s*=\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `src=$1/${BASE_PATH}/` },
  { pattern: `src\\s*=\\s*{(['"\`])\\/(?!${BASE_PATH})`, replacement: `src={$1/${BASE_PATH}/` },
  { pattern: `_url\\s*\\?\\?\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `_url ?? $1/${BASE_PATH}/` },
  { pattern: `Url\\s*=\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `Url=$1/${BASE_PATH}/` },
  {
    pattern: `:\\s*(['"\`])\\/(?!${BASE_PATH}|ollama|my-command)`,
    replacement: `: $1/${BASE_PATH}/`,
    ignore: ["backend/open_webui/utils/middleware.py", "src/lib/apis/prompts/index.ts"],
  },
  {
    pattern: `==\\s*(['"\`])\\/(?!${BASE_PATH}|ollama|my-command)`,
    replacement: `== $1/${BASE_PATH}/`,
    ignore: [
      "src/lib/components/chat/MessageInput/Commands.svelte",
      "src/lib/components/workspace/Prompts/PromptEditor.svelte",
      "src/lib/components/workspace/Prompts.svelte",
      "src/routes/\\(app\\)/\\+layout.svelte",
      "src/lib/apis/prompts/index.ts",
      "backend/open_webui/config.py",
    ],
  },
  {
    pattern: `\\(\\s*dev\\s*\\?\\s*\`http:\\/\\/\\$\\{WEBUI_HOSTNAME\\}\`\\s:\\s\`\`\\)\\s:\\s\`\``,
    replacement: `(dev ? \`http://\${WEBUI_HOSTNAME}/${BASE_PATH}\` : \`/${BASE_PATH}\`) : \`/${BASE_PATH}\``,
  },
  {
    pattern: `\\(\\s*dev\\s*\\?\\s*\`http:\\/\\/\\$\\{WEBUI_HOSTNAME\\}(?!\\/${BASE_PATH})`,
    replacement: `(dev ? \`http://\${WEBUI_HOSTNAME}/${BASE_PATH}`,
  },
  {
    pattern: `\\(\\s*dev\\s*\\?\\s*\`http:\\/\\/\\$\\{WEBUI_HOSTNAME\\}\\/${BASE_PATH}\`\\s*:\\s*\`\\/(?!${BASE_PATH})\``,
    replacement: `(dev ? \`http://\${WEBUI_HOSTNAME}/${BASE_PATH}\` : \`/${BASE_PATH}\``,
  },
  { pattern: `{\\[\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `{[$1/${BASE_PATH}/` },
  {
    pattern: `pathname\\.includes\\(\\s*(['"\`])\\/(?!${BASE_PATH})`,
    replacement: `pathname.includes($1/${BASE_PATH}/`,
  },
  { pattern: `redirect'\\)\\s*\\|\\|\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `redirect') || $1/${BASE_PATH}/` },
  { pattern: `path:\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `path: $1/${BASE_PATH}/` },
].map(({ pattern, replacement, ignore }) => ({
  regex: new RegExp(pattern, "g"),
  replacement,
  ignore,
}));

/**
 * Recursively processes all files in a directory
 * @param {string} dir - The directory path to scan
 */
function updateFiles(dir) {
  fs.readdirSync(dir).forEach((file) => {
    const fullPath = path.join(dir, file);

    // ✅ Skip ignored files
    if (ig.ignores(path.relative(TARGET_DIR, fullPath))) return;

    if (fs.statSync(fullPath).isDirectory()) {
      updateFiles(fullPath); // Recursively process subdirectories
    } else {
      processFile(fullPath);
    }
  });
}

/**
 * Processes a file and applies regex replacements
 * @param {string} filePath - The file to modify
 */
function processFile(filePath) {
  try {
    let content = fs.readFileSync(filePath, "utf8");
    let updatedContent = content;
    let changes = [];

    RULES.forEach(({ regex, replacement, ignore }, ruleIndex) => {
      if (
        ignore &&
        ignore.some((pattern) => new RegExp(pattern.replace(/\./g, "\\.").replace(/\*/g, ".*")).test(filePath))
      ) {
        return; // Skip files matching ignore pattern
      }

      let regexWithGlobal = new RegExp(regex, regex.flags.includes("g") ? regex.flags : regex.flags + "g"); // Ensure global flag
      let matchFound = false;

      updatedContent = updatedContent.replace(regexWithGlobal, (match, ...groups) => {
        matchFound = true;

        // ✅ Get line number by counting new lines before match index
        let lineNumber = content.substring(0, content.indexOf(match)).split("\n").length;

        // ✅ Get actual replacement
        let actualReplacement = replacement.replace(/\$(\d+)/g, (_, num) => groups[num - 1] || "");

        if (match !== actualReplacement) {
          changes.push({
            ruleNumber: ruleIndex + 1,
            line: lineNumber,
            match: match.trim(),
            actualReplacement: actualReplacement.trim(),
          });
        }

        return actualReplacement; // ✅ Properly return the updated content
      });

      if (!matchFound) {
        regexWithGlobal.lastIndex = 0; // Reset regex state
      }
    });

    if (changes.length > 0) {
      if (DRY_RUN) {
        console.log(`🔍 Changes in: ${filePath}`);
        changes.forEach((change) => {
          console.log(`   - Rule #${change.ruleNumber} (Line ${change.line}):`);
          console.log(`     ❌ Before: ${change.match}`);
          console.log(`     ✅ After : ${change.actualReplacement}`);
        });
      } else {
        fs.writeFileSync(filePath, updatedContent, "utf8"); // ✅ Actually write the modified file
        console.log(`✅ Updated: ${filePath}`);
      }
    }
  } catch (error) {
    console.error(`❌ Error processing ${filePath}:`, error.message);
  }
}

function updateSvelteConfig() {
  const configPath = path.join(TARGET_DIR, "svelte.config.js");

  if (!fs.existsSync(configPath)) {
    console.warn("⚠️ svelte.config.js not found. Skipping.");
    return;
  }

  try {
    let content = fs.readFileSync(configPath, "utf8");

    // ✅ Check if paths.base already exists
    if (content.includes(`paths: { base: '/${BASE_PATH}' }`)) {
      console.log("✅ paths.base already exists in svelte.config.js. Skipping.");
      return;
    }

    // ✅ Flexible regex to match the adapter block dynamically (ignoring whitespace and quotes)
    const adapterRegex =
      /adapter:\s*adapter\(\s*{\s*pages:\s*['"`]build['"`],\s*assets:\s*['"`]build['"`],\s*fallback:\s*['"`]index\.html['"`]\s*}\s*\)/;

    const newConfigText = `,
          paths: {
              base: '/${BASE_PATH}'
          }`;

    // ✅ Replace using regex
    if (adapterRegex.test(content)) {
      content = content.replace(adapterRegex, (match) => match + newConfigText);
      fs.writeFileSync(configPath, content, "utf8");
      console.log(`✅ Updated: ${configPath}`);
    } else {
      console.warn("⚠️ Could not find the adapter config in svelte.config.js. No changes made.");
    }
  } catch (error) {
    console.error(`❌ Error updating svelte.config.js:`, error.message);
  }
}

// ✅ Run the script
console.log(`🔍 Scanning: ${TARGET_DIR}`);
updateFiles(TARGET_DIR);

if (!DRY_RUN) {
  updateSvelteConfig();
}

console.log(`✅ ${DRY_RUN ? "Dry-run complete (No files modified)" : "Update complete!"}`);

Alternatives Considered

No response

Additional Context

No response

Originally created by @marius-gherghief on GitHub (Mar 11, 2025). Original GitHub issue: https://github.com/open-webui/open-webui/issues/11559 ### Check Existing Issues - [x] I have searched the existing issues and discussions. ### Problem Description If you need to be able to host the open_webui UI & backend at https://example.com/my_ai_portal, I want to publish this way a short script that will add this enhancement. Mainly the script finds and replaces all the code that chnages the relative path from '/' to 'my_ai_portal', or any path you desire. After running this script from the base of the repository, you just need to rebuild the UI and that is all. ### Desired Solution you'd like The attached script is executed as follows: * dry run: `node ./prepare_openwebui.js ./open-webui/ --dry-run --path my_ai_portal` * replacement mode: `node ./prepare_openwebui.js ./open-webui/ --path my_ai_portal` Note that the current dir for the script execution is the parent dir of the cloned repository. **prepare_openwebui.js**: ```js #!/usr/bin/env node import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; import ignore from "ignore"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const args = process.argv.slice(2); const TARGET_DIR = args.find((arg) => !arg.startsWith("--") && !arg.startsWith("--path")) || "."; const DRY_RUN = args.includes("--dry-run"); const PATH_ARG_INDEX = args.findIndex((arg) => arg === "--path"); const BASE_PATH = PATH_ARG_INDEX !== -1 ? args[PATH_ARG_INDEX + 1] : "my_ai"; // Default: "my_ai" if (!TARGET_DIR) { console.error("❌ Error: Please provide a folder to scan."); console.error("Usage: node updateFiles.js /path/to/folder [--path 'custom_path'] [--dry-run]"); process.exit(1); } // ✅ Load `.gitignore` rules (if available) const gitignorePath = path.join(TARGET_DIR, ".gitignore"); const ig = ignore(); if (fs.existsSync(gitignorePath)) { const gitignoreContent = fs.readFileSync(gitignorePath, "utf8"); ig.add(gitignoreContent.split("\n")); } // ✅ General Ignore Rules const GENERAL_IGNORES = [ ".git", ".github", "*.jpg", "*.gif", "*.png", "*.ttf", "cypress", "**/testdata", "**/swagger-ui", "backend/open_webui/test", ]; // ✅ Extend ignore set ig.add(GENERAL_IGNORES); const RULES = [ { pattern: `goto\\((['"\`])\\/(?!${BASE_PATH})`, replacement: `goto($1/${BASE_PATH}/` }, { pattern: `href\\s*=\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `href=$1/${BASE_PATH}/` }, { pattern: `href\\s*=\\s*{(['"\`])\\/(?!${BASE_PATH})`, replacement: `href={$1/${BASE_PATH}/` }, { pattern: `app\\.mount\\(\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `app.mount($1/${BASE_PATH}/` }, { pattern: `router,\\s*prefix\\s*=\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `router, prefix=$1/${BASE_PATH}/` }, { pattern: `@app\\.(get|post|put)\\(\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `@app.$1($2/${BASE_PATH}/` }, { pattern: `_url\\s*=\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `_url=$1/${BASE_PATH}/` }, { pattern: `_url\\s*:\\s*str\\s*=\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `_url:str=$1/${BASE_PATH}/` }, { pattern: `return\\s*(['"\`])\\/(?!${BASE_PATH}|['"\`].join)`, replacement: `return $1/${BASE_PATH}/` }, { pattern: `socketio_path\\s*=\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `socketio_path=$1/${BASE_PATH}/` }, { pattern: `src\\s*=\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `src=$1/${BASE_PATH}/` }, { pattern: `src\\s*=\\s*{(['"\`])\\/(?!${BASE_PATH})`, replacement: `src={$1/${BASE_PATH}/` }, { pattern: `_url\\s*\\?\\?\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `_url ?? $1/${BASE_PATH}/` }, { pattern: `Url\\s*=\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `Url=$1/${BASE_PATH}/` }, { pattern: `:\\s*(['"\`])\\/(?!${BASE_PATH}|ollama|my-command)`, replacement: `: $1/${BASE_PATH}/`, ignore: ["backend/open_webui/utils/middleware.py", "src/lib/apis/prompts/index.ts"], }, { pattern: `==\\s*(['"\`])\\/(?!${BASE_PATH}|ollama|my-command)`, replacement: `== $1/${BASE_PATH}/`, ignore: [ "src/lib/components/chat/MessageInput/Commands.svelte", "src/lib/components/workspace/Prompts/PromptEditor.svelte", "src/lib/components/workspace/Prompts.svelte", "src/routes/\\(app\\)/\\+layout.svelte", "src/lib/apis/prompts/index.ts", "backend/open_webui/config.py", ], }, { pattern: `\\(\\s*dev\\s*\\?\\s*\`http:\\/\\/\\$\\{WEBUI_HOSTNAME\\}\`\\s:\\s\`\`\\)\\s:\\s\`\``, replacement: `(dev ? \`http://\${WEBUI_HOSTNAME}/${BASE_PATH}\` : \`/${BASE_PATH}\`) : \`/${BASE_PATH}\``, }, { pattern: `\\(\\s*dev\\s*\\?\\s*\`http:\\/\\/\\$\\{WEBUI_HOSTNAME\\}(?!\\/${BASE_PATH})`, replacement: `(dev ? \`http://\${WEBUI_HOSTNAME}/${BASE_PATH}`, }, { pattern: `\\(\\s*dev\\s*\\?\\s*\`http:\\/\\/\\$\\{WEBUI_HOSTNAME\\}\\/${BASE_PATH}\`\\s*:\\s*\`\\/(?!${BASE_PATH})\``, replacement: `(dev ? \`http://\${WEBUI_HOSTNAME}/${BASE_PATH}\` : \`/${BASE_PATH}\``, }, { pattern: `{\\[\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `{[$1/${BASE_PATH}/` }, { pattern: `pathname\\.includes\\(\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `pathname.includes($1/${BASE_PATH}/`, }, { pattern: `redirect'\\)\\s*\\|\\|\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `redirect') || $1/${BASE_PATH}/` }, { pattern: `path:\\s*(['"\`])\\/(?!${BASE_PATH})`, replacement: `path: $1/${BASE_PATH}/` }, ].map(({ pattern, replacement, ignore }) => ({ regex: new RegExp(pattern, "g"), replacement, ignore, })); /** * Recursively processes all files in a directory * @param {string} dir - The directory path to scan */ function updateFiles(dir) { fs.readdirSync(dir).forEach((file) => { const fullPath = path.join(dir, file); // ✅ Skip ignored files if (ig.ignores(path.relative(TARGET_DIR, fullPath))) return; if (fs.statSync(fullPath).isDirectory()) { updateFiles(fullPath); // Recursively process subdirectories } else { processFile(fullPath); } }); } /** * Processes a file and applies regex replacements * @param {string} filePath - The file to modify */ function processFile(filePath) { try { let content = fs.readFileSync(filePath, "utf8"); let updatedContent = content; let changes = []; RULES.forEach(({ regex, replacement, ignore }, ruleIndex) => { if ( ignore && ignore.some((pattern) => new RegExp(pattern.replace(/\./g, "\\.").replace(/\*/g, ".*")).test(filePath)) ) { return; // Skip files matching ignore pattern } let regexWithGlobal = new RegExp(regex, regex.flags.includes("g") ? regex.flags : regex.flags + "g"); // Ensure global flag let matchFound = false; updatedContent = updatedContent.replace(regexWithGlobal, (match, ...groups) => { matchFound = true; // ✅ Get line number by counting new lines before match index let lineNumber = content.substring(0, content.indexOf(match)).split("\n").length; // ✅ Get actual replacement let actualReplacement = replacement.replace(/\$(\d+)/g, (_, num) => groups[num - 1] || ""); if (match !== actualReplacement) { changes.push({ ruleNumber: ruleIndex + 1, line: lineNumber, match: match.trim(), actualReplacement: actualReplacement.trim(), }); } return actualReplacement; // ✅ Properly return the updated content }); if (!matchFound) { regexWithGlobal.lastIndex = 0; // Reset regex state } }); if (changes.length > 0) { if (DRY_RUN) { console.log(`🔍 Changes in: ${filePath}`); changes.forEach((change) => { console.log(` - Rule #${change.ruleNumber} (Line ${change.line}):`); console.log(` ❌ Before: ${change.match}`); console.log(` ✅ After : ${change.actualReplacement}`); }); } else { fs.writeFileSync(filePath, updatedContent, "utf8"); // ✅ Actually write the modified file console.log(`✅ Updated: ${filePath}`); } } } catch (error) { console.error(`❌ Error processing ${filePath}:`, error.message); } } function updateSvelteConfig() { const configPath = path.join(TARGET_DIR, "svelte.config.js"); if (!fs.existsSync(configPath)) { console.warn("⚠️ svelte.config.js not found. Skipping."); return; } try { let content = fs.readFileSync(configPath, "utf8"); // ✅ Check if paths.base already exists if (content.includes(`paths: { base: '/${BASE_PATH}' }`)) { console.log("✅ paths.base already exists in svelte.config.js. Skipping."); return; } // ✅ Flexible regex to match the adapter block dynamically (ignoring whitespace and quotes) const adapterRegex = /adapter:\s*adapter\(\s*{\s*pages:\s*['"`]build['"`],\s*assets:\s*['"`]build['"`],\s*fallback:\s*['"`]index\.html['"`]\s*}\s*\)/; const newConfigText = `, paths: { base: '/${BASE_PATH}' }`; // ✅ Replace using regex if (adapterRegex.test(content)) { content = content.replace(adapterRegex, (match) => match + newConfigText); fs.writeFileSync(configPath, content, "utf8"); console.log(`✅ Updated: ${configPath}`); } else { console.warn("⚠️ Could not find the adapter config in svelte.config.js. No changes made."); } } catch (error) { console.error(`❌ Error updating svelte.config.js:`, error.message); } } // ✅ Run the script console.log(`🔍 Scanning: ${TARGET_DIR}`); updateFiles(TARGET_DIR); if (!DRY_RUN) { updateSvelteConfig(); } console.log(`✅ ${DRY_RUN ? "Dry-run complete (No files modified)" : "Update complete!"}`); ``` ### Alternatives Considered _No response_ ### Additional Context _No response_
Author
Owner

@marius-gherghief commented on GitHub (Mar 11, 2025):

The above script was tested on version 0.5.20

<!-- gh-comment-id:2715651100 --> @marius-gherghief commented on GitHub (Mar 11, 2025): The above script was tested on version 0.5.20
Author
Owner

@tjbck commented on GitHub (Mar 11, 2025):

Please check for previous discussions, TL;DR we currently do not have the capacity to handle unnecessary additional complexity.

<!-- gh-comment-id:2715675172 --> @tjbck commented on GitHub (Mar 11, 2025): Please check for previous discussions, TL;DR we currently do not have the capacity to handle unnecessary additional complexity.
Author
Owner

@marius-gherghief commented on GitHub (Mar 11, 2025):

I think this can help you or any community member that needs it. I know it was discussed, but this script if sully functional and serves mainly the case when the app is published under a reverse proxy sub path.

At the same time, this can help any contributing developer to identify every place a new env var needs to be implemented.

<!-- gh-comment-id:2715682951 --> @marius-gherghief commented on GitHub (Mar 11, 2025): I think this can help you or any community member that needs it. I know it was discussed, but this script if sully functional and serves mainly the case when the app is published under a reverse proxy sub path. At the same time, this can help any contributing developer to identify every place a new env var needs to be implemented.
Author
Owner

@chenkang1 commented on GitHub (Mar 13, 2025):

can cthat script can run in docker container??

<!-- gh-comment-id:2720285010 --> @chenkang1 commented on GitHub (Mar 13, 2025): can cthat script can run in docker container??
Author
Owner

@marius-gherghief commented on GitHub (Mar 13, 2025):

no it can;t as it runs on top of the svelte scripts that will be used to recompile the webui.
What you can do is just clone the repo and change the standard Dockerfile to include before the build step, the script execution.

<!-- gh-comment-id:2721429666 --> @marius-gherghief commented on GitHub (Mar 13, 2025): no it can;t as it runs on top of the svelte scripts that will be used to recompile the webui. What you can do is just clone the repo and change the standard Dockerfile to include before the build step, the script execution.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#31801