🏗️ build: replace webpack with vite 8 build system#4529
🏗️ build: replace webpack with vite 8 build system#4529
Conversation
Migrate the entire frontend build pipeline from Webpack to Vite 8 (Rolldown/OXC). Adds vite.config.js with entry discovery from groups.json, HTML template generation, vendor code splitting, and dynamic plugin loading via glob + indirect eval. - Add vite.config.js with htmlTemplatePlugin for PHPTAL templates - Add public/vite-entries/ with all entry points and groups.json - Add lib/Utils/Vite/ViteAssets.php for dev/prod asset injection - Update BaseKleinViewController to use ViteAssets - Update templates (_manage.html, common.html) for Vite assets - Update package.json: consolidate scripts, add Vite deps, add events polyfill, remove 14 webpack-only devDependencies - Delete webpack.config.js - Update .gitignore for public/build/ output directory
- commonUtils: convert require() to dynamic import() for offlineUtils and CatToolActions (breaks circular deps) - mbc-style.scss: remove *zoom:1 IE hack (lightningcss warning) - Button.scss: fix selector specificity for Vite CSS ordering - SegmentButtons/SegmentTargetToolbar/SegmentsContainer: adjust component imports for ESM module resolution - useSocketLayer: simplify import path - mountPage: remove unused require
- babel.config.js: remove dead 'development' env (only Jest remains) - .htaccess: update commented-out offline rules for public/build/ - README.md: update yarn watch description, remove dev:on/dev:off Docker-specific commands (moved to docker_matecat repo)
There was a problem hiding this comment.
Pull request overview
Migrates the frontend asset pipeline from Webpack 5 to Vite 8 (Rolldown/OXC), including new entrypoint discovery and template-time asset injection to keep the PHP/PHPTAL rendering flow working in both dev (HMR) and production builds.
Changes:
- Remove Webpack config/tooling and switch
yarnscripts + dependencies to Vite 8. - Add
vite.config.jswith entry grouping (groups.json), plugin loading, vendor splitting, and post-build PHPTAL template injection. - Update application code/templates to work with ESM/Vite (dynamic imports, ESM
socket.io-client, CSS selector tweaks, dev-mode template selection + Vite dev tags).
Reviewed changes
Copilot reviewed 35 out of 37 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| yarn.lock | Dependency graph updated for Vite/Rolldown and removal of Webpack-related packages. |
| webpack.config.js | Removed legacy Webpack build configuration. |
| vite.config.js | New Vite build config (entry discovery, template injection, splitting, dev server/HMR config). |
| package.json | Switch scripts to Vite and update deps/devDeps (remove Webpack tooling, add Vite + plugins). |
| babel.config.js | Limit Babel config to Jest/test environment. |
| .htaccess | Adjust (commented) offline rewrite exceptions for new build output naming/layout. |
| .gitignore | Ignore public/build/ output directory. |
| README.md | Update development instructions to reflect Vite watch/HMR workflow. |
| lib/Utils/Vite/ViteAssets.php | New PHP helper to inject Vite dev-server scripts for HMR in dev mode. |
| lib/Controller/Abstracts/BaseKleinViewController.php | Dev-mode template selection (templates/_*) + expose vite_html and CSP nonce to templates. |
| lib/View/templates/common.html | Replace old CSS loop with ${structure vite_html} injection hook. |
| lib/View/templates/_manage.html | Remove initial loader markup in manage container. |
| public/vite-entries/groups.json | Single source of truth mapping templates → Vite entry names. |
| public/vite-entries/cattool.js | Vite wrapper entry for cattool (imports globalFunctions, page JS, and SCSS). |
| public/vite-entries/cattoolPlugins.js | Eager-glob cattool plugin entry imports. |
| public/vite-entries/allPagesPlugins.js | Eager-glob “all pages” plugin entry imports. |
| public/vite-entries/upload.js | Vite wrapper entry for upload page JS + SCSS. |
| public/vite-entries/uploadPlugins.js | Eager-glob upload plugin entry imports. |
| public/vite-entries/dashboard.js | Vite wrapper entry for dashboard page JS + SCSS. |
| public/vite-entries/signin.js | Vite wrapper entry for signin page JS + SCSS. |
| public/vite-entries/analyze.js | Vite wrapper entry for analyze page JS + SCSS. |
| public/vite-entries/activityLog.js | Vite wrapper entry for activity log page JS + SCSS. |
| public/vite-entries/qa-report.js | Vite wrapper entry for quality report page JS + SCSS. |
| public/vite-entries/xliffToTarget.js | Vite wrapper entry for xliff-to-target page JS + SCSS. |
| public/vite-entries/apiDoc.js | Vite wrapper entry for API doc page SCSS. |
| public/vite-entries/commonCss.js | Vite wrapper entry for shared/common SCSS. |
| public/vite-entries/errorPage.js | Vite wrapper entry for error page SCSS. |
| public/vite-entries/test-entry.js | Added placeholder entry file. |
| public/js/utils/commonUtils.js | Replace eager requires with async dynamic imports to reduce circular deps impact. |
| public/js/pages/mountPage.js | Remove unconditional globalFunctions import (moved to cattool entry). |
| public/js/hooks/useSocketLayer.js | Convert require('socket.io-client') to ESM import. |
| public/js/components/segments/SegmentsContainer.js | Move getRowHeightWithMargin definition earlier (same logic). |
| public/js/components/segments/SegmentTargetToolbar.js | Adjust element keys/props and wrap mapped output in keyed fragments. |
| public/js/components/segments/SegmentButtons.js | Minor JSX string literal formatting changes. |
| public/css/sass/mbc-style.scss | Remove IE-only *zoom hack (leaves empty .mbc-clearfix {}). |
| public/css/sass/components/common/Button.scss | Update selectors to avoid :global(...) pattern. |
| @@ -0,0 +1 @@ | |||
| // test | |||
There was a problem hiding this comment.
This appears to be a leftover placeholder entry and is not referenced by groups.json/the Vite input discovery. Removing it avoids confusion about supported entries and prevents accidental inclusion later.
- ViteAssets: add PHPDoc types for $groups and loadGroups(), handle file_get_contents returning false - BaseKleinViewController: null-coalesce $nonce for getHtml() call - phpstan-baseline: replace stale css_resources ignore with vite_html
| setBrowserHistoryBehavior() { | ||
| let updateAppByPopState = () => { | ||
| let updateAppByPopState = async () => { | ||
| const [{default: SegmentStore}, {default: SegmentActions}] = | ||
| await Promise.all([ | ||
| import('../stores/SegmentStore'), | ||
| import('../actions/SegmentActions'), | ||
| ]) |
There was a problem hiding this comment.
updateAppByPopState is now async and performs dynamic import()s, but nothing in this method ensures errors are handled. Since the handler is invoked from onpopstate without awaiting, any failure here will surface as an unhandled promise rejection and can break back/forward navigation. Consider adding try/catch inside updateAppByPopState (or returning a promise that the caller .catch()es) and optionally caching the Promise.all(import(...)) so it’s not re-created on every popstate event.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 36 out of 38 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
public/js/utils/commonUtils.js:136
- updateAppByPopState is now async and its Promise is not awaited/handled in window.onpopstate. If the dynamic imports fail (network/cache issue, dev server down), this will create an unhandled rejection and popstate handling will silently stop. Wrap the imports in try/catch and/or explicitly discard the Promise with error handling (e.g.,
void updateAppByPopState().catch(...)).
let updateAppByPopState = async () => {
const [{default: SegmentStore}, {default: SegmentActions}] =
await Promise.all([
import('../stores/SegmentStore'),
import('../actions/SegmentActions'),
])
var segment = SegmentStore.getSegmentByIdToJS(this.parsedHash.segmentId)
var currentSegment = SegmentStore.getCurrentSegment()
if (segment && currentSegment?.sid === segment.sid) return
if (segment && !segment.opened) {
SegmentActions.openSegment(this.parsedHash.segmentId, true)
}
}
window.onpopstate = () => {
this.parsedHash = new ParsedHash(window.location.hash)
updateAppByPopState()
}
| {buttons.map((button, index) => { | ||
| if (button.dropdownGroup) return <React.Fragment key={`group-${index}`}>{button.dropdownGroup}</React.Fragment> | ||
| return <React.Fragment key={`btn-${index}`}>{button.component}</React.Fragment> |
There was a problem hiding this comment.
The list rendering now wraps every toolbar item in a Fragment keyed by the array index. Since the buttons array is conditionally built (items appear/disappear based on config/state), index keys can cause React to reuse the wrong element between renders (e.g., handlers/state sticking to the wrong button). Prefer a stable key derived from the underlying item (e.g., an explicit id on each item, or reuse the existing per-button key values you already set like "reviselock"/"segmentquality").
| {buttons.map((button, index) => { | |
| if (button.dropdownGroup) return <React.Fragment key={`group-${index}`}>{button.dropdownGroup}</React.Fragment> | |
| return <React.Fragment key={`btn-${index}`}>{button.component}</React.Fragment> | |
| {buttons.map((button) => { | |
| const buttonKey = | |
| button.key || | |
| button.id || | |
| (button.dropdownGroup && button.dropdownGroup.key) || | |
| (button.component && button.component.key) | |
| if (button.dropdownGroup) return <React.Fragment key={buttonKey}>{button.dropdownGroup}</React.Fragment> | |
| return <React.Fragment key={buttonKey}>{button.component}</React.Fragment> |
| const require = createRequire(import.meta.url) | ||
| const ini = require('ini') | ||
|
|
||
| const matecatConfig = ini.parse(readFileSync('./inc/config.ini', 'utf-8')) | ||
|
|
||
| // Single source of truth: template name → Vite entry names | ||
| const entryGroups = JSON.parse(readFileSync('./public/vite-entries/groups.json', 'utf-8')) | ||
|
|
There was a problem hiding this comment.
vite.config.js reads ./inc/config.ini unconditionally. In this repo only inc/config.ini.sample is versioned, so a fresh checkout running yarn watch/vite will throw at startup. Consider falling back to config.ini.sample (or an env-based default) when config.ini is missing, or guard with existsSync and use empty defaults for ENV/BUILD_NUMBER.
| server: { | ||
| host: '0.0.0.0', | ||
| port: 5173, | ||
| strictPort: true, | ||
| origin: 'https://dev.matecat.com', | ||
| cors: true, | ||
| hmr: { | ||
| protocol: 'wss', | ||
| host: 'dev.matecat.com', | ||
| clientPort: 443, | ||
| path: '__vite_hmr', | ||
| }, |
There was a problem hiding this comment.
Vite dev-server settings are hard-coded to dev.matecat.com (origin/HMR host). This makes local/dev environments with different hostnames difficult (and can break HMR if the app runs on another domain). Consider deriving these values from existing config (e.g., AppConfig/INI/env vars) with a sensible localhost default.
#4520) * 🐛 fix(project-creation): eliminate replication-lag race and make pre-translation failures fatal - replace getChunksByJobId() re-query in insertPreTranslations() with direct $job->source/$job->target access, avoiding ProxySQL routing standalone SELECT to an unsynced read replica - remove dead getChunksByJobId() method and ChunkDao import from JobCreationService - re-throw exception in insertPreTranslations() catch block so failures abort project creation instead of being swallowed - add clearFailedProject() call in the post-creation catch block to clean up orphaned project/file records on any failure - consolidate duplicate try/catch in createProject() by moving resolveAndInsertFiles(), determineStatusAndPopulateResult(), and insertFileInstructions() into a single unified method resolveFilesExtractSegmentsAndStoreData() - rewrite tests: verify exception propagation, addError-before- throw ordering, and first-failure-aborts-foreach behavior * ♻️ refactor(project-creation): centralize error recording in outer catch and remove redundant email notification Remove addError() and sendErrMailReport() from JobCreationService::insertPreTranslations() catch block. Error recording is now handled exclusively by mapSegmentExtractionError() in the outer handler, eliminating duplicate error entries. Debug logging preserved. Remove insertPreTranslationsRecordsErrorBeforePropagating test (behavior removed; propagation already covered by insertPreTranslationsFailurePropagatesException). * 📝 docs: update instructions with used technologies section - add PHP 8.3, JavaScript, and React 18 to the list of used technologies in instructions Signed-off-by: domenico <domenico@translated.net> * 📝 docs(project-creation): fix stale docblock, test name, and technology casing Update insertPreTranslations() docblock to remove mention of removed email notification. Rename test to insertPreTranslationsFailurePropagatesException to match actual behavior. Fix "Javascript" → "JavaScript" casing in review instructions. --------- Signed-off-by: domenico <domenico@translated.net>
* fix: subfiltering handlers persist * Fixed PHPStan error
- @translated/lara: 1.8.0-beta.3 → 1.9.0
* feat: add ed error_code to AI Worker messages * fixed phpstan * fixed phpstan * FE integration --------- Co-authored-by: pierluigi.dicianni <pierluigi.dicianni@translated.net>
- regenerate phpstan-baseline.neon to absorb 726 pre-existing @throws violations across 275 files - add phpstan-throws-backlog.txt listing all files to fix sequentially
- create `.github/PULL_REQUEST_TEMPLATE.md` to standardize pull request descriptions - add `.github/workflows/pr-readiness-check.yml` GitHub Action to validate mandatory checklist - implement checklist validation logic in `.github/scripts/pr-readiness-check.js` - include comprehensive unit tests in `.github/scripts/pr-readiness-check.test.js` Signed-off-by: domenico <domenico@translated.net>
- update instructions to only require naming the AI agent/tool used - adjust example to remove implementation + test generation details 🐛 fix(pr-checks): ensure comments are fully removed in section validation - implement loop to repeatedly strip nested HTML comments in `pr-readiness-check.js` 🔧 chore(tests): exclude `.github/scripts` from jest transformations - update `jest.config.js` to add `.github/scripts/` to `transformIgnorePatterns` Signed-off-by: domenico <domenico@translated.net>
- add testPathIgnorePatterns to jest.config.js so Jest does not pick up CI validation scripts that use Node built-in test runner
- add lib/View/APIDoc.php and lib/View/templates/_APIDoc.php to excludePaths in phpstan.neon (webpack build artifacts) - remove 5 stale baseline entries referencing excluded files
- APIDoc.php is a webpack build artifact that may not exist in CI - append (?) to its excludePaths entry so PHPStan tolerates absence
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- validate PR title (required gate) and commit messages (hygiene gate) against emoji-prefixed conventional-commit spec - add commit-message-check.js with emoji↔type map, VS16 normalization, format/length/case/period validation, merge-commit skip - add 35 unit tests covering all 12 types, edge cases, and error collection - bypass via `commit-message-exception` label
- add requireEmoji option (default true) to validateCommitMessage so PR title stays strict while commit messages accept emoji-less conventional-commit format (e.g. "docs(qa): ...") - auto-skip GitHub web UI patterns (Update/Create/Delete/Rename) in relaxed mode - update workflow to pass requireEmoji: false for commit-messages job - add 18 new tests for relaxed mode and isGitHubWebEdit (53 total)
…callers Declare checked exceptions on all methods using Database::transaction(), which re-throws \Throwable on rollback. Remove 2 stale baseline entries now covered by the broader @throws declaration.
- run PHPUnit with Xdebug coverage on pull requests - invoke ostico/test-guard@v1.0.1 with 80% coverage threshold - enable AI-powered test adequacy analysis
- move test-guard from standalone workflow into _ci-cd.yml as a PR-only job that consumes coverage from the tests job - extract coverage.xml from test container via docker cp and upload as "coverage-report" artifact - add pull-requests:write and statuses:write permissions to aws_dev.yml and aws_prod.yml callers - set per-job permissions in _ci-cd.yml (test-guard needs write access, other jobs only need contents:read) - update docker submodule (php-pcov + --coverage-clover)
- grant models:read permission in PR workflows for repository access Signed-off-by: domenico <domenico@translated.net>
- update permissions in _ci-cd.yml, aws_prod.yml, and aws_dev.yml - align with GitHub's recommended permissions model Signed-off-by: domenico <domenico@translated.net>
- Add Clover reporter to Jest so it writes js-coverage/clover.xml - Extract both PHP and JS coverage from test container - Pass both files to test-guard via YAML block scalar
# Conflicts: # .github/workflows/commit-message-check.yml
🧪 Test-Guard Report❌ FAIL — Some changed source files lack adequate test coverage. Coverage Analysis: ❌ FAILNo changed source files found in coverage report (threshold: 80%)
Test File Matching: ❌ FAILFile matching: 22 fail
Per-File Evaluation: ❌ FAILAll files resolved by deterministic shortcuts.
Result: ❌ FAIL |
| ### `yarn watch` | ||
|
|
||
| Watches for changes in the source files and automatically rebuilds the project in development mode. Useful for local development as it provides live updates. | ||
| Starts the Vite development server with Hot Module Replacement (HMR). Useful for local development as it provides instant updates without full page reloads. |
There was a problem hiding this comment.
yarn watch is described as starting the Vite dev server, but the app also needs PHP-side dev mode enabled (e.g., VITE_DEV=1 / the reverse-proxy setup) for templates to inject Vite scripts. Consider updating this line to mention the required server-side toggle so developers don’t start Vite and still get production templates/assets.
| Starts the Vite development server with Hot Module Replacement (HMR). Useful for local development as it provides instant updates without full page reloads. | |
| Starts the Vite development server with Hot Module Replacement (HMR). For local development, also enable the PHP-side Vite dev mode (for example `VITE_DEV=1` or the reverse-proxy setup) so server-rendered templates inject the Vite scripts instead of the production assets. |
Summary
Migrate the entire frontend build pipeline from Webpack 5 to Vite 8 (Rolldown/OXC). Replaces
webpack.config.jswithvite.config.js, adds a PHP asset helper for dev/prod injection, creates explicit entry-point modules, and adapts source code for ESM compatibility.Type
refactor— restructure without behavior changeChanges
vite.config.jsgroups.json, HTML template generation for PHPTAL, vendor code splitting, dynamic plugin loadingwebpack.config.jslib/Utils/Vite/ViteAssets.phplib/Controller/Abstracts/BaseKleinViewController.phpViteAssetsfor script/style injection instead of manual asset listslib/View/templates/_manage.html,common.htmlpublic/vite-entries/(14 files +groups.json)public/js/utils/commonUtils.jsrequire()to dynamicimport()to break circular depspublic/js/components/segments/Segment*.js,SegmentsContainer.jspublic/js/hooks/useSocketLayer.jspublic/js/pages/mountPage.jsrequirepublic/css/sass/mbc-style.scss*zoom:1IE hack (lightningcss warning)public/css/sass/components/common/Button.scssbabel.config.jsdevelopmentenv — only Jest config remains.htaccesspublic/build/package.jsonyarn.lock.gitignorepublic/build/output directoryphpstan-baseline.neonplugins/translatedREADME.mdTesting
vendor/bin/phpunit --exclude-group=ExternalServices --no-coveragepasses./vendor/bin/phpstanpasses (0 errors, with baseline)Build verified: 2971 modules, ~45s build time, zero warnings. Dev server tested with HMR via Docker Apache reverse proxy (docker_matecat#25).
AI Disclosure
Claude Code (claude-opus-4-6), GitHub Copilot
Notes
Build Stats: 2971 modules, ~45s build, Vite 8.0.9, Rolldown 1.0.0-rc.16.
Dev Mode: Vite dev server runs inside the Docker container with Apache reverse proxy for HMR. See docker_matecat#25 for the
vite-proxyCLI tool and Apache proxy config.Known Tech Debt: 127 circular dependency cycles in the cattool entry, centered around 5 hub files:
SegmentActions,SegmentStore,commonUtils,offlineUtils,setTranslationUtil. Vite/Rolldown handles them at runtime (no build errors) but they're a maintenance hazard worth addressing incrementally.