mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-08-29 02:26:59 +08:00
5cbd14e8f0
Adds packages/ui/ as a second workspace member alongside api-client -- private, source-only, no library build. Empty src/index.ts barrel; components and composables move in next. Wires galaxy-ui into the main client as a workspace:* dep and as an unconditional resolve.alias in vite.config.mjs (serve and build). The api-client alias stays serve-only because it has a real dist/ build and production consumes that via package.json exports; galaxy-ui is internal-only so we skip the build step entirely and let the main client's @vitejs/plugin-vue2 handle the Vue 2 SFCs from source in both dev and prod. client/packages/README.md now lists both packages and calls out the "flips to a library build + publish when the interface stabilizes on Vue 3" intent.
229 lines
9.9 KiB
JavaScript
229 lines
9.9 KiB
JavaScript
import { readFileSync } from "node:fs";
|
|
import { dirname, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
import ViteYaml from "@modyfi/vite-plugin-yaml";
|
|
import inject from "@rollup/plugin-inject";
|
|
import vue from "@vitejs/plugin-vue2";
|
|
import { defineConfig } from "vite";
|
|
|
|
import { buildMetadataPlugin } from "./vite-plugin-build-metadata.js";
|
|
import { galaxyDevServerPlugin } from "./vite-plugin-galaxy-dev-server.js";
|
|
import { galaxyLegacyPlugin } from "./vite-plugin-galaxy-legacy.js";
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const packageJson = JSON.parse(readFileSync(resolve(__dirname, "package.json"), "utf-8"));
|
|
|
|
/**
|
|
* Plugin to fix D3 v3 ES module compatibility
|
|
* D3 v3 is an IIFE that expects `this` to be `window` at the module level.
|
|
* In ES modules, `this` is `undefined`. This plugin wraps the code to
|
|
* execute with the correct global context.
|
|
*/
|
|
function d3v3CompatPlugin() {
|
|
return {
|
|
name: "d3v3-compat",
|
|
transform(code, id) {
|
|
// Only transform the d3v3 main file
|
|
if (
|
|
(id.includes("node_modules/d3v3/d3.js") || id.includes("node_modules\\d3v3\\d3.js")) &&
|
|
code.startsWith("!function()")
|
|
) {
|
|
// The D3 v3 code is: !function() { ... }();
|
|
// We need to change it to: !function() { ... }.call(window);
|
|
// This ensures `this` inside the IIFE refers to `window`
|
|
const transformed = code.replace(
|
|
/\}(\s*)\(\s*\)\s*;?\s*$/,
|
|
"}.call(typeof window !== 'undefined' ? window : globalThis);",
|
|
);
|
|
return {
|
|
code: transformed,
|
|
map: null,
|
|
};
|
|
}
|
|
return null;
|
|
},
|
|
};
|
|
}
|
|
|
|
export default defineConfig(({ command }) => ({
|
|
// Use relative base so CSS asset references work with any proxy prefix.
|
|
// The HTML script tags use url_for() which handles the prefix correctly.
|
|
base: "./",
|
|
resolve: {
|
|
tsconfigPaths: true,
|
|
alias: {
|
|
// galaxy-ui is internal-only (no library build) and always
|
|
// resolved from source -- the main client consumes the .vue
|
|
// files directly through @vitejs/plugin-vue2.
|
|
"@galaxyproject/galaxy-ui": resolve(__dirname, "packages/ui/src/index.ts"),
|
|
// galaxy-api-client has a real tsup dist/ build and production
|
|
// uses that via package.json exports. During `vite serve` we
|
|
// resolve to source so edits trigger HMR without a rebuild.
|
|
...(command === "serve"
|
|
? { "@galaxyproject/galaxy-api-client": resolve(__dirname, "packages/api-client/src/index.ts") }
|
|
: {}),
|
|
},
|
|
},
|
|
define: {
|
|
// Make jQuery available globally for plugins and legacy code
|
|
global: "globalThis",
|
|
// Polyfill process.env for Node.js modules (like util) that reference it
|
|
"process.env": JSON.stringify({}),
|
|
// Define build system for runtime checks
|
|
__GALAXY_BUILD_SYSTEM__: JSON.stringify("vite"),
|
|
// Define build timestamp
|
|
__buildTimestamp__: JSON.stringify(new Date().toISOString()),
|
|
// Define license from package.json
|
|
__license__: JSON.stringify(packageJson.license),
|
|
},
|
|
plugins: [
|
|
vue({
|
|
template: {
|
|
compilerOptions: {
|
|
// Preserve whitespace to match Webpack's vue-loader default behavior
|
|
whitespace: "preserve",
|
|
},
|
|
},
|
|
}),
|
|
ViteYaml(), // YAML file support
|
|
galaxyLegacyPlugin(), // Handle legacy module resolution
|
|
buildMetadataPlugin(), // Generate build metadata (replaces DumpMetaPlugin)
|
|
d3v3CompatPlugin(), // Fix D3 v3 ES module compatibility
|
|
// Inject imports for Buffer
|
|
// jQuery is set up as window.$ and window.jQuery by libs.bundled.js
|
|
// Note: We don't inject jQuery here to avoid circular dependencies with code splitting
|
|
inject({
|
|
include: ["**/*.js", "**/*.ts", "**/*.vue"],
|
|
exclude: ["**/node_modules/**"],
|
|
Buffer: ["buffer", "Buffer"],
|
|
}),
|
|
galaxyDevServerPlugin(), // Transform proxied Galaxy HTML for HMR support
|
|
],
|
|
// Note: resolve.extensions are set by galaxyLegacyPlugin
|
|
css: {
|
|
lightningcss: {
|
|
errorRecovery: true,
|
|
},
|
|
preprocessorOptions: {
|
|
scss: {
|
|
quietDeps: true,
|
|
silenceDeprecations: ["import", "color-functions", "global-builtin"],
|
|
includePaths: ["src/style", "src/style/scss", "node_modules"],
|
|
},
|
|
},
|
|
},
|
|
build: {
|
|
outDir: "dist",
|
|
emptyOutDir: true,
|
|
// Generate manifest.json for production
|
|
manifest: true,
|
|
// Disable CSS code splitting - combine all CSS into one file
|
|
cssCodeSplit: false,
|
|
// Generate sourcemaps when GXY_BUILD_SOURCEMAPS is set
|
|
sourcemap: !!process.env.GXY_BUILD_SOURCEMAPS,
|
|
rolldownOptions: {
|
|
input: {
|
|
// Entry points that will be referenced in templates
|
|
// libs must be loaded first - it exposes globals (jQuery, bundleEntries, config)
|
|
libs: resolve(__dirname, "src/entry/libs.js"),
|
|
analysis: resolve(__dirname, "src/entry/analysis/index.ts"),
|
|
generic: resolve(__dirname, "src/entry/generic.js"),
|
|
},
|
|
output: {
|
|
entryFileNames: "[name].bundled.js",
|
|
chunkFileNames: "[name]-[hash].js",
|
|
// CSS should be named 'base.css' to match what templates expect
|
|
assetFileNames: (assetInfo) => {
|
|
if (assetInfo.name && assetInfo.name.endsWith(".css")) {
|
|
return "base.css";
|
|
}
|
|
return "[name]-[hash].[ext]";
|
|
},
|
|
manualChunks: (id) => {
|
|
// Put jQuery in its own chunk - jquery-migrate is imported dynamically
|
|
if (id.includes("node_modules/jquery/") && !id.includes("jquery-migrate")) {
|
|
return "jquery-core";
|
|
}
|
|
// Keep app/* files together to avoid circular dependency issues
|
|
// (getGalaxyInstance is re-exported through app/index.js)
|
|
if (id.includes("/src/app/")) {
|
|
return "galaxy-app";
|
|
}
|
|
},
|
|
},
|
|
},
|
|
},
|
|
server: {
|
|
port: process.env.VITE_PORT || 5173,
|
|
host: "0.0.0.0",
|
|
proxy: {
|
|
// Proxy everything except Vite's own routes to Galaxy backend
|
|
"^/(?!(@|src/|node_modules/|__vite))": {
|
|
target: process.env.GALAXY_URL || "http://127.0.0.1:8080",
|
|
changeOrigin: true,
|
|
secure: false,
|
|
cookieDomainRewrite: "",
|
|
configure: (proxy) => {
|
|
proxy.on("proxyRes", (proxyRes, req) => {
|
|
// Strip Secure flag and fix SameSite from upstream HTTPS cookies so
|
|
// they are accepted by the browser on http://localhost.
|
|
const cookies = proxyRes.headers["set-cookie"];
|
|
if (cookies) {
|
|
proxyRes.headers["set-cookie"] = cookies.map((cookie) =>
|
|
cookie.replace(/;\s*Secure/gi, "").replace(/;\s*SameSite=None/gi, "; SameSite=Lax"),
|
|
);
|
|
}
|
|
// Rewrite Location header to use the dev server origin instead of
|
|
// the Galaxy backend. With changeOrigin=true, Galaxy sees the backend
|
|
// Host and generates absolute URLs (e.g. in TUS upload responses).
|
|
// Without this rewrite, the browser tries to access the backend directly
|
|
// which causes CORS failures.
|
|
const location = proxyRes.headers["location"];
|
|
if (location) {
|
|
const targetUrl = new URL(process.env.GALAXY_URL || "http://127.0.0.1:8080");
|
|
const locationUrl = new URL(location, targetUrl);
|
|
const fallbackDevHost = req.headers.host || `localhost:${process.env.VITE_PORT || 5173}`;
|
|
const devOrigin = req.headers.origin || `http://${fallbackDevHost}`;
|
|
|
|
// Only rewrite locations generated for the Galaxy backend.
|
|
if (locationUrl.origin === targetUrl.origin) {
|
|
proxyRes.headers["location"] =
|
|
`${devOrigin}${locationUrl.pathname}${locationUrl.search}${locationUrl.hash}`;
|
|
}
|
|
}
|
|
});
|
|
},
|
|
},
|
|
},
|
|
cors: true,
|
|
hmr: {
|
|
protocol: "ws",
|
|
host: "localhost",
|
|
},
|
|
},
|
|
worker: {
|
|
format: "es",
|
|
},
|
|
optimizeDeps: {
|
|
// Use Rolldown plugin to fix D3 v3's IIFE `this` binding during pre-bundling
|
|
rolldownOptions: {
|
|
plugins: [
|
|
{
|
|
name: "d3v3-compat-rolldown",
|
|
load(id) {
|
|
if (id.includes("node_modules/d3v3/d3.js") || id.includes("node_modules\\d3v3\\d3.js")) {
|
|
let contents = readFileSync(id, "utf8");
|
|
contents = contents.replace(
|
|
/\}(\s*)\(\s*\)\s*;?\s*$/,
|
|
"}.call(typeof window !== 'undefined' ? window : globalThis);",
|
|
);
|
|
return contents;
|
|
}
|
|
},
|
|
},
|
|
],
|
|
},
|
|
},
|
|
}));
|