diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7681178b..d7baba77 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,7 @@
-### v2.1.17 (not yet released)
+### v2.1.17 (2024-08-12)
 #### Improvements
+- Removed dependency of 'clipboard-polyfill'. The clipboard API is now supported in all browsers.
+- Reincorporation of `webpack-node-externals`, which is used when building the nodeJS package.
 - Upgraded dependencies
 
 ### v2.1.16 (2023-12-12)
diff --git a/README.md b/README.md
index c9223cfe..fb59909a 100644
--- a/README.md
+++ b/README.md
@@ -64,7 +64,6 @@ The latest version of the compiled and minified script `jclic.min.js` is current
 JClic.js makes use of:
 * [jQuery](https://jquery.com/) to parse XML documents and manage DOM objects
 * [JSZip](https://stuk.github.io/jszip/) to extract contents from "jclic.zip" files
-* [clipboard-polyfill](https://github.com/lgarron/clipboard-polyfill) to copy reports data into the user's clipboard
 * [script.js](https://github.com/ded/script.js) to read JClic projects from local file systems as JSONP
 * [webfontloader](https://github.com/typekit/webfontloader) to dynamically load web fonts as needed
 * [MidiPlayerJS](https://github.com/grimmdude/MidiPlayerJS), [soundfont-player](https://github.com/danigb/soundfont-player), [audio-loader](https://github.com/audiojs/audio-loader) and [sample-player](https://github.com/danigb/sample-player) to process and play MIDI files
diff --git a/package-lock.json b/package-lock.json
index df66193a..54fef077 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,7 +22,6 @@
         "@xmldom/xmldom": "^0.9.1",
         "babel-loader": "^9.1.3",
         "clean-jsdoc-theme": "^4.3.0",
-        "clipboard-polyfill": "^4.1.0",
         "eslint": "^8.57.0",
         "eslint-webpack-plugin": "^4.2.0",
         "fs-extra": "^11.2.0",
@@ -33,7 +32,8 @@
         "terser-webpack-plugin": "^5.3.10",
         "webpack": "^5.94.0",
         "webpack-cli": "^5.1.4",
-        "webpack-dev-server": "^5.1.0"
+        "webpack-dev-server": "^5.1.0",
+        "webpack-node-externals": "^3.0.0"
       }
     },
     "node_modules/@aashutoshrathi/word-wrap": {
@@ -3343,12 +3343,6 @@
         "node": ">=12"
       }
     },
-    "node_modules/clipboard-polyfill": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/clipboard-polyfill/-/clipboard-polyfill-4.1.0.tgz",
-      "integrity": "sha512-ksMESxI9ermQxE3hOC4DGwfjmrAxuHVtwQoJMsy06ylpaY4ybISb6y21yJ17xg9EO9ZVWvzSLIkJRlO93E8Gng==",
-      "dev": true
-    },
     "node_modules/clone-deep": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
@@ -4507,20 +4501,6 @@
       "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
       "dev": true
     },
-    "node_modules/fsevents": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
-      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
-      "dev": true,
-      "hasInstallScript": true,
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
-      }
-    },
     "node_modules/function-bind": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -8239,6 +8219,16 @@
         "node": ">=10.0.0"
       }
     },
