Conversation
Replace webpack with Vite 8 (Rolldown) as the frontend bundler. Key changes: - Replace webpack.config.ts with vite.config.ts using Rolldown - Use native ES modules with import maps for cache busting - Build web components as a separate blocking IIFE bundle to prevent flash of unstyled content (same behavior as webpack's blocking script) - Update all dynamic imports from webpack chunk comments to standard dynamic import() syntax - Replace process.env.TEST with import.meta.env.MODE - Add vite/client types to tsconfig.json - Update Monaco error suppression regex for new chunk names - Rename WEBPACK_* Makefile variables to FRONTEND_* Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
Replace query-string cache busting (?v=) with content-hashed entry filenames for JS and CSS assets. Vite now generates a manifest (.vite/manifest.json) mapping unhashed to hashed paths. A new Go-side AssetPath function reads the manifest and resolves paths in templates. This eliminates the need for the importmap workaround that was required because chunks imported the entry module without the ?v= query parameter. - Add modules/public/manifest.go with mtime-based cache invalidation so dev mode auto-detects frontend rebuilds - Add AssetPath template function for hashed path resolution - Update all templates to use AssetPath instead of ?v=AssetVersion - Pass sharedWorkerPath via window.config for the SharedWorker URL - Rename eventsource.sharedworker to sharedworker - Fix markup_external_test.go for type="module" and hashed paths Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
- Add content hash to webcomponents.js IIFE build and append its entry to the Vite manifest - Use AssetPath for swagger asset paths in openapi.go renderer - Strip content hash from theme CSS filenames in webtheme.go to correctly extract internal theme names - Remove AssetVersion variable and template function, now fully replaced by content-hashed filenames via manifest - Rename AssetPath to GetAssetPath Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
- Rename AssetPath to GetAssetPath in template helper and all templates - Clean up stale webcomponents files before IIFE rebuild - Add comment clarifying TypeError catch for navigation-during-import Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
`build()` returns an array for IIFE lib builds, so the `'output' in result` check silently skipped the manifest append. Handle both array and single-object return types. Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
|
But this will break Firefox support? |
Why should it? I've already tested everything in Firefox. The only new browser requirement is module scripts which are supported in Firefox since 2018. |
The webcomponents directory had both index.ts and webcomponents-blocking.ts with identical content. Remove the duplicate and use index.ts as the entry. Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR migrates Gitea’s frontend build pipeline from Webpack to Vite 8, switching to content-hashed asset filenames resolved at runtime via a manifest to improve build performance and cache correctness.
Changes:
- Replace Webpack configuration/build flow with a new Vite 8 build (including manifest generation and hashed outputs).
- Update backend + templates to resolve asset filenames via
public.GetAssetPath/GetAssetPathinstead of?v={{AssetVersion}}. - Adjust frontend entrypoints and dynamic imports for Vite, including a dedicated blocking webcomponents bundle and updated Monaco worker wiring.
Reviewed changes
Copilot reviewed 54 out of 60 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| webpack.config.ts | Removed legacy Webpack build configuration. |
| vite.config.ts | Added Vite 8 build config, manifest output, webcomponents IIFE build, and license generation. |
| package.json | Replaced Webpack deps with Vite/Vite Vue plugin and related tooling. |
| pnpm-lock.yaml | Lockfile updates reflecting bundler/tooling migration. |
| types.d.ts | Removed webpack-specific module typing. |
| tsconfig.json | Switched TS global types from webpack/module to vite/client. |
| eslint.config.ts | Dropped globals.webpack for web sources. |
| Makefile | Replaced webpack build/watch targets with Vite equivalents and new outputs. |
| .gitignore | Ignored Vite manifest output directory under public/assets/.vite. |
| web_src/js/webcomponents/webcomponents-blocking.ts | New blocking webcomponents entry used for FOUC avoidance. |
| web_src/js/vitest.setup.ts | Updated unit test window config to remove webpack globals and add shared worker path field. |
| web_src/js/utils/testhelper.ts | Updated “unit test mode” detection for Vite/Vitest. |
| web_src/js/utils/dom.test.ts | Adjusted Vitest expectation API usage. |
| web_src/js/utils.test.ts | Adjusted Vitest expectation API usage. |
| web_src/js/standalone/swagger.ts | Ensured standalone CSS is imported from the entrypoint for Vite bundling. |
| web_src/js/standalone/external-render-iframe.ts | Ensured standalone CSS is imported from the entrypoint for Vite bundling. |
| web_src/js/standalone/devtest.ts | Ensured standalone CSS is imported from the entrypoint for Vite bundling. |
| web_src/js/render/plugins/pdf-viewer.ts | Removed webpack chunk annotations; rely on Vite dynamic import. |
| web_src/js/render/plugins/3d-viewer.ts | Removed webpack chunk annotations; rely on Vite dynamic import. |
| web_src/js/modules/sortable.ts | Removed webpack chunk annotation; keep dynamic import for code-splitting. |
| web_src/js/modules/monaco.ts | New Monaco module that wires Vite ?worker imports and exports Monaco API. |
| web_src/js/markup/refissue.ts | Removed webpack chunk annotation; use Vite dynamic import for Vue component. |
| web_src/js/markup/mermaid.ts | Removed webpack chunk annotations; use Vite dynamic import. |
| web_src/js/markup/math.ts | Switched KaTeX + CSS loading to plain dynamic imports for Vite. |
| web_src/js/markup/asciicast.ts | Switched asciinema player + CSS loading to plain dynamic imports for Vite. |
| web_src/js/index.ts | Moved CSS imports into the JS entry; updated dynamic import error handling. |
| web_src/js/globals.d.ts | Updated window.config shape; added MonacoEnvironment typing and *?worker module declaration. |
| web_src/js/features/tribute.ts | Removed webpack chunk annotation; rely on Vite dynamic import. |
| web_src/js/features/stopwatch.ts | Switched SharedWorker URL construction to use manifest-resolved worker path. |
| web_src/js/features/notification.ts | Switched SharedWorker URL construction to use manifest-resolved worker path. |
| web_src/js/features/sharedworker.ts | Added new SharedWorker implementation for event streaming. |
| web_src/js/features/repo-issue-pull.ts | Removed webpack chunk annotation for Vue component dynamic import. |
| web_src/js/features/repo-findfile.ts | Removed webpack chunk annotation for Vue component dynamic import. |
| web_src/js/features/recent-commits.ts | Removed webpack chunk annotation for Vue component dynamic import. |
| web_src/js/features/heatmap.ts | Removed webpack chunk annotation for Vue component dynamic import. |
| web_src/js/features/dropzone.ts | Switched Dropzone + CSS loading to plain dynamic imports for Vite. |
| web_src/js/features/contributors.ts | Removed webpack chunk annotation for Vue component dynamic import. |
| web_src/js/features/comp/Cropper.ts | Removed webpack chunk annotation; rely on Vite dynamic import. |
| web_src/js/features/comp/ComboMarkdownEditor.ts | Switched EasyMDE + CSS loading to plain dynamic imports for Vite. |
| web_src/js/features/colorpicker.ts | Switched color picker + CSS loading to plain dynamic imports for Vite. |
| web_src/js/features/codeeditor.ts | Updated Monaco import to use the new modules/monaco.ts wrapper. |
| web_src/js/features/code-frequency.ts | Removed webpack chunk annotation for Vue component dynamic import. |
| web_src/js/features/citation.ts | Removed webpack chunk annotations; rely on Vite dynamic imports. |
| web_src/js/features/captcha.ts | Removed webpack chunk annotation; rely on Vite dynamic import. |
| web_src/js/bootstrap.ts | Removed webpack public path setup; adjusted ignore patterns and asset base URL logic. |
| templates/swagger/ui.tmpl | Updated Swagger assets to use GetAssetPath and module script. |
| templates/status/500.tmpl | Updated “minimal template functions” comment to reference GetAssetPath. |
| templates/shared/combomarkdowneditor.tmpl | Converted inline script to module script. |
| templates/repo/diff/box.tmpl | Converted inline script to module script and adjusted file-tree visibility init. |
| templates/devtest/devtest-header.tmpl | Updated devtest CSS link to GetAssetPath. |
| templates/devtest/devtest-footer.tmpl | Updated devtest JS to module script + GetAssetPath. |
| templates/base/head_style.tmpl | Updated core CSS and theme CSS to use GetAssetPath. |
| templates/base/head_script.tmpl | Removed AssetVersion usage; added sharedWorkerPath config; added blocking webcomponents script and module index.js script via GetAssetPath. |
| modules/templates/helper.go | Exposed GetAssetPath to templates (replacing AssetVersion). |
| modules/setting/server.go | Removed AssetVersion from server settings initialization. |
| modules/public/manifest.go | Added Vite manifest loader/cache + GetAssetPath resolver. |
| modules/public/manifest_test.go | Added unit tests for manifest parsing and GetAssetPath fallback behavior. |
| modules/markup/render.go | Updated external render iframe asset URLs to resolve via GetAssetPath and module script. |
| modules/markup/external/openapi.go | Updated OpenAPI renderer to use GetAssetPath-resolved swagger assets and module script. |
| tests/integration/markup_external_test.go | Updated expected HTML to match module script + manifest-resolved asset paths. |
| services/webtheme/webtheme.go | Stripped Vite content hash from theme internal names when loading theme metadata. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
- Add comment explaining ENABLE_SOURCEMAP=reduced backward compatibility - Add dev-licenses-stub plugin so licenses.txt exists in dev builds Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
|
Actually the |
because of the bug mentioned in #36896 (comment) caused by |
OK, if you can clearly document the behavior and most people agree to increase most page's loading time. |
Async chunks do not increase page load times, those scripts are deferred, so all they cause is the deferred JS to become active maybe a few milliseconds later, dependant on how many waterfall effects there are. |
It increases "network time" during the page loading. Don't you see that in your screenshots? If the "network request" doesn't finish, how can the JS scripts get executed? If the JS scripts don't execute, how can the page JS-related functions work? |
The page is interactive at the same time regardless of how many async chunks, the loading times in the footer are variable, not representative. Only the IIFE chunk is render-blocking and therefor involved in the actual page load time. |
Use includeDependenciesRecursively: false to prevent the mermaid codeSplitting group from absorbing shared dependencies like the preload-helper, which would make the mermaid chunk a static dependency of every page. Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
Let me quote Claude on this:
So the only way to un-chunk them is remove them from the swagger entry point. |
Use native fetch in swagger instead of the shared fetch wrapper to eliminate utils and fetch shared chunks. Broaden vue group to include all @VUE packages and rename to just "vue". Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
|
Although you act as a "frontend expert", you knows nothing about page loading. Just like you didn't understand what is "async": #17386 (comment) |
All fixed except svg which must remain a chunk because 6 Vue components import it which themselves are lazy-loaded. |
Async and module scripts are non-parser-blocking, meaning the browser will render the page and then execute the scripts after page load when DOMContentReady fires. |
Signed-off-by: silverwind <me@silverwind.io>
|
Will do a few more refactors in vite config and maybe try to get the chunk number down a bit more. |
- Remove unused fileURLToPath, use join(import.meta.dirname, ...) instead - Remove unnecessary process.env.NODE_ENV define from IIFE build - Remove dead webcomponents cleanup glob - Remove unnecessary try/catch around manifest parsing - Simplify enableSourcemap ternary - Simplify commonViteOpts generic signature - Simplify assetFileNames function - Use names instead of deprecated name in assetFileNames Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
|
Down to 197 files wil latest tweaks. Nothing more is feasible in terms of de-chunking and the code is already rather hacky. Ultimatlely rolldown optimizes for smallest possible total size, which is ideal for binary size, and given caching and HTTP 2, a non-issue in practice. |
…s group Tippy.js checks process.env.NODE_ENV and is pulled into the IIFE bundle via overflow-menu.ts -> modules/tippy.ts. The citation-js codeSplitting group breaks plugin registration because includeDependenciesRecursively: false leaves the Cite class in a separate chunk. Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>

Replace webpack with Vite 8 as the frontend bundler. Frontend build is around 3-4 times faster than before. Will work on all platforms including riscv64 (via wasm).
JS loading order is exactly like before,
index.jsremains a classic script that is render-blocking. All other JS chunks are now module scripts (supported in all browsers since 2018).Entry filenames are content-hashed (e.g.
index.C6Z2MRVQ.js) and resolved at runtime via the Vite manifest, eliminating the?v=cache busting (which was unreliable in some scenarios like vscode dev build).Fixes: #17793
Docs: https://gitea.com/gitea/docs/pulls/364