From 630ab0dbef0db4c229ad703fc36cc01a977dffcb Mon Sep 17 00:00:00 2001
From: Lee Rowlands <lee.rowlands@previousnext.com.au>
Date: Tue, 25 Feb 2025 10:27:56 +1000
Subject: [PATCH 1/4] Bundle a small amount

---
 .../ComponentSource/JsComponent.php           |  5 ++++
 ui/lib/astro-hydration/astro.config.mjs       | 16 +++++++++++-
 ui/lib/astro-hydration/package.json           |  5 +++-
 .../astro-hydration/src/components/Stub.jsx   |  3 +++
 ui/package-lock.json                          | 25 ++++++++++++++++++-
 ui/src/features/code-editor/Preview.tsx       |  4 +++
 6 files changed, 55 insertions(+), 3 deletions(-)

diff --git a/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php b/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php
index ba5ce12f5c..da8a357c24 100644
--- a/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php
+++ b/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php
@@ -115,6 +115,11 @@ final class JsComponent extends GeneratedFieldExplicitInputUxComponentSourceBase
         'preact' => \sprintf('%s%s/ui/lib/astro-hydration/dist/preact.module.js', $base_path, $xb_path),
         'preact/hooks' => \sprintf('%s%s/ui/lib/astro-hydration/dist/hooks.module.js', $base_path, $xb_path),
         'react/jsx-runtime' => \sprintf('%s%s/ui/lib/astro-hydration/dist/jsxRuntime.module.js', $base_path, $xb_path),
+        // @todo Remove this hard-coding and calculate it on a per component
+        // basis - see https://drupal.org/i/3500761.
+        'clsx' => \sprintf('%s%s/ui/lib/astro-hydration/dist/clsx.js', $base_path, $xb_path),
+        'class-variant-authority' => \sprintf('%s%s/ui/lib/astro-hydration/dist/class-variant-authority.js', $base_path, $xb_path),
+        'tailwind-merge' => \sprintf('%s%s/ui/lib/astro-hydration/dist/tailwind-merge.js', $base_path, $xb_path),
       ],
       // @todo Rename plugin ID in https://www.drupal.org/project/experience_builder/issues/3502982
       '#component' => $this->configuration['plugin_id'],
diff --git a/ui/lib/astro-hydration/astro.config.mjs b/ui/lib/astro-hydration/astro.config.mjs
index 344ae4cbc1..9439b87b27 100644
--- a/ui/lib/astro-hydration/astro.config.mjs
+++ b/ui/lib/astro-hydration/astro.config.mjs
@@ -11,7 +11,21 @@ export default defineConfig({
         output: {
           // Filename pattern for the output files
           entryFileNames: '[name].js',
-          chunkFileNames: '[name].js',
+          chunkFileNames: (chunkInfo) => {
+            // Make sure the output chunks for dependencies have useful file
+            // names so we can easily distinguish between them.
+            const matches = {
+              clsx: 'clsx.js',
+              'class-variance-authority': 'class-variance-authority.js',
+              'tailwind-merge': 'tailwind-merge.js',
+            };
+            return Object.entries(matches).reduce((carry, [key, value]) => {
+              if (chunkInfo.facadeModuleId?.includes(`node_modules/${key}`)) {
+                return value;
+              }
+              return carry;
+            }, '[name].js');
+          },
           assetFileNames: '[name][extname]',
         },
       },
diff --git a/ui/lib/astro-hydration/package.json b/ui/lib/astro-hydration/package.json
index 429a2cb590..24818c95f0 100644
--- a/ui/lib/astro-hydration/package.json
+++ b/ui/lib/astro-hydration/package.json
@@ -8,6 +8,9 @@
   "dependencies": {
     "@astrojs/preact": "^4.0.3",
     "astro": "^5.2.2",
-    "preact": "^10.25.4"
+    "class-variance-authority": "^0.7.1",
+    "clsx": "^2.1.1",
+    "preact": "^10.25.4",
+    "tailwind-merge": "^3.0.2"
   }
 }
diff --git a/ui/lib/astro-hydration/src/components/Stub.jsx b/ui/lib/astro-hydration/src/components/Stub.jsx
index a49cc7d385..826b61d673 100644
--- a/ui/lib/astro-hydration/src/components/Stub.jsx
+++ b/ui/lib/astro-hydration/src/components/Stub.jsx
@@ -8,5 +8,8 @@
 
 const { ...preactHooks } = await import('preact/hooks');
 const { jsx, jsxs, Fragment } = await import('preact/jsx-runtime');
+const { default: clsx } = await import('clsx');
+const { ...tailwindMerge } = await import('tailwind-merge');
+const { cva } = await import('class-variance-authority');
 
 export default function () {}
diff --git a/ui/package-lock.json b/ui/package-lock.json
index 8542a42404..77cc4afe3b 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -103,7 +103,10 @@
       "dependencies": {
         "@astrojs/preact": "^4.0.3",
         "astro": "^5.2.2",
-        "preact": "^10.25.4"
+        "class-variance-authority": "^0.7.1",
+        "clsx": "^2.1.1",
+        "preact": "^10.25.4",
+        "tailwind-merge": "^3.0.2"
       }
     },
     "node_modules/@adobe/css-tools": {
@@ -8891,6 +8894,17 @@
         "node": ">=8"
       }
     },
+    "node_modules/class-variance-authority": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
+      "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
+      "dependencies": {
+        "clsx": "^2.1.1"
+      },
+      "funding": {
+        "url": "https://polar.sh/cva"
+      }
+    },
     "node_modules/classnames": {
       "version": "2.5.1",
       "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
@@ -17308,6 +17322,15 @@
         "url": "https://opencollective.com/unts"
       }
     },
+    "node_modules/tailwind-merge": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.0.2.tgz",
+      "integrity": "sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/dcastil"
+      }
+    },
     "node_modules/tailwindcss-in-browser": {
       "version": "0.1.3",
       "resolved": "https://registry.npmjs.org/tailwindcss-in-browser/-/tailwindcss-in-browser-0.1.3.tgz",
diff --git a/ui/src/features/code-editor/Preview.tsx b/ui/src/features/code-editor/Preview.tsx
index 29293052cf..4131cf678d 100644
--- a/ui/src/features/code-editor/Preview.tsx
+++ b/ui/src/features/code-editor/Preview.tsx
@@ -67,6 +67,10 @@ const importMap = {
     'react/': 'https://esm.sh/preact/compat/',
     'react-dom': 'https://esm.sh/preact/compat',
     'react-dom/': 'https://esm.sh/preact/compat/',
+    // @todo Remove hardcoding and allow components to nominate their own?
+    clsx: 'https://esm.sh/clsx',
+    'class-variance-authority': 'https://esm.sh/class-variance-authority',
+    'tailwind-merge': 'https://esm.sh/tailwind-merge',
   },
 };
 
-- 
GitLab


From db0dd1686f5542565114074077eba1857be329da Mon Sep 17 00:00:00 2001
From: Lee Rowlands <lee.rowlands@previousnext.com.au>
Date: Tue, 25 Feb 2025 10:46:23 +1000
Subject: [PATCH 2/4] Update tests

---
 tests/src/Kernel/DataType/ComponentTreeHydratedTest.php | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tests/src/Kernel/DataType/ComponentTreeHydratedTest.php b/tests/src/Kernel/DataType/ComponentTreeHydratedTest.php
index 273ad589b1..95d8d869ae 100644
--- a/tests/src/Kernel/DataType/ComponentTreeHydratedTest.php
+++ b/tests/src/Kernel/DataType/ComponentTreeHydratedTest.php
@@ -804,6 +804,9 @@ HTML,
                                 'preact' => \sprintf('%s/ui/lib/astro-hydration/dist/preact.module.js', $path),
                                 'preact/hooks' => \sprintf('%s/ui/lib/astro-hydration/dist/hooks.module.js', $path),
                                 'react/jsx-runtime' => \sprintf('%s/ui/lib/astro-hydration/dist/jsxRuntime.module.js', $path),
+                                'clsx' => \sprintf('%s/ui/lib/astro-hydration/dist/clsx.js', $path),
+                                'class-variant-authority' => \sprintf('%s/ui/lib/astro-hydration/dist/class-variant-authority.js', $path),
+                                'tailwind-merge' => \sprintf('%s/ui/lib/astro-hydration/dist/tailwind-merge.js', $path),
                               ],
                               '#component' => 'my-cta',
                               '#props' => [
-- 
GitLab


From 40e5f64aec6101c06b7fbd2cd6f82cc4d6da459c Mon Sep 17 00:00:00 2001
From: Lee Rowlands <lee.rowlands@previousnext.com.au>
Date: Tue, 25 Feb 2025 11:00:47 +1000
Subject: [PATCH 3/4] Add support for lib

---
 .../ExperienceBuilder/ComponentSource/JsComponent.php |  1 +
 .../src/Kernel/DataType/ComponentTreeHydratedTest.php |  1 +
 ui/lib/astro-hydration/astro.config.mjs               | 11 +++++++++++
 ui/lib/astro-hydration/src/components/Stub.jsx        |  1 +
 ui/lib/astro-hydration/src/lib/utils.ts               |  7 +++++++
 ui/lib/astro-hydration/tsconfig.json                  |  5 ++++-
 ui/src/features/code-editor/Preview.tsx               |  1 +
 7 files changed, 26 insertions(+), 1 deletion(-)
 create mode 100644 ui/lib/astro-hydration/src/lib/utils.ts

diff --git a/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php b/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php
index da8a357c24..1c938b2601 100644
--- a/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php
+++ b/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php
@@ -120,6 +120,7 @@ final class JsComponent extends GeneratedFieldExplicitInputUxComponentSourceBase
         'clsx' => \sprintf('%s%s/ui/lib/astro-hydration/dist/clsx.js', $base_path, $xb_path),
         'class-variant-authority' => \sprintf('%s%s/ui/lib/astro-hydration/dist/class-variant-authority.js', $base_path, $xb_path),
         'tailwind-merge' => \sprintf('%s%s/ui/lib/astro-hydration/dist/tailwind-merge.js', $base_path, $xb_path),
+        '@/lib/utils' => \sprintf('%s%s/ui/lib/astro-hydration/dist/utils.js', $base_path, $xb_path),
       ],
       // @todo Rename plugin ID in https://www.drupal.org/project/experience_builder/issues/3502982
       '#component' => $this->configuration['plugin_id'],
diff --git a/tests/src/Kernel/DataType/ComponentTreeHydratedTest.php b/tests/src/Kernel/DataType/ComponentTreeHydratedTest.php
index 95d8d869ae..61899c3556 100644
--- a/tests/src/Kernel/DataType/ComponentTreeHydratedTest.php
+++ b/tests/src/Kernel/DataType/ComponentTreeHydratedTest.php
@@ -807,6 +807,7 @@ HTML,
                                 'clsx' => \sprintf('%s/ui/lib/astro-hydration/dist/clsx.js', $path),
                                 'class-variant-authority' => \sprintf('%s/ui/lib/astro-hydration/dist/class-variant-authority.js', $path),
                                 'tailwind-merge' => \sprintf('%s/ui/lib/astro-hydration/dist/tailwind-merge.js', $path),
+                                '@/lib/utils' => \sprintf('%s/ui/lib/astro-hydration/dist/utils.js', $path),
                               ],
                               '#component' => 'my-cta',
                               '#props' => [
diff --git a/ui/lib/astro-hydration/astro.config.mjs b/ui/lib/astro-hydration/astro.config.mjs
index 9439b87b27..fee0f554fe 100644
--- a/ui/lib/astro-hydration/astro.config.mjs
+++ b/ui/lib/astro-hydration/astro.config.mjs
@@ -1,11 +1,21 @@
 import { defineConfig } from 'astro/config';
 import preact from '@astrojs/preact';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
 
 // https://astro.build/config
 export default defineConfig({
   // Enable Preact to support Preact JSX components.
   integrations: [preact()],
   vite: {
+    resolve: {
+      alias: {
+        '@': path.resolve(__dirname, 'src/'),
+      },
+    },
     build: {
       rollupOptions: {
         output: {
@@ -18,6 +28,7 @@ export default defineConfig({
               clsx: 'clsx.js',
               'class-variance-authority': 'class-variance-authority.js',
               'tailwind-merge': 'tailwind-merge.js',
+              'lib/astro-hydration/src/lib/utils.ts': 'util.js',
             };
             return Object.entries(matches).reduce((carry, [key, value]) => {
               if (chunkInfo.facadeModuleId?.includes(`node_modules/${key}`)) {
diff --git a/ui/lib/astro-hydration/src/components/Stub.jsx b/ui/lib/astro-hydration/src/components/Stub.jsx
index 826b61d673..c9936f4173 100644
--- a/ui/lib/astro-hydration/src/components/Stub.jsx
+++ b/ui/lib/astro-hydration/src/components/Stub.jsx
@@ -11,5 +11,6 @@ const { jsx, jsxs, Fragment } = await import('preact/jsx-runtime');
 const { default: clsx } = await import('clsx');
 const { ...tailwindMerge } = await import('tailwind-merge');
 const { cva } = await import('class-variance-authority');
+const { cn } = await import('@/lib/utils');
 
 export default function () {}
diff --git a/ui/lib/astro-hydration/src/lib/utils.ts b/ui/lib/astro-hydration/src/lib/utils.ts
new file mode 100644
index 0000000000..b1ca34a146
--- /dev/null
+++ b/ui/lib/astro-hydration/src/lib/utils.ts
@@ -0,0 +1,7 @@
+import { clsx } from 'clsx';
+import { twMerge } from 'tailwind-merge';
+import type { ClassValue } from 'clsx';
+
+export function cn(...inputs: ClassValue[]) {
+  return twMerge(clsx(inputs));
+}
diff --git a/ui/lib/astro-hydration/tsconfig.json b/ui/lib/astro-hydration/tsconfig.json
index eb8b4ca6c2..e8e64a216c 100644
--- a/ui/lib/astro-hydration/tsconfig.json
+++ b/ui/lib/astro-hydration/tsconfig.json
@@ -10,6 +10,9 @@
   ],
   "compilerOptions": {
     "jsx": "react-jsx",
-    "jsxImportSource": "preact"
+    "jsxImportSource": "preact",
+    "paths": {
+      "@/*": ["src/*"],
+    }
   }
 }
diff --git a/ui/src/features/code-editor/Preview.tsx b/ui/src/features/code-editor/Preview.tsx
index 4131cf678d..ca347a373a 100644
--- a/ui/src/features/code-editor/Preview.tsx
+++ b/ui/src/features/code-editor/Preview.tsx
@@ -71,6 +71,7 @@ const importMap = {
     clsx: 'https://esm.sh/clsx',
     'class-variance-authority': 'https://esm.sh/class-variance-authority',
     'tailwind-merge': 'https://esm.sh/tailwind-merge',
+    '@/lib/utils': `${XB_MODULE_UI_PATH}/lib/astro-hydration/dist/utils.js`,
   },
 };
 
-- 
GitLab


From f7005901de54498f0ee11929def58f1f2c874e0b Mon Sep 17 00:00:00 2001
From: Balint Kleri <b@balintbrews.com>
Date: Tue, 25 Feb 2025 02:37:08 +0100
Subject: [PATCH 4/4] =?UTF-8?q?Fix=20typo:=20class-variant-authority=20?=
 =?UTF-8?q?=E2=86=92=20class-variance-authority?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php | 2 +-
 tests/src/Kernel/DataType/ComponentTreeHydratedTest.php      | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php b/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php
index 1c938b2601..4a42e40534 100644
--- a/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php
+++ b/src/Plugin/ExperienceBuilder/ComponentSource/JsComponent.php
@@ -118,7 +118,7 @@ final class JsComponent extends GeneratedFieldExplicitInputUxComponentSourceBase
         // @todo Remove this hard-coding and calculate it on a per component
         // basis - see https://drupal.org/i/3500761.
         'clsx' => \sprintf('%s%s/ui/lib/astro-hydration/dist/clsx.js', $base_path, $xb_path),
-        'class-variant-authority' => \sprintf('%s%s/ui/lib/astro-hydration/dist/class-variant-authority.js', $base_path, $xb_path),
+        'class-variance-authority' => \sprintf('%s%s/ui/lib/astro-hydration/dist/class-variance-authority.js', $base_path, $xb_path),
         'tailwind-merge' => \sprintf('%s%s/ui/lib/astro-hydration/dist/tailwind-merge.js', $base_path, $xb_path),
         '@/lib/utils' => \sprintf('%s%s/ui/lib/astro-hydration/dist/utils.js', $base_path, $xb_path),
       ],
diff --git a/tests/src/Kernel/DataType/ComponentTreeHydratedTest.php b/tests/src/Kernel/DataType/ComponentTreeHydratedTest.php
index 61899c3556..5f5dce771f 100644
--- a/tests/src/Kernel/DataType/ComponentTreeHydratedTest.php
+++ b/tests/src/Kernel/DataType/ComponentTreeHydratedTest.php
@@ -805,7 +805,7 @@ HTML,
                                 'preact/hooks' => \sprintf('%s/ui/lib/astro-hydration/dist/hooks.module.js', $path),
                                 'react/jsx-runtime' => \sprintf('%s/ui/lib/astro-hydration/dist/jsxRuntime.module.js', $path),
                                 'clsx' => \sprintf('%s/ui/lib/astro-hydration/dist/clsx.js', $path),
-                                'class-variant-authority' => \sprintf('%s/ui/lib/astro-hydration/dist/class-variant-authority.js', $path),
+                                'class-variance-authority' => \sprintf('%s/ui/lib/astro-hydration/dist/class-variance-authority.js', $path),
                                 'tailwind-merge' => \sprintf('%s/ui/lib/astro-hydration/dist/tailwind-merge.js', $path),
                                 '@/lib/utils' => \sprintf('%s/ui/lib/astro-hydration/dist/utils.js', $path),
                               ],
-- 
GitLab