Repository: parcel-bundler/parcel (JavaScript)

Issue:
Support for Typescript Proxies
# 🙋 feature request

Hi Parcel 👋 ,
I see that you support a `.proxyrc.js` file but we have a bunch of proxies written in typescript. We would not like to re-write all these into javascript. Would you consider adding support for a `.proxyrc.ts` file?


# 🤔 Expected Behavior
Support `.proxyrc.ts` file for proxies.

# 😯 Current Behavior
No support for typescript proxies

# 💁 Possible Solution
Add support for a `.proxyrc.ts` file

Thank you so much 😄 



Discussion:

Patch:
diff --git a/packages/core/package-manager/src/NodePackageManager.js b/packages/core/package-manager/src/NodePackageManager.js
index 98f10b7b8e2..6f6a8cbbee9 100644
--- a/packages/core/package-manager/src/NodePackageManager.js
+++ b/packages/core/package-manager/src/NodePackageManager.js
@@ -215,7 +215,10 @@ export class NodePackageManager implements PackageManager {
     if (!filePath.includes(NODE_MODULES)) {
       let extname = path.extname(filePath);
       if (
-        (extname === '.ts' || extname === '.tsx') &&
+        (extname === '.ts' ||
+          extname === '.tsx' ||
+          extname === '.mts' ||
+          extname === '.cts') &&
         // $FlowFixMe
         !Module._extensions[extname]
       ) {
diff --git a/packages/dev/repl/.eslintrc.json b/packages/dev/repl/.eslintrc.json
index 889394204c0..8e0968511b8 100644
--- a/packages/dev/repl/.eslintrc.json
+++ b/packages/dev/repl/.eslintrc.json
@@ -10,7 +10,8 @@
   },
   "rules": {
     "react/jsx-no-bind": "off",
-    "no-console": "off"
+    "no-console": "off",
+    "no-use-before-define": "off"
   },
   "globals": {
     "globalThis": "readonly"
diff --git a/packages/reporters/dev-server/src/Server.js b/packages/reporters/dev-server/src/Server.js
index 26227f53d0d..56baa5dc805 100644
--- a/packages/reporters/dev-server/src/Server.js
+++ b/packages/reporters/dev-server/src/Server.js
@@ -419,6 +419,9 @@ export default class Server {
       this.options.inputFS,
       fileInRoot,
       [
+        '.proxyrc.cts',
+        '.proxyrc.mts',
+        '.proxyrc.ts',
         '.proxyrc.cjs',
         '.proxyrc.mjs',
         '.proxyrc.js',
@@ -434,13 +437,24 @@ export default class Server {
 
     const filename = path.basename(configFilePath);
 
-    if (
-      filename === '.proxyrc.js' ||
-      filename === '.proxyrc.cjs' ||
-      filename === '.proxyrc.mjs'
-    ) {
-      // $FlowFixMe
-      // let cfg = (await import(configFilePath)).default;
+    if (filename === '.proxyrc' || filename === '.proxyrc.json') {
+      let conf = await readConfig(this.options.inputFS, configFilePath);
+      if (!conf) {
+        return this;
+      }
+      let cfg = conf.config;
+      if (typeof cfg !== 'object') {
+        this.options.logger.warn({
+          message:
+            "Proxy table in '.proxyrc' should be of object type. Skipping...",
+        });
+        return this;
+      }
+      for (const [context, options] of Object.entries(cfg)) {
+        // each key is interpreted as context, and value as middleware options
+        app.use(createProxyMiddleware(context, options));
+      }
+    } else {
       let cfg = await this.options.packageManager.require(
         configFilePath,
         fileInRoot,
@@ -459,23 +473,6 @@ export default class Server {
         return this;
       }
       cfg(app);
-    } else if (filename === '.proxyrc' || filename === '.proxyrc.json') {
-      let conf = await readConfig(this.options.inputFS, configFilePath);
-      if (!conf) {
-        return this;
-      }
-      let cfg = conf.config;
-      if (typeof cfg !== 'object') {
-        this.options.logger.warn({
-          message:
-            "Proxy table in '.proxyrc' should be of object type. Skipping...",
-        });
-        return this;
-      }
-      for (const [context, options] of Object.entries(cfg)) {
-        // each key is interpreted as context, and value as middleware options
-        app.use(createProxyMiddleware(context, options));
-      }
     }
 
     return this;


Test patch:
diff --git a/packages/core/integration-tests/test/integration/proxyrc-ts/.proxyrc.ts b/packages/core/integration-tests/test/integration/proxyrc-ts/.proxyrc.ts
new file mode 100644
index 00000000000..3f3c3e863db
--- /dev/null
+++ b/packages/core/integration-tests/test/integration/proxyrc-ts/.proxyrc.ts
@@ -0,0 +1,10 @@
+const {createProxyMiddleware} = require('http-proxy-middleware');
+
+module.exports = function(app: any) {
+  app.use(createProxyMiddleware('/api', {
+    target: 'http://localhost:9753/',
+    pathRewrite: {
+      '^/api': ''
+    }
+  }));
+};
diff --git a/packages/core/integration-tests/test/integration/proxyrc-ts/index.js b/packages/core/integration-tests/test/integration/proxyrc-ts/index.js
new file mode 100644
index 00000000000..313f4281067
--- /dev/null
+++ b/packages/core/integration-tests/test/integration/proxyrc-ts/index.js
@@ -0,0 +1,3 @@
+module.exports = function () {
+  return 'Hello, Parcel.js!';
+};
diff --git a/packages/core/integration-tests/test/integration/proxyrc-ts/yarn.lock b/packages/core/integration-tests/test/integration/proxyrc-ts/yarn.lock
new file mode 100644
index 00000000000..fb57ccd13af
--- /dev/null
+++ b/packages/core/integration-tests/test/integration/proxyrc-ts/yarn.lock
@@ -0,0 +1,4 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
diff --git a/packages/core/integration-tests/test/proxy.js b/packages/core/integration-tests/test/proxy.js
index f0fecd6f027..8e851074aa5 100644
--- a/packages/core/integration-tests/test/proxy.js
+++ b/packages/core/integration-tests/test/proxy.js
@@ -196,4 +196,30 @@ describe('proxy', function () {
     data = await get('/api/get', port);
     assert.equal(data, 'Request URL: /get');
   });
+
+  it('should handle proxy table written in .proxyrc.ts', async function () {
+    let dir = path.join(__dirname, 'integration/proxyrc-ts');
+    inputFS.chdir(dir);
+
+    let port = await getPort();
+    let b = bundler(path.join(dir, 'index.js'), {
+      config,
+      serveOptions: {
+        https: false,
+        port: port,
+        host: 'localhost',
+      },
+    });
+
+    subscription = await b.watch();
+    await getNextBuild(b);
+
+    server = apiServer();
+
+    let data = await get('/index.js', port);
+    assert.notEqual(data, 'Request URL: /index.js');
+
+    data = await get('/api/get', port);
+    assert.equal(data, 'Request URL: /get');
+  });
 });