Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to configure for Typescript #3

Closed
khashashin opened this issue Dec 25, 2024 · 2 comments
Closed

How to configure for Typescript #3

khashashin opened this issue Dec 25, 2024 · 2 comments

Comments

@khashashin
Copy link

Can this package be used in typescript project? Doing the following does not work

import { createServer, Server } from "node:net";
import path from "path";
import { fileURLToPath } from "url";
import { createServiceProxy } from "socketnaut";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const workerPath = path.resolve(__dirname, "app.ts");

const server: Server = createServer();

server.listen({ port: 8080, host: "0.0.0.0" }, () => {
  console.log("Server listening on port 8080");
});

createServiceProxy({
  server,
  minWorkers: 4,
  maxWorkers: 42,
  workerURL: workerPath,
});

The error

╰─ npm run dev                                                                                                       ─╯ 

> dev
> npx tsx src/index.ts

<INFO> 2024-12-25T23:28:43.293Z KHASHASHIN-PC 22676 - socketnaut v1.5.3
<INFO> 2024-12-25T23:28:43.297Z KHASHASHIN-PC 22676 - pid 22676
Server listening on port 8080
<INFO> 2024-12-25T23:28:43.306Z KHASHASHIN-PC 22676 - Service Proxy listening on {"address":"0.0.0.0","family":"IPv4","port":8080}
<ERROR> 2024-12-25T23:28:43.393Z KHASHASHIN-PC 22676 - Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'C:\Users\khash\Development\ms-export\app.ts' imported from C:\Users\khash\Development\ms-export\
    at finalizeResolution (node:internal/modules/esm/resolve:255:11)
    at moduleResolve (node:internal/modules/esm/resolve:908:10)
    at defaultResolve (node:internal/modules/esm/resolve:1121:11)
    at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:396:12)
    at ModuleLoader.resolve (node:internal/modules/esm/loader:365:25)
    at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:240:38)
    at ModuleLoader.import (node:internal/modules/esm/loader:328:34)
    at node:internal/modules/run_main:99:28
    at loadESM (node:internal/process/esm_loader:34:13)
    at async handleMainPromise (node:internal/modules/run_main:113:12)
@adamjpatterson
Copy link
Member

adamjpatterson commented Dec 26, 2024

@khashashin Thank you for submitting this issue and thank you for bringing this to my attention.

Please see privatenumber/tsx#354 and nodejs/node#47747 for more information on this issue.

The following approach, as described in vitest-dev/vitest#5757 (comment), seems to work; however, I don't know all the implications of using it.

import * as net from 'node:net';
import { createServiceProxy, Level } from 'socketnaut';

const server = net.createServer();

server.listen({ port: 8080, host: '0.0.0.0' });

const proxy = createServiceProxy({
    server,
    minWorkers: 4,
    maxWorkers: 42,
    workerURL: `import { tsImport } from "tsx/esm/api"; tsImport("./app.ts", import.meta.url);`,
    workerOptions: { eval: true }
});

The workerURL argument is a string that is evaluated and app.ts is the scaled module. Please see tsImport and Worker options for detail.

@khashashin
Copy link
Author

Thank you so much for your prompt response and for providing a workable solution!

I implemented your suggested approach and made a few additional tweaks to accommodate both development and production environments. Specifically, I encountered an issue where the relative path was being resolved relative to package.json. To address this, I utilized pathToFileURL and adjusted the worker file naming to differentiate between TypeScript (app.ts) and JavaScript (app.js) versions. This was necessary because the build process outputs JavaScript files, and referencing app.ts in production was causing issues.

Here is my final index.ts:

import path from "path";
import { createServer, Server } from "node:net";
import { fileURLToPath, pathToFileURL } from "url";
import { createServiceProxy, Level } from "socketnaut";

const isProduction = process.env.NODE_ENV === "production";
const workerFile = isProduction ? "app.js" : "app.ts";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const workerPath = pathToFileURL(path.resolve(__dirname, workerFile)).href;

const server: Server = createServer();

server.listen({ port: 8080, host: "0.0.0.0" }, () => {
  console.log("Server listening on port 8080");
});

const proxy = createServiceProxy({
  server,
  minWorkers: 4,
  maxWorkers: 42,
  workerURL: `import { tsImport } from "tsx/esm/api"; tsImport("${workerPath}", import.meta.url);`,
  workerOptions: { eval: true },
});

proxy.log.setLevel(isProduction ? Level.INFO : Level.DEBUG);

It works using the following Docker image:

FROM node:22-alpine AS builder

WORKDIR /app

COPY package.json package-lock.json tsconfig.json ./
RUN npm ci

COPY src ./src

RUN npm run build

FROM node:22-alpine

WORKDIR /app

COPY package.json package-lock.json ./
RUN npm install

COPY --from=builder /app/dist ./dist

ENV NODE_ENV=production

EXPOSE 8080

CMD ["node", "dist/index.js"]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants