Skip to content

Replace Webpack with Vite for client build#21369

Merged
mvdbeek merged 59 commits intogalaxyproject:devfrom
dannon:vite-reorganized
Dec 3, 2025
Merged

Replace Webpack with Vite for client build#21369
mvdbeek merged 59 commits intogalaxyproject:devfrom
dannon:vite-reorganized

Conversation

@dannon
Copy link
Copy Markdown
Member

@dannon dannon commented Nov 30, 2025

Following up on the Vitest migration, this swaps out Webpack for Vite as the
client bundler. Since Vitest already uses Vite under the hood, this gets us on
a single modern toolchain for both building and testing.

The branch is a cleaned up rebase of previous Vite work - same functionality,
just reorganized into cleaner commits. Webpack and Babel dependencies are
removed (~30 packages), build time is around 35 seconds, and all the output
files match what templates expect.

Builds on #21194 and #21348

Will probably need some followup, but the dev server setup ended up being
straightforward - no crazy workarounds needed, and it should be easy to build
on going forward.

How to test the changes?

(Select all options that apply)

  • I've included appropriate automated tests.
  • This is a refactoring of components with existing test coverage.
  • Instructions for manual testing are as follows:
    1. [add testing steps and prerequisites here if you didn't write automated tests covering all your changes]

License

  • I agree to license these and all my past contributions to the core galaxy codebase under the MIT license.

* This allows `GALAXY_URL=https://usegalaxy.org yarn develop` to work with
* full HMR support without any server-side changes.
*/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well that is fun - very clever!

Copy link
Copy Markdown
Member Author

@dannon dannon Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So much cleaner (from the usability side) than the previous env var variant toggling the extra stuff server-side in the mako :)

@dannon
Copy link
Copy Markdown
Member Author

dannon commented Nov 30, 2025

Looks like I need to address memory usage issues to make the build work in CI, similar to webpack. I'll iterate on it.

@jmchilton
Copy link
Copy Markdown
Member

The selenium failures seem consistent - I think there something consistently wrong with the build around the workflow editor. I assume the playwright tests aren't failing because those tests haven't been migrated. Let me know if you want to delegate at least looking into the issue and tests some more and characterizing it for you so you can focus on downstream things.

@dannon
Copy link
Copy Markdown
Member Author

dannon commented Dec 1, 2025

@jmchilton Yep, they're legit -- one real issue w/ monaco packaging that I think I have a handle on now, but I haven't played with the other workflow editor ones yet. I'll give it a look when I wrap up the monaco stuff, and then can happily pass it on if I can't resolve them right away.

@dannon dannon marked this pull request as ready for review December 2, 2025 09:34
@github-actions github-actions Bot added this to the 26.0 milestone Dec 2, 2025
@mvdbeek
Copy link
Copy Markdown
Member

mvdbeek commented Dec 2, 2025

I suppose the monaco tests are still legitimate failures, should I see if I can make sense of them ?

@dannon
Copy link
Copy Markdown
Member Author

dannon commented Dec 2, 2025

@mvdbeek Yeah, I fixed the stale handle issue earlier this morning but I hadn't pushed yet -- I think there may be one more legit monaco issue though if you wanted to look. Try test_run_custom_tool locally to see it

dannon added 18 commits December 2, 2025 12:11
Use explicit paths for SCSS imports that Vite cannot resolve, including custom_theme_variables.scss in App.vue, base.scss in 3 files, _breakpoints.scss in 7 files, and theme/blue.scss in 1 file.
Vite requires relative paths for worker imports to resolve correctly.
Replace // comments with /* */ which is valid CSS syntax.
Use Object type instead of IconDefinition for the icon prop to avoid
type import issues in non-TypeScript Vue files.
faGear is only available in Font Awesome 6 (FA5 uses faCog), so import
it from the font-awesome-6 alias.
Configure Vite to proxy all requests (except its own routes) to the Galaxy backend, matching webpack-dev-server behavior. Supports GALAXY_URL env var to specify backend (default: http://127.0.0.1:8080), CHANGE_ORIGIN env var for remote server support, and listens on 0.0.0.0 for network access.
Creates src/entry/libs.js that exposes required globals (jQuery, underscore, bundleEntries, config) to window for legacy Mako templates. Also updates vite.config.mjs to add libs as an entry point and disables CSS code splitting for single base.css output.
Rename vite-plugin-webpack-aliases.js to vite-plugin-galaxy-legacy.js and remove webpack-related comments and unused getWebpackAliases function.
Remove publicPath.js (webpack-specific), consolidate jquery.custom.js to ESM version, remove __webpack_public_path__ global, and update comments throughout to remove webpack mentions.
dannon added 10 commits December 2, 2025 13:48
Bootstrap-vue checks Vue.version at module init time, which fails when
loaded as a separate chunk because ES modules can execute in parallel.
Keep these libraries in the main bundle for now - can revisit with
dynamic imports in a followup.
- Configure Monaco workers with Vite's ?worker syntax in CustomToolEditor
- Use lazy monacoInstance pattern in YamlJs.ts to avoid AMD loader issues
- Import CustomToolEditor statically (async loading incompatible with Vue Router 3.x + Vite)

The static import increases bundle size by ~7MB but is necessary until Vue Router 4 migration.
Add type declarations for Vite's ?worker suffix imports and use the
proper IDisposable type from monaco-types.
Convert the dynamic import of the layout module to a static import.
The dynamic import was causing the app to reinitialize after clicking
auto-layout in production builds, clearing the workflow stores.

This increases the initial bundle size slightly (elkjs is now bundled
with the main chunk instead of being lazy-loaded), but ensures the
workflow editor functions correctly.

TODO: Investigate why dynamic imports in Vite production builds cause
this behavior, and consider alternative code-splitting approaches
like defineAsyncComponent or manual chunk configuration.
Vite's template compiler doesn't preserve whitespace between inline
elements the way Webpack did, so the tool name and description were
running together. Adding an explicit space fixes this.
The .view-line elements inside Monaco editor get re-rendered as the
editor updates, causing StaleElementReferenceException. Use the stable
.monaco-editor container instead.
The queue processing for config.set() calls was added to handle a race
condition in Vite dev mode, but no Mako templates actually use config.set().
This removes the dead code and simplifies the Window type declaration.
editor = self.wait_for_selector_visible(".monaco-editor div.view-line")
# Try finding Monaco editor and replace skeleton content
self.sleep_for(self.wait_types.UX_RENDER) # Allow editor to initialize
# Use the stable .monaco-editor container, not .view-line which gets re-rendered
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

excellent fix!

@mvdbeek
Copy link
Copy Markdown
Member

mvdbeek commented Dec 3, 2025

I've taken the liberty to push 0cfdf13 ... it seems to address c6e82cf.

Feel free to drop it if we want to go the route of explicit whitespace, but this looks a little nicer to me ?

Copy link
Copy Markdown
Member

@mvdbeek mvdbeek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome, and I think the build also nicely stays below the 4GB limit during the build phase, while completing in reasonable time (83 seconds for me).

@mvdbeek
Copy link
Copy Markdown
Member

mvdbeek commented Dec 3, 2025

So something weird is going on. yarn build succeeds, but make client runs out of memory ?
Aren't they doing the same thing ??

✓ 8004 modules transformed.

<--- Last few GCs --->

[73311:0x160018000]    91468 ms: Mark-Compact (reduce) 2944.8 (3112.5) -> 2944.8 (3081.5) MB, pooled: 0 MB, 806.71 / 0.00 ms  (average mu = 0.186, current mu = 0.000) last resort; GC in old space requested
[73311:0x160018000]    92245 ms: Mark-Compact (reduce) 2944.8 (3081.5) -> 2944.8 (3081.5) MB, pooled: 0 MB, 777.21 / 0.00 ms  (average mu = 0.113, current mu = 0.000) last resort; GC in old space requested


<--- JS stacktrace --->

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
----- Native stack trace -----

 1: 0x10069e278 node::OOMErrorHandler(char const*, v8::OOMDetails const&) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
 2: 0x100884cd4 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
 3: 0x100a89bfc v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
 4: 0x100a5d9ec v8::internal::FactoryBase<v8::internal::Factory>::NewRawTwoByteString(int, v8::internal::AllocationType) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
 5: 0x100d98c0c v8::internal::String::SlowFlatten(v8::internal::Isolate*, v8::internal::Handle<v8::internal::ConsString>, v8::internal::AllocationType) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
 6: 0x100e72d64 v8::internal::RegExpImpl::IrregexpExec(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSRegExp>, v8::internal::Handle<v8::internal::String>, int, v8::internal::Handle<v8::internal::RegExpMatchInfo>, v8::internal::RegExp::ExecQuirks) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
 7: 0x100e92e50 v8::internal::Runtime_RegExpExec(int, unsigned long*, v8::internal::Isolate*) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
 8: 0x101345af4 Builtins_CEntry_Return1_ArgvOnStack_NoBuiltinExit [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
 9: 0x1013cc218 Builtins_RegExpPrototypeTest [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
10: 0x1012b0ef0 Builtins_InterpreterEntryTrampoline [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
11: 0x1076ea46c
12: 0x1076eecbc
13: 0x1013b84d8 Builtins_PromiseFulfillReactionJob [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
14: 0x1012dd594 Builtins_RunMicrotasks [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
15: 0x1012aeaf4 Builtins_JSRunMicrotasksEntry [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages
Revert "Use `whitespace: "preserve"` compiler option"
/nodejs_wheel/bin/node]
16: 0x1009ee644 v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
17: 0x1009eeeec v8::internal::(anonymous namespace)::InvokeWithTryCatch(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
18: 0x1009ef024 v8::internal::Execution::TryRunMicrotasks(v8::internal::Isolate*, v8::internal::MicrotaskQueue*) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
19: 0x100a1be38 v8::internal::MicrotaskQueue::RunMicrotasks(v8::internal::Isolate*) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
20: 0x100a1c5ec v8::internal::MicrotaskQueue::PerformCheckpoint(v8::Isolate*) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
21: 0x10059d9cc node::InternalCallbackScope::Close() [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
22: 0x10059d420 node::CallbackScope::~CallbackScope() [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
23: 0x10065ed5c (anonymous namespace)::uvimpl::Work::AfterThreadPoolWork(int) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
24: 0x10065f174 node::ThreadPoolWork::ScheduleWork()::'lambda'(uv_work_s*, int)::operator()(uv_work_s*, int) const [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
25: 0x10065f028 node::ThreadPoolWork::ScheduleWork()::'lambda'(uv_work_s*, int)::__invoke(uv_work_s*, int) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
26: 0x1012875f0 uv__work_done [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
27: 0x10128b36c uv__async_io [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
28: 0x10129f970 uv__io_poll [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
29: 0x10128b904 uv_run [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
30: 0x10059e508 node::SpinEventLoopInternal(node::Environment*) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
31: 0x1006e9744 node::NodeMainInstance::Run() [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
32: 0x1006578b8 node::Start(int, char**) [/Users/mvandenb/src/galaxy/.venv/lib/python3.13/site-packages/nodejs_wheel/bin/node]
33: 0x1854c6b98 start [/usr/lib/dyld]
/bin/sh: line 1: 73311 Abort trap: 6           vite build
error Command failed with exit code 134.

this is with or without the last commit.

@mvdbeek
Copy link
Copy Markdown
Member

mvdbeek commented Dec 3, 2025

ahhhh, the makefile specifies --max-old-space-size=3072 in NODE_OPTIONS, which is less than what we do in CI!

mvdbeek and others added 4 commits December 3, 2025 09:22
bundleEntries.js was deleted upstream and no templates use
window.bundleEntries or window.config anymore. Removes dead code
from entry points.
This preserves whitespace in Vue templates globally, matching the
default behavior of Webpack's vue-loader. Removes the need for
explicit {{ " " }} hacks in Tool.vue.

Note: Vue 3+ defaults to 'condense' which produces smaller bundles
but can break layouts when whitespace between elements spans
newlines. A future cleanup could switch to condense after auditing
components and using CSS margins instead of whitespace for spacing.
Copy link
Copy Markdown
Member

@itisAliRH itisAliRH left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's super nice, thank you @dannon✌🏻🚀

@mvdbeek mvdbeek merged commit 1a58476 into galaxyproject:dev Dec 3, 2025
58 of 62 checks passed
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Dec 3, 2025

This PR was merged without a "kind/" label, please correct.

@nsoranzo nsoranzo added kind/enhancement kind/refactoring cleanup or refactoring of existing code, no functional changes labels Dec 3, 2025
@itisAliRH itisAliRH deleted the vite-reorganized branch December 8, 2025 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/admin area/client area/UI-UX kind/enhancement kind/refactoring cleanup or refactoring of existing code, no functional changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants