Repository: SRGSSR/pillarbox-web-suite
Pull request #48: chore(create): generate umd build
Author: login: jboix
Labels: name: released
Created: 2025-05-01T14:20:43Z | Merged: 2025-05-02T14:15:13Z

## Description

New and old components can now be loaded via a CDN (e.g., jsDelivr) using a simple <script> tag, enabling easier integration in external projects.

This PR makes sure that all new an existing UMD builds use the common babel configuration to align the compatibility requirements to those of the pillarbox-web player.

## Changes Made

- Added UMD build generation for new components.
- `pillarbox-debug-panel`: add specific browser export property to the package.json.
- `user-preferences`: align browser compatibility with Bable for the UMD build.
- Add a UMD build for both the `pillarbox-playlist` plugin and the `skip-button` component. An additional `ui` specific 
  build has been added to the pillarox-playlist plugin since this plugin allows to integration without the visual component.

## Checklist

- [x] I have followed the project's style and contribution guidelines.
- [x] I have performed a self-review of my own changes.
- [x] I have made corresponding changes to the documentation.
- [x] I have added tests that prove my fix is effective or that my feature works.



Diff:
diff --git a/packages/pillarbox-debug-panel/package.json b/packages/pillarbox-debug-panel/package.json
index cb7081f..4ba7f4b 100644
--- a/packages/pillarbox-debug-panel/package.json
+++ b/packages/pillarbox-debug-panel/package.json
@@ -13,6 +13,7 @@
   "homepage": "https://github.com/SRGSSR/pillarbox-web-suite/tree/main/packages/pillarbox-debug-panel#readme",
   "type": "module",
   "main": "dist/pillarbox-debug-panel.cjs",
+  "browser": "dist/pillarbox-debug-panel.umd.min.js",
   "module": "dist/pillarbox-debug-panel.js",
   "style": "./dist/pillarbox-debug-panel.min.css",
   "exports": {
diff --git a/packages/pillarbox-debug-panel/vite.config.umd.js b/packages/pillarbox-debug-panel/vite.config.umd.js
index 60d9adf..bc03bff 100644
--- a/packages/pillarbox-debug-panel/vite.config.umd.js
+++ b/packages/pillarbox-debug-panel/vite.config.umd.js
@@ -3,11 +3,10 @@ import babel from '@rollup/plugin-babel';
 import terser from '@rollup/plugin-terser';
 
 /**
- * Vite's configuration for the lib build.
+ * Vite's configuration for the UMD build.
  *
  * Outputs:
- * - 'dist/pillarbox-debug-panel.js': ESModule version with sourcemaps.
- * - 'dist/pillarbox-debug-panel.cjs': CommonJS version with sourcemaps.
+ * - 'dist/pillarbox-debug-panel.umd.min.js': Universal Module Definition version.
  */
 export default defineConfig({
   esbuild: false,
@@ -20,12 +19,14 @@ export default defineConfig({
       entry: 'src/pillarbox-debug-panel.js'
     },
     rollupOptions: {
-      external: ['video.js'],
       output: {
+        name: 'PillarboxDebugPanel',
+        entryFileNames: 'pillarbox-debug.umd.min.js',
         globals: {
-          'video.js': 'videojs'
-        }
+          videojs: 'videojs',
+        },
       },
+      external: ['video.js'],
       plugins: [
         babel({
           babelHelpers: 'bundled',
diff --git a/packages/pillarbox-playlist/package.json b/packages/pillarbox-playlist/package.json
index d3e5b63..26cefc7 100644
--- a/packages/pillarbox-playlist/package.json
+++ b/packages/pillarbox-playlist/package.json
@@ -14,6 +14,7 @@
   "homepage": "https://github.com/SRGSSR/pillarbox-web-suite/tree/main/packages/pillarbox-playlist#readme",
   "type": "module",
   "main": "dist/pillarbox-playlist.cjs",
+  "browser": "dist/pillarbox-playlist.umd.min.js",
   "module": "dist/pillarbox-playlist.js",
   "style": "./dist/pillarbox-playlist.min.css",
   "exports": {
@@ -39,9 +40,11 @@
     "playlist"
   ],
   "scripts": {
-    "build": "npm run build:lib && npm run build:ui && npm run build:css",
+    "build": "npm run build:lib && npm run build:ui && npm run build:umd && npm run build:umd:ui && npm run build:css",
     "build:css": "sass ./scss/pillarbox-playlist.scss:dist/pillarbox-playlist.min.css --style compressed --source-map --load-path node_modules",
     "build:lib": "vite build --config vite.config.lib.js",
+    "build:umd": "vite build --config vite.config.umd.js",
+    "build:umd:ui": "vite build --config vite.config.umd.ui.js",
     "build:ui": "vite build --config vite.config.ui.js",
     "github:page": "vite build",
     "release:ci": "semantic-release",
diff --git a/packages/pillarbox-playlist/vite.config.ui.js b/packages/pillarbox-playlist/vite.config.ui.js
index 0e9515f..c686c44 100644
--- a/packages/pillarbox-playlist/vite.config.ui.js
+++ b/packages/pillarbox-playlist/vite.config.ui.js
@@ -3,11 +3,11 @@ import babel from '@rollup/plugin-babel';
 import copy from 'rollup-plugin-copy';
 
 /**
- * Vite's configuration for the lib build.
+ * Vite's configuration for the ui build.
  *
  * Outputs:
- * - 'dist/pillarbox-playlist-ui.js': ESModule version with sourcemaps.
- * - 'dist/pillarbox-playlist-ui.cjs': CommonJS version with sourcemaps.
+ * - 'dist/ui/pillarbox-playlist-ui.js': ESModule version with sourcemaps.
+ * - 'dist/ui/pillarbox-playlist-ui.cjs': CommonJS version with sourcemaps.
  */
 export default defineConfig({
   esbuild: false,
diff --git a/packages/pillarbox-playlist/vite.config.umd.js b/packages/pillarbox-playlist/vite.config.umd.js
new file mode 100644
index 0000000..287ce23
--- /dev/null
+++ b/packages/pillarbox-playlist/vite.config.umd.js
@@ -0,0 +1,39 @@
+import { defineConfig } from 'vite';
+import babel from '@rollup/plugin-babel';
+import terser from '@rollup/plugin-terser';
+
+/**
+ * Vite's configuration for the umd build.
+ *
+ * Outputs:
+ * - 'dist/pillarbox-playlist.umd.min.js': Universal Module Definition version.
+ */
+export default defineConfig({
+  esbuild: false,
+  build: {
+    emptyOutDir: false,
+    sourcemap: true,
+    lib: {
+      formats: ['umd'],
+      name: 'PillarboxPlaylist',
+      entry: 'src/pillarbox-playlist.js'
+    },
+    rollupOptions: {
+      output: {
+        name: 'PillarboxPlaylist',
+        entryFileNames: 'pillarbox-playlist.umd.min.js',
+        globals: {
+          videojs: 'videojs'
+        },
+      },
+      external: ['video.js'],
+      plugins: [
+        babel({
+          babelHelpers: 'bundled',
+          exclude: 'node_modules/**'
+        }),
+        terser()
+      ]
+    },
+  },
+});
diff --git a/packages/pillarbox-playlist/vite.config.umd.ui.js b/packages/pillarbox-playlist/vite.config.umd.ui.js
new file mode 100644
index 0000000..83f893c
--- /dev/null
+++ b/packages/pillarbox-playlist/vite.config.umd.ui.js
@@ -0,0 +1,40 @@
+import { defineConfig } from 'vite';
+import babel from '@rollup/plugin-babel';
+import terser from '@rollup/plugin-terser';
+
+/**
+ * Vite's configuration for the umd UI build.
+ *
+ * Outputs:
+ * - 'dist/ui/pillarbox-playlist-ui.umd.min.js': Universal Module Definition version.
+ */
+export default defineConfig({
+  esbuild: false,
+  build: {
+    outDir: 'dist/ui',
+    emptyOutDir: false,
+    sourcemap: true,
+    lib: {
+      formats: ['umd'],
+      name: 'PillarboxPlaylistUI',
+      entry: 'src/pillarbox-playlist-ui.js'
+    },
+    rollupOptions: {
+      output: {
+        name: 'PillarboxPlaylistUI',
+        entryFileNames: 'pillarbox-playlist-ui.umd.min.js',
+        globals: {
+          videojs: 'videojs'
+        },
+      },
+      external: ['video.js'],
+      plugins: [
+        babel({
+          babelHelpers: 'bundled',
+          exclude: 'node_modules/**'
+        }),
+        terser()
+      ]
+    },
+  },
+});
diff --git a/packages/skip-button/package.json b/packages/skip-button/package.json
index 8a5ad7c..03d45da 100644
--- a/packages/skip-button/package.json
+++ b/packages/skip-button/package.json
@@ -14,6 +14,7 @@
   "homepage": "https://github.com/SRGSSR/pillarbox-web-suite/tree/main/packages/skip-button#readme",
   "type": "module",
   "main": "dist/skip-button.cjs",
+  "browser": "dist/skip-button.umd.min.js",
   "module": "dist/skip-button.js",
   "style": "./dist/skip-button.min.css",
   "exports": {
@@ -35,10 +36,10 @@
     "skip-button"
   ],
   "scripts": {
-    "build": "npm run build:lib && npm run build:css",
+    "build": "npm run build:lib && npm run build:umd && npm run build:css",
     "build:css": "sass ./scss/skip-button.scss:dist/skip-button.min.css --style compressed --source-map --load-path node_modules",
     "build:lib": "vite build --config vite.config.lib.js",
-    "build:ui": "vite build --config vite.config.ui.js",
+    "build:umd": "vite build --config vite.config.umd.js",
     "github:page": "vite build",
     "release:ci": "semantic-release",
     "start": " vite --port 4200 --open",
diff --git a/packages/skip-button/vite.config.umd.js b/packages/skip-button/vite.config.umd.js
new file mode 100644
index 0000000..4b0869f
--- /dev/null
+++ b/packages/skip-button/vite.config.umd.js
@@ -0,0 +1,39 @@
+import { defineConfig } from 'vite';
+import babel from '@rollup/plugin-babel';
+import terser from '@rollup/plugin-terser';
+
+/**
+ * Vite's configuration for the umd build.
+ *
+ * Outputs:
+ * - 'dist/skip-button.umd.min.js': Universal Module Definition version.
+ */
+export default defineConfig({
+  esbuild: false,
+  build: {
+    emptyOutDir: false,
+    sourcemap: true,
+    lib: {
+      formats: ['umd'],
+      name: 'SkipButton',
+      entry: 'src/skip-button.js'
+    },
+    rollupOptions: {
+      output: {
+        name: 'SkipButton',
+        entryFileNames: 'skip-button.umd.min.js',
+        globals: {
+          pillarbox: 'pillarbox'
+        },
+      },
+      external: ['@srgssr/pillarbox-web'],
+      plugins: [
+        babel({
+          babelHelpers: 'bundled',
+          exclude: 'node_modules/**'
+        }),
+        terser()
+      ]
+    },
+  },
+});
diff --git a/packages/user-preferences/vite.config.umd.js b/packages/user-preferences/vite.config.umd.js
index fa8c983..134c4d8 100644
--- a/packages/user-preferences/vite.config.umd.js
+++ b/packages/user-preferences/vite.config.umd.js
@@ -1,4 +1,6 @@
 import { defineConfig } from 'vite';
+import babel from '@rollup/plugin-babel';
+import terser from '@rollup/plugin-terser';
 
 /**
  * Vite's configuration for the umd build.
@@ -7,6 +9,7 @@ import { defineConfig } from 'vite';
  * - 'dist/user-preferences.umd.min.js': Universal Module Definition version.
  */
 export default defineConfig({
+  esbuild: false,
   build: {
     emptyOutDir: false,
     sourcemap: true,
@@ -24,6 +27,13 @@ export default defineConfig({
         },
       },
       external: ['video.js'],
+      plugins: [
+        babel({
+          babelHelpers: 'bundled',
+          exclude: 'node_modules/**'
+        }),
+        terser()
+      ]
     },
   },
 });
diff --git a/scripts/template/package.json.hbs b/scripts/template/package.json.hbs
index e3948e7..52c8fff 100644
--- a/scripts/template/package.json.hbs
+++ b/scripts/template/package.json.hbs
@@ -13,6 +13,7 @@
   "homepage": "https://github.com/SRGSSR/pillarbox-web-suite/tree/main/packages/{{kebabCase name}}#readme",
   "type": "module",
   "main": "dist/{{kebabCase name}}.cjs",
+  "browser": "dist/{{kebabCase name}}.umd.min.js",
   "module": "dist/{{kebabCase name}}.js",{{#if wantScss}}
   "style": "./dist/{{kebabCase name}}.min.css",{{/if}}
   "exports": {
@@ -34,9 +35,10 @@
     "pillarbox-plugin"{{/ifEq}}{{/ifEq}}
   ],
   "scripts": {
-    "build": "npm run build:lib{{#if wantScss}} && npm run build:css{{/if}}",{{#if wantScss}}
+    "build": "npm run build:lib && npm run build:umd{{#if wantScss}} && npm run build:css{{/if}}",{{#if wantScss}}
     "build:css": "sass ./scss/{{kebabCase name}}.scss:dist/{{kebabCase name}}.min.css --style compressed --source-map --load-path node_modules",{{/if}}
     "build:lib": "vite build --config vite.config.lib.js",
+    "build:umd": "vite build --config vite.config.umd.js",
     "github:page": "vite build",
     "release:ci": "semantic-release",
     "start": " vite --port 4200 --open",
diff --git a/scripts/template/vite.config.umd.js.hbs b/scripts/template/vite.config.umd.js.hbs
new file mode 100644
index 0000000..39954a8
--- /dev/null
+++ b/scripts/template/vite.config.umd.js.hbs
@@ -0,0 +1,39 @@
+import { defineConfig } from 'vite';
+import babel from '@rollup/plugin-babel';
+import terser from '@rollup/plugin-terser';
+
+/**
+ * Vite's configuration for the umd build.
+ *
+ * Outputs:
+ * - 'dist/{{kebabCase name}}.umd.min.js': Universal Module Definition version.
+ */
+export default defineConfig({
+  esbuild: false,
+  build: {
+    emptyOutDir: false,
+    sourcemap: true,
+    lib: {
+      formats: ['umd'],
+      name: '{{properCase name}}',
+      entry: 'src/{{kebabCase name}}.js'
+    },
+    rollupOptions: {
+      output: {
+        name: '{{properCase name}}',
+        entryFileNames: '{{kebabCase name}}.umd.min.js',
+        globals: {
+          {{platform}}: '{{platform}}',
+        },
+      },
+      external: ['{{importAlias}}'],
+      plugins: [
+        babel({
+          babelHelpers: 'bundled',
+          exclude: 'node_modules/**'
+        }),
+        terser()
+      ],
+    },
+  },
+});


Reviews:
user: login: amtins
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T08:25:59Z
user: login: amtins
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T08:34:22Z
user: login: jboix
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T14:00:58Z
user: login: jboix
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-02T14:04:01Z
user: login: amtins
body: LGTM!
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-02T14:06:50Z

Review comments:
diff_hunk: @@ -3,11 +3,10 @@ import babel from '@rollup/plugin-babel';
 import terser from '@rollup/plugin-terser';
 
 /**
- * Vite's configuration for the lib build.
+ * Vite's configuration for the UMD build.
  *
  * Outputs:
- * - 'dist/pillarbox-debug-panel.js': ESModule version with sourcemaps.
- * - 'dist/pillarbox-debug-panel.cjs': CommonJS version with sourcemaps.
+ * - 'dist/pillarbox-debug-panel.umd.min.js': ESModule version with sourcemaps.
path: packages/pillarbox-debug-panel/vite.config.umd.js
user: login: amtins
body: `UMD` instead of `ESModule`?
created_at: 2025-05-02T08:25:59Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,40 @@
+import { defineConfig } from 'vite';
+import babel from '@rollup/plugin-babel';
+import terser from '@rollup/plugin-terser';
+
+/**
+ * Vite's configuration for the umd UI build.
+ *
+ * Outputs:
+ * - 'dist/ui/pillarbox-playlist-ui.umd.min.js': Universal Module Definition version.
+ */
+export default defineConfig({
+  esbuild: false,
+  build: {
+    outDir: 'dist/ui',
path: packages/pillarbox-playlist/vite.config.umd.ui.js
user: login: amtins
body: Quick question. Why `dist/ui` and not `dist` since the file output file will contain **pillarbox-playlist-`ui`.umd.min.js**?
created_at: 2025-05-02T08:34:22Z
author_association: MEMBER
diff_hunk: @@ -3,11 +3,10 @@ import babel from '@rollup/plugin-babel';
 import terser from '@rollup/plugin-terser';
 
 /**
- * Vite's configuration for the lib build.
+ * Vite's configuration for the UMD build.
  *
  * Outputs:
- * - 'dist/pillarbox-debug-panel.js': ESModule version with sourcemaps.
- * - 'dist/pillarbox-debug-panel.cjs': CommonJS version with sourcemaps.
+ * - 'dist/pillarbox-debug-panel.umd.min.js': ESModule version with sourcemaps.
path: packages/pillarbox-debug-panel/vite.config.umd.js
user: login: jboix
body: Fixed.
created_at: 2025-05-02T14:00:58Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,40 @@
+import { defineConfig } from 'vite';
+import babel from '@rollup/plugin-babel';
+import terser from '@rollup/plugin-terser';
+
+/**
+ * Vite's configuration for the umd UI build.
+ *
+ * Outputs:
+ * - 'dist/ui/pillarbox-playlist-ui.umd.min.js': Universal Module Definition version.
+ */
+export default defineConfig({
+  esbuild: false,
+  build: {
+    outDir: 'dist/ui',
path: packages/pillarbox-playlist/vite.config.umd.ui.js
user: login: jboix
body: There was a prexisting ui distribution folder to facilitate importing with this mapping:

https://github.com/SRGSSR/pillarbox-web-suite/blob/d7323ba06568481cde3839b052f518eae255f159/packages/pillarbox-playlist/package.json#L25-L28

Which allows to import the module like this: `import '@srgssr/pillarbox-playlist/ui';`

Since the folder was already there I thought it made sense to bundle the UMD build there as well to keep things together, technically it could be in the root `dist` folder.
created_at: 2025-05-02T14:04:01Z
author_association: MEMBER

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-01T14:21:23Z
body: <h2>Coverage Report</h2>
<table> <thead> <tr> <th align="center">Status</th> <th align="left">Category</th> <th align="right">Percentage</th> <th align="right">Covered / Total</th> </tr> </thead> <tbody> <tr> <td align="center">🔵</td> <td align="left">Lines</td> <td align="right">98.91%</td> <td align="right">2004 / 2026</td> </tr> <tr> <td align="center">🔵</td> <td align="left">Statements</td> <td align="right">98.91%</td> <td align="right">2004 / 2026</td> </tr> <tr> <td align="center">🔵</td> <td align="left">Functions</td> <td align="right">96.37%</td> <td align="right">133 / 138</td> </tr> <tr> <td align="center">🔵</td> <td align="left">Branches</td> <td align="right">89.25%</td> <td align="right">216 / 242</td> </tr> </tbody> </table><details><summary>File Coverage</summary>No changed files found.</details>
<em>Generated in workflow <a href=https://github.com/SRGSSR/pillarbox-web-suite/actions/runs/14796773293>#127</a> for commit <a href="https://github.com/SRGSSR/pillarbox-web-suite/commit/36030ab96fbebe9bfaf9e773f91bbfb22ab1c389">36030ab</a> by the <a href="https://github.com/davelosert/vitest-coverage-report-action">Vitest Coverage Report Action</a></em>

<!-- vitest-coverage-report-marker-root -->
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-01T14:21:26Z
body: [PR Preview Action](https://github.com/rossjrw/pr-preview-action) v1.6.1
:---:
Preview removed because the pull request was closed.
2025-05-02 14:15 UTC
<!-- Sticky Pull Request Commentpr-preview -->
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-02T14:16:23Z
body: :tada: This PR is included in version @srgssr/pillarbox-debug-panel-v1.1.0 :tada:

The release is available on:
- [npm package (@latest dist-tag)](https://www.npmjs.com/package/@srgssr/pillarbox-debug-panel/v/1.1.0)
- [GitHub release](https://github.com/SRGSSR/pillarbox-web-suite/releases/tag/%40srgssr/pillarbox-debug-panel-v1.1.0)

Your **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package::rocket:
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-02T14:17:06Z
body: :tada: This PR is included in version @srgssr/pillarbox-playlist-v2.2.0 :tada:

The release is available on:
- [npm package (@latest dist-tag)](https://www.npmjs.com/package/@srgssr/pillarbox-playlist/v/2.2.0)
- [GitHub release](https://github.com/SRGSSR/pillarbox-web-suite/releases/tag/%40srgssr/pillarbox-playlist-v2.2.0)

Your **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package::rocket:
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-02T14:17:41Z
body: :tada: This PR is included in version @srgssr/skip-button-v1.1.0 :tada:

The release is available on:
- [npm package (@latest dist-tag)](https://www.npmjs.com/package/@srgssr/skip-button/v/1.1.0)
- [GitHub release](https://github.com/SRGSSR/pillarbox-web-suite/releases/tag/%40srgssr/skip-button-v1.1.0)

Your **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package::rocket:
author_association: NONE