+    "node_modules/webpack-node-externals": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz",
+      "integrity": "sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/webpack-sources": {
       "version": "3.2.3",
       "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
diff --git a/package.json b/package.json
index 1c03fa31..31c4c00f 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,6 @@
     "@xmldom/xmldom": "^0.9.1",
     "babel-loader": "^9.1.3",
     "clean-jsdoc-theme": "^4.3.0",
-    "clipboard-polyfill": "^4.1.0",
     "eslint": "^8.57.0",
     "eslint-webpack-plugin": "^4.2.0",
     "fs-extra": "^11.2.0",
@@ -70,7 +69,8 @@
     "terser-webpack-plugin": "^5.3.10",
     "webpack": "^5.94.0",
     "webpack-cli": "^5.1.4",
-    "webpack-dev-server": "^5.1.0"
+    "webpack-dev-server": "^5.1.0",
+    "webpack-node-externals": "^3.0.0"
   },
   "scripts": {
     "prebuild": "patch-package",
diff --git a/src/Utils.js b/src/Utils.js
index 347421da..44b41b94 100644
--- a/src/Utils.js
+++ b/src/Utils.js
@@ -32,26 +32,19 @@
 /* global Promise, window, document, console, HTMLElement */
 
 import $ from 'jquery';
-import * as clipboard from 'clipboard-polyfill';
 import JSZip from 'jszip';
 import JSZipUtils from 'jszip-utils';
-import WebFont from 'webfontloader';
 import GlobalData from './GlobalData';
 
 /**
  * Exports third-party NPM packages used by JClic, so they become available to other scripts through
  * the global variable `JClicObject` (defined in {@link module:JClic.JClic})
- * @example <caption>Example usage of JSZip through JClicObject</caption>
- * var WebFont = window.JClicObject.Utils.pkg.WebFont;
- * WebFont.load({google: {families: ['Roboto']}});
  * @type: {object}
  */
 export const pkg = {
-  clipboard,
   $,
   JSZip,
   JSZipUtils,
-  WebFont,
 };
 
 /**
@@ -1175,7 +1168,7 @@ export const settings = {
   // JClic.js Version
   VERSION: GlobalData.version,
   // Check if we are running on NodeJS with JSDOM
-  NODEJS: window.navigator.userAgent.includes('jsdom'),
+  NODEJS: typeof window === 'undefined' || window?.navigator?.userAgent?.includes('jsdom'),
   // layout constants
   AB: 0, BA: 1, AUB: 2, BUA: 3,
   LAYOUT_NAMES: ['AB', 'BA', 'AUB', 'BUA'],
@@ -1280,7 +1273,7 @@ export const settings = {
   // CANVAS_HITREGIONS: typeof CanvasRenderingContext2D !== 'undefined' && typeof CanvasRenderingContext2D.prototype.addHitRegion === 'function',
   // CANVAS_HITREGIONS_FOCUS: typeof CanvasRenderingContext2D !== 'undefined' && typeof CanvasRenderingContext2D.prototype.drawFocusIfNeeded === 'function',
   //
-  CANVAS_DRAW_FOCUS: typeof window.CanvasRenderingContext2D !== 'undefined' && typeof window.CanvasRenderingContext2D.prototype.drawFocusIfNeeded === 'function',
+  CANVAS_DRAW_FOCUS: typeof window !== 'undefined' && typeof window?.CanvasRenderingContext2D?.prototype?.drawFocusIfNeeded === 'function',
   // See: https://emptycharacter.com/
   // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
   WHITESPACES: '  \f\n\r\t\v\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202f\u205f\u3000\ufeff',
diff --git a/src/skins/Skin.js b/src/skins/Skin.js
index 80075a3e..8cec2ce4 100644
--- a/src/skins/Skin.js
+++ b/src/skins/Skin.js
@@ -29,10 +29,9 @@
  *  @module
  */
 
-/* global Promise, window, document */
+/* global Promise, window, document, navigator, ClipboardItem, Blob */
 
 import $ from 'jquery';
-import * as clipboard from 'clipboard-polyfill';
 import { appendStyleAtHead, cloneObject, getMsg, setLogLevel, log, getRootHead, toCssSize, $HTML, getPercent, getHMStime, settings } from '../Utils';
 import { Container, Dimension, Rectangle } from '../AWT';
 
@@ -173,11 +172,11 @@ export class Skin extends Container {
     this.$copyBtn = $('<button/>', { title: msg, 'aria-label': msg })
       .append($(this.copyIcon).css({ width: '26px', height: '26px' }))
       .on('click', () => {
-        const item = new clipboard.ClipboardItem({
-          'text/plain': `===> ${getMsg('The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor')} <===`,
-          'text/html': this.$reportsPanel.html(),
+        const item = new ClipboardItem({
+          'text/plain': new Blob([`===> ${getMsg('The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor')} <===`], {type: 'text/plain'}),
+          'text/html': new Blob([this.$reportsPanel.html()], {type: 'text/html'}),
         });
-        clipboard.write([item])
+        navigator.clipboard.write([item])
           .then(() => this.$copyBtn.parent().append(
             $('<div/>', { class: 'smallPopup' })
               .html(getMsg('The data has been copied to clipboard'))
diff --git a/webpack.config.js b/webpack.config.js
index 7c58f301..08c3c7af 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -2,6 +2,7 @@
 
 const TerserPlugin = require('terser-webpack-plugin');
 const ESLintPlugin = require('eslint-webpack-plugin');
+const nodeExternals = require('webpack-node-externals');
 const path = require('path');
 const pkg = require('./package.json');
 const buildLocales = require('./build-locales');
@@ -137,6 +138,7 @@ const mainConfig = {
 const nodeConfig = {
   target: 'node',
   mode: 'production',
+  externals: [nodeExternals()],
   entry: './src/JClic.js',
   module: {
     rules: [...assetRules],