Files
galaxy/client/vite.config.mjs
T
Dannon Baker 143f32f926 Remove underscore from build config and global exposure
Drop the _ : "underscore" injection from the Vite inject plugin (no
files were relying on the implicit global), remove underscore from the
optimizeDeps prebundle list, and stop exposing window._ in libs.js.
Backbone bundles its own underscore internally so it doesn't need the
global.
2026-04-01 08:25:51 -04:00

185 lines
7.4 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 tsconfigPaths from "vite-tsconfig-paths";
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({
// 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: "./",
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",
},
},
}),
tsconfigPaths(), // TypeScript path resolution
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
],
// resolve aliases are handled by galaxyLegacyPlugin
css: {
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,
rollupOptions: {
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: !!process.env.CHANGE_ORIGIN,
secure: process.env.CHANGE_ORIGIN ? false : true,
},
},
cors: true,
hmr: {
protocol: "ws",
host: "localhost",
},
},
worker: {
format: "es",
},
optimizeDeps: {
// Use esbuild plugin to fix D3 v3's IIFE `this` binding during pre-bundling
esbuildOptions: {
plugins: [
{
name: "d3v3-compat-esbuild",
setup(build) {
build.onLoad({ filter: /node_modules\/d3v3\/d3\.js$/ }, async (args) => {
const fs = await import("node:fs");
let contents = fs.readFileSync(args.path, "utf8");
// D3 v3 is: !function() { ... }();
// Change to: !function() { ... }.call(window);
contents = contents.replace(
/\}(\s*)\(\s*\)\s*;?\s*$/,
"}.call(typeof window !== 'undefined' ? window : globalThis);",
);
return { contents, loader: "js" };
});
},
},
],
},
},
});