diff --git a/srcts/TODO.md b/srcts/TODO.md
index dbe275f1..e36ced9e 100644
--- a/srcts/TODO.md
+++ b/srcts/TODO.md
@@ -36,6 +36,7 @@
   * √ Verify it works on phantomjs / shinytest
 * √ Set up initial jest tests
 * √ Use a global shim to avoid importing jquery directly, but make testing easy to test
+* √ Use yarn PnP
 
 # Later TODO
 
@@ -49,12 +50,3 @@
 * Completely remove `parcel` from `./package.json` and only use `esbuild`
 * Delete 'shiny-es5' files
 * Delete 'old' folder
-
-
-# Eventual TODO
-* Use yarn PnP
-  * Use [esbuild](https://github.com/yarnpkg/berry/tree/master/packages/esbuild-plugin-pnp#yarnpkgesbuild-plugin-pnp)
-  * Remove `./.yarnrc.yaml` `nodeLinker` key
-  * TODO - Figure out how to call the esbuild command with the missing packages. Currently Yarn can't ifnd `esbuild` and suggests `esbuild-X.Y.Z-SHA` (or something other than `esbuild`) which does not make sense.
-    * Calling `yarn node esbuild.config.mjs` does not work
-    * Calling `yarn pnpify node esbuild.config.mjs` does not work
diff --git a/srcts/esbuild.config.js b/srcts/esbuild.config.js
new file mode 100644
index 00000000..8e4a0801
--- /dev/null
+++ b/srcts/esbuild.config.js
@@ -0,0 +1,54 @@
+/* eslint-disable no-undef */
+/* eslint-disable @typescript-eslint/no-var-requires */
+
+// !! Do not convert this file to a module (aka using `import` statements) as VSCode suggests to do
+// Yarn shims the `require` function to make PnP work. It does not work on import statements
+
+const esbuild = require("esbuild");
+const babel = require("esbuild-plugin-babel");
+const readcontrol = require("readcontrol");
+const pnpPlugin = require("esbuild-plugin-pnp");
+const process = require("process");
+const globalsPlugin = require("esbuild-plugin-globals");
+
+let watch = process.argv.length >= 3 && process.argv[2] == "--watch";
+
+let outdir = "../inst/www/shared/";
+let opts = {
+  entryPoints: ["src/index.ts"],
+  bundle: true,
+  watch: watch,
+  plugins: [
+    globalsPlugin({
+      jquery: "window.jQuery",
+    }),
+    pnpPlugin(),
+    babel(),
+  ],
+  target: "es5",
+  sourcemap: true,
+  define: {
+    "process.env.SHINY_VERSION": `"${
+      readcontrol.readSync("../DESCRIPTION").version
+    }"`,
+  },
+};
+
+console.log("Building shiny.js");
+esbuild
+  .build({
+    ...opts,
+    outfile: outdir + "shiny.js",
+  })
+  .then(() => {
+    console.log("Building shiny.min.js");
+    esbuild.build({
+      ...opts,
+      outfile: outdir + "shiny.min.js",
+      minify: true,
+    });
+  })
+  .catch((reason) => {
+    console.error(reason);
+    process.exit(1);
+  });
diff --git a/srcts/esbuild.config.mjs b/srcts/esbuild.config.mjs
deleted file mode 100644
index ffdb855b..00000000
--- a/srcts/esbuild.config.mjs
+++ /dev/null
@@ -1,40 +0,0 @@
-import esbuild from "esbuild";
-import babel from "esbuild-plugin-babel";
-import readcontrol from "readcontrol";
-import process from "process";
-import globalsPlugin from "esbuild-plugin-globals";
-
-let watch = process.argv.length >= 3 && process.argv[2] == "--watch";
-
-let outdir = "../inst/www/shared/";
-let opts = {
-  entryPoints: ["src/index.ts"],
-  bundle: true,
-  watch: watch,
-  plugins: [
-    globalsPlugin({
-      jquery: "window.jQuery",
-    }),
-    babel(),
-  ],
-  target: "es5",
-  sourcemap: true,
-  define: {
-    "process.env.SHINY_VERSION": `"${
-      readcontrol.readSync("../DESCRIPTION").version
-    }"`,
-  },
-};
-
-console.log("Building shiny.js");
-await esbuild.build({
-  ...opts,
-  outfile: outdir + "shiny.js",
-});
-
-console.log("Building shiny.min.js");
-await esbuild.build({
-  ...opts,
-  outfile: outdir + "shiny.min.js",
-  minify: true,
-});
diff --git a/srcts/package.json b/srcts/package.json
index c7f6b66b..edff5ce9 100644
--- a/srcts/package.json
+++ b/srcts/package.json
@@ -21,8 +21,9 @@
     "@typescript-eslint/parser": "^4",
     "browserslist": "^4.16.3",
     "esbuild": "^0.8.50",
-    "esbuild-plugin-babel": "0.2.3",
+    "esbuild-plugin-babel": "patch:esbuild-plugin-babel@0.2.3#./patch/esbuild-plugin-babel.patch",
     "esbuild-plugin-globals": "^0.1.1",
+    "esbuild-plugin-pnp": "^0.3.0",
     "eslint": "^7",
     "eslint-config-prettier": "^7",
     "eslint-plugin-jest": "^24",
@@ -45,7 +46,7 @@
     "build": "yarn run build_shiny",
     "setup_build_shiny": "yarn run lint && yarn run typescript-check",
     "build_shiny": "yarn run setup_build_shiny && yarn run bundle_shiny",
-    "bundle_shiny": "node esbuild.config.mjs",
+    "bundle_shiny": "node esbuild.config.js",
     "bundle_shiny_parcel2": "parcel build -d ../inst/www/shared --no-minify -o shiny.js src/index.ts",
     "watch_parcel2": "yarn run setup_build_shiny && parcel run -d ../inst/www/shared -o shiny.js srcjs/index.ts",
     "replace_shiny_version2": "replace --silent '\"[^\"]+\"; // @VERSION@' \"\\\"`node -e 'console.log(require(\"readcontrol\").readSync(\"../DESCRIPTION\").version)'`\\\"; // @VERSION@\" src/shiny.ts",
diff --git a/srcts/patch/esbuild-plugin-babel.patch b/srcts/patch/esbuild-plugin-babel.patch
new file mode 100644
index 00000000..24cc9425
--- /dev/null
+++ b/srcts/patch/esbuild-plugin-babel.patch
@@ -0,0 +1,33 @@
+diff --git a/package.json b/package.json
+index 6b9cdb89e2bbf0f5b5ad65adb53951d129f265ca..4e9b0e08e1c9850ff637eb6a47b5f3cfa33bbb55 100644
+--- a/package.json
++++ b/package.json
+@@ -7,7 +7,6 @@
+ 	"license": "ISC",
+ 	"exports": "./src/index.js",
+ 	"main": "src/index.js",
+-	"type": "module",
+ 	"scripts": {
+ 		"format": "prettier --write --ignore-unknown '**/*'"
+ 	},
+diff --git a/src/index.js b/src/index.js
+index b3cff90a292daa6cfac0566ee73bab142ac627df..d06ecf8873a45a5ea3cda7edb3814e8034efed32 100644
+--- a/src/index.js
++++ b/src/index.js
+@@ -1,6 +1,7 @@
+-import babel from '@babel/core';
+-import fs from 'fs';
+-import path from 'path';
++const babel = require('@babel/core');
++const fs = require('fs');
++const path = require('path');
++
+
+ const pluginBabel = (options = {}) => ({
+ 	name: 'babel',
+@@ -41,4 +42,4 @@ const pluginBabel = (options = {}) => ({
+ 	}
+ });
+
+-export default pluginBabel;
++module.exports = pluginBabel;
diff --git a/srcts/yarn.lock b/srcts/yarn.lock
index 90d3fd04..1ca29eba 100644
--- a/srcts/yarn.lock
+++ b/srcts/yarn.lock
@@ -4334,7 +4334,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"esbuild-plugin-babel@npm:0.2.3":
+esbuild-plugin-babel@0.2.3:
   version: 0.2.3
   resolution: "esbuild-plugin-babel@npm:0.2.3"
   peerDependencies:
@@ -4343,6 +4343,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"esbuild-plugin-babel@patch:esbuild-plugin-babel@0.2.3#./patch/esbuild-plugin-babel.patch::locator=root-workspace-0b6124%40workspace%3A.":
+  version: 0.2.3
+  resolution: "esbuild-plugin-babel@patch:esbuild-plugin-babel@npm%3A0.2.3#./patch/esbuild-plugin-babel.patch::version=0.2.3&hash=80b9d8&locator=root-workspace-0b6124%40workspace%3A."
+  peerDependencies:
+    "@babel/core": ^7.0.0
+  checksum: 91e0a233ed255b4798b3a1d9b2d9fbc8ea3c107561c69b31790f02c556a4687770a13d2b4c58f3dc638198bcddd5c6d7d26496a6578da730cd635dea1dd8450c
+  languageName: node
+  linkType: hard
+
 "esbuild-plugin-globals@npm:^0.1.1":
   version: 0.1.1
   resolution: "esbuild-plugin-globals@npm:0.1.1"
@@ -4350,6 +4359,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"esbuild-plugin-pnp@npm:^0.3.0":
+  version: 0.3.0
+  resolution: "esbuild-plugin-pnp@npm:0.3.0"
+  peerDependencies:
+    esbuild: ^0.8.1
+  checksum: b80ab17bea35ab6eaf9a9adc14c52667c0a5e2c7c8c8e97194c57feb7d14b7247228745a3ad34f69447d6c5241081f38b9786948b879bf0051a479ce74450edc
+  languageName: node
+  linkType: hard
+
 "esbuild@npm:^0.8.50":
   version: 0.8.50
   resolution: "esbuild@npm:0.8.50"
@@ -9295,8 +9313,9 @@ fsevents@^2.1.2:
     browserslist: ^4.16.3
     core-js: ^3.9
     esbuild: ^0.8.50
-    esbuild-plugin-babel: 0.2.3
+    esbuild-plugin-babel: "patch:esbuild-plugin-babel@0.2.3#./patch/esbuild-plugin-babel.patch"
     esbuild-plugin-globals: ^0.1.1
+    esbuild-plugin-pnp: ^0.3.0
     eslint: ^7
     eslint-config-prettier: ^7
     eslint-plugin-jest: ^24
