Quellcode durchsuchen

fix(dashboard): Fix compilation issues caused by SWC version issues (#4105)

Michael Bromley vor 1 Woche
Ursprung
Commit
8f5496a260

+ 0 - 5
.github/workflows/publish_and_install.yml

@@ -108,11 +108,6 @@ jobs:
               run: |
                 cd ~/install/test-app
                 node setup-test-plugin.js
-            - name: Check SWC version
-              shell: bash
-              run: |
-                cd ~/install/test-app
-                npm ls @swc/core
             - name: Install Playwright
               run: |
                 cd $GITHUB_WORKSPACE

Datei-Diff unterdrückt, da er zu groß ist
+ 325 - 342
package-lock.json


+ 2 - 2
package.json

@@ -70,8 +70,8 @@
         "@nx/nx-linux-x64-gnu": "17.2.8",
         "@nx/nx-win32-x64-msvc": "17.2.8",
         "@rollup/rollup-linux-x64-gnu": "^4.13.0",
-        "@swc/core-darwin-arm64": "1.7.19",
-        "@swc/core-linux-x64-gnu": "1.4.7"
+        "@swc/core-darwin-arm64": "1.15.8",
+        "@swc/core-linux-x64-gnu": "1.15.8"
     },
     "resolutions": {
         "@apollo/server": "^5.0.0"

+ 1 - 0
packages/core/package.json

@@ -99,6 +99,7 @@
         "chokidar": "^3.6.0",
         "fs-extra": "^11.2.0",
         "glob": "^10.3.10",
+        "ioredis": "^5.3.2",
         "mysql2": "^3.15.0",
         "pg": "^8.13.1",
         "rimraf": "^5.0.5",

+ 8 - 7
packages/dashboard/package.json

@@ -57,15 +57,18 @@
         "index.html"
     ],
     "dependencies": {
+        "@babel/core": "^7.26.0",
+        "@babel/preset-react": "^7.26.3",
+        "@babel/preset-typescript": "^7.26.0",
         "@dnd-kit/core": "^6.3.1",
         "@dnd-kit/modifiers": "^9.0.0",
         "@dnd-kit/sortable": "^10.0.0",
         "@hookform/resolvers": "^4.1.3",
-        "@lingui/cli": "^5.5.0",
-        "@lingui/core": "^5.5.0",
-        "@lingui/react": "^5.5.0",
-        "@lingui/swc-plugin": "5.6.1",
-        "@lingui/vite-plugin": "^5.5.0",
+        "@lingui/babel-plugin-lingui-macro": "^5.7.0",
+        "@lingui/cli": "^5.7.0",
+        "@lingui/core": "^5.7.0",
+        "@lingui/react": "^5.7.0",
+        "@lingui/vite-plugin": "^5.7.0",
         "@radix-ui/react-accordion": "^1.2.11",
         "@radix-ui/react-alert-dialog": "^1.1.14",
         "@radix-ui/react-aspect-ratio": "^1.1.7",
@@ -92,7 +95,6 @@
         "@radix-ui/react-toggle": "^1.1.9",
         "@radix-ui/react-toggle-group": "^1.1.10",
         "@radix-ui/react-tooltip": "^1.2.7",
-        "@swc/core": "1.13.5",
         "@tailwindcss/vite": "^4.1.5",
         "@tanstack/eslint-plugin-query": "^5.66.1",
         "@tanstack/react-query": "^5.66.7",
@@ -112,7 +114,6 @@
         "@types/react-dom": "^19.0.4",
         "@uidotdev/usehooks": "^2.4.1",
         "@vitejs/plugin-react": "^5.0.4",
-        "@vitejs/plugin-react-swc": "^4.1.0",
         "acorn": "^8.11.3",
         "acorn-walk": "^8.3.2",
         "awesome-graphql-client": "^2.1.0",

+ 95 - 0
packages/dashboard/vite/vite-plugin-lingui-babel.ts

@@ -0,0 +1,95 @@
+import * as babel from '@babel/core';
+import type { Plugin } from 'vite';
+
+/**
+ * @description
+ * A custom Vite plugin that transforms Lingui macros in files using Babel instead of SWC.
+ *
+ * This plugin solves a critical compatibility issue with SWC plugins:
+ * - SWC plugins are compiled Wasm binaries that require exact version matching with `@swc/core`
+ * - When users have different SWC versions in their projects (e.g., from Next.js, Nx, etc.),
+ *   the Lingui SWC plugin fails with "failed to invoke plugin" errors
+ * - Babel has no such binary compatibility issues, making it much more reliable for library code
+ *
+ * The plugin runs BEFORE `@vitejs/plugin-react` and transforms files containing Lingui macros
+ * (imports from `@lingui/core/macro` or `@lingui/react/macro`) using the Babel-based
+ * `@lingui/babel-plugin-lingui-macro`.
+ *
+ * Files processed:
+ * - `@vendure/dashboard/src` files (in node_modules for external projects)
+ * - `packages/dashboard/src` files (in monorepo development)
+ * - User's dashboard extension files (e.g., custom plugins using Lingui)
+ *
+ * Files NOT processed:
+ * - Other node_modules packages (they shouldn't contain Lingui macros)
+ *
+ * @see https://github.com/vendurehq/vendure/issues/3929
+ * @see https://github.com/lingui/swc-plugin/issues/179
+ */
+export function linguiBabelPlugin(): Plugin {
+    return {
+        name: 'vendure:lingui-babel',
+        // Run BEFORE @vitejs/plugin-react so the macros are already transformed
+        // when the react plugin processes the file
+        enforce: 'pre',
+
+        async transform(code, id) {
+            // Strip query params for path matching (Vite adds ?v=xxx for cache busting)
+            const cleanId = id.split('?')[0];
+
+            // Only process TypeScript/JavaScript files
+            if (!/\.[tj]sx?$/.test(cleanId)) {
+                return null;
+            }
+
+            // Only process files that actually contain Lingui macro imports
+            // This is a fast check to avoid running Babel on files that don't need it
+            if (!code.includes('@lingui/') || !code.includes('/macro')) {
+                return null;
+            }
+
+            // Skip node_modules files EXCEPT for @vendure/dashboard source
+            // This ensures:
+            // 1. Dashboard source files get transformed (both in monorepo and external projects)
+            // 2. User's extension files get transformed (not in node_modules)
+            // 3. Other node_modules packages are left alone
+            if (cleanId.includes('node_modules')) {
+                const isVendureDashboard =
+                    cleanId.includes('@vendure/dashboard/src') || cleanId.includes('packages/dashboard/src');
+                if (!isVendureDashboard) {
+                    return null;
+                }
+            }
+
+            try {
+                const result = await babel.transformAsync(code, {
+                    filename: id,
+                    presets: [
+                        ['@babel/preset-typescript', { isTSX: true, allExtensions: true }],
+                        ['@babel/preset-react', { runtime: 'automatic' }],
+                    ],
+                    plugins: ['@lingui/babel-plugin-lingui-macro'],
+                    sourceMaps: true,
+                    // Don't look for babel config files - we want to control the config completely
+                    configFile: false,
+                    babelrc: false,
+                });
+
+                if (!result?.code) {
+                    return null;
+                }
+
+                return {
+                    code: result.code,
+                    map: result.map,
+                };
+            } catch (error) {
+                // Log the error but don't crash - let the build continue
+                // The lingui vite plugin will catch untransformed macros later
+                // eslint-disable-next-line no-console
+                console.error(`[vendure:lingui-babel] Failed to transform ${id}:`, error);
+                return null;
+            }
+        },
+    };
+}

+ 13 - 5
packages/dashboard/vite/vite-plugin-vendure-dashboard.ts

@@ -1,7 +1,7 @@
 import { lingui } from '@lingui/vite-plugin';
 import tailwindcss from '@tailwindcss/vite';
 import { tanstackRouter } from '@tanstack/router-plugin/vite';
-import react from '@vitejs/plugin-react-swc';
+import react from '@vitejs/plugin-react';
 import path from 'path';
 import { PluginOption } from 'vite';
 
@@ -13,6 +13,7 @@ import { viteConfigPlugin } from './vite-plugin-config.js';
 import { dashboardMetadataPlugin } from './vite-plugin-dashboard-metadata.js';
 import { gqlTadaPlugin } from './vite-plugin-gql-tada.js';
 import { hmrPlugin } from './vite-plugin-hmr.js';
+import { linguiBabelPlugin } from './vite-plugin-lingui-babel.js';
 import { dashboardTailwindSourcePlugin } from './vite-plugin-tailwind-source.js';
 import { themeVariablesPlugin, ThemeVariablesPluginOptions } from './vite-plugin-theme.js';
 import { transformIndexHtmlPlugin } from './vite-plugin-transform-index.js';
@@ -121,6 +122,7 @@ export type VitePluginVendureDashboardOptions = {
      */
     disablePlugins?: {
         tanstackRouter?: boolean;
+        linguiBabel?: boolean;
         react?: boolean;
         lingui?: boolean;
         themeVariables?: boolean;
@@ -185,12 +187,18 @@ export function vendureDashboardPlugin(options: VitePluginVendureDashboardOption
                     generatedRouteTree: path.join(packageRoot, 'src/app/routeTree.gen.ts'),
                 }),
         },
+        {
+            // Custom plugin that transforms Lingui macros using Babel instead of SWC.
+            // This runs BEFORE the react plugin to ensure macros are transformed first.
+            // Using Babel eliminates the SWC binary compatibility issues that caused
+            // "failed to invoke plugin" errors in external projects.
+            // See: https://github.com/vendurehq/vendure/issues/3929
+            key: 'linguiBabel',
+            plugin: () => linguiBabelPlugin(),
+        },
         {
             key: 'react',
-            plugin: () =>
-                react({
-                    plugins: [['@lingui/swc-plugin', {}]],
-                }),
+            plugin: () => react(),
         },
         {
             key: 'lingui',

+ 2 - 2
packages/job-queue-plugin/package.json

@@ -29,8 +29,8 @@
         "@google-cloud/pubsub": "^4.11.0",
         "@vendure/common": "3.5.2",
         "@vendure/core": "3.5.2",
-        "bullmq": "^5.4.2",
-        "ioredis": "^5.3.2",
+        "bullmq": "^5.66.4",
+        "ioredis": "5.8.2",
         "rimraf": "^5.0.5",
         "typescript": "5.8.2"
     },

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.