0

I am making a websocket webgame. I am trying to standardize data going over the websocket via some shared "Action" objects. I am using docker volumes to share a "shared" directory between two different containers, and tsconfig.json files to create an alias for easier use. This works fine for client, but I keep getting an error from the server.

The command I'm entering npm run dev:

(base) omitted@omitted CS5001-Scribble-Beasts % npm run dev 

> [email protected] dev
> docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build

The error I'm running into:

server-1  |   import { Actions, ActionType, ParseAction, type AnyAction } from "@shared/actions";
server-1  |                   ^
server-1  | 
server-1  | SyntaxError: The requested module '@shared/actions' does not provide an export named 'ActionType'```

Added Context

Code: https://github.com/2025-Senior-Design-Project/Scribble-Beasts/tree/room-system

(if you want to try and run this yourself, check out CONTRIBUTING.md)

Basic file structure:

/client
/server
/shared
docker-compose.yml

Pertinent Snippets:

docker-compose.yml

  server:
    build:
      context: ./server
      dockerfile: Dockerfile
    volumes:
      - ./server:/app
      - ./shared:/shared

server/package.json

  "type": "module",
  "main": "dist/server/src/index.js",
  "exports": "./dist/*.js",
  "scripts": {
    "start": "node dist/server/src/index.js",
    "dev": "tsx watch src/index.ts",

server/tsconfig.json

{
  "compilerOptions": {
    "lib": ["es2024", "ESNext.Array", "ESNext.Collection", "ESNext.Promise"],
    "module": "esnext",
    "moduleResolution": "bundler",
    "target": "es2017",
    "outDir": "./dist",
    "baseUrl": ".",
    "paths": {
      "@shared/*": ["../shared/*"]
    },
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "allowJs": true,
    "resolveJsonModule": true,
    "isolatedModules": true
  },
  "include": ["src/**/*", "../shared/**/*"],
  "exclude": ["node_modules", "dist"]
}

What I know:

  • The import/export names are correct. If I put the file into the same directory as room-handler.ts and change the from path it works without issue.
  • It's not an issue with the alias. If I swap the alias @shared with the relative path (../../../../shared) it shows the same error
  • The file exists in the container. If I use fs to print the contents of the file to the console while room-handler is running, it shows the actual content. If I look in docker-desktop I can see the shared mount.
  • Client uses the same setup as server and works (@shared and everything) and can import the file without issues.

What I've tried:

  • Changing from tsx to ts-node-dev or ts-node (I get the error: Error: Cannot find module '/app/src/lib/scripts/roomless-handler' imported from /app/src/index.ts)
  • Changing the moduleResolution from bundler to Node (same error)
  • Moving the shared volume into app instead of being in the root of the container (this worked, but the ts mismatched with the actual/local setup)
3
  • You'll be more likely to get expedient help if you can share a more minimal reproduction of the problem. For example, you said that path aliases aren't the issue and that using a normal relative path as the import specifier also reproduces the error, so don't involve aliases at all in your question/reproduction. Commented Sep 18 at 22:04
  • This looks like you're having trouble with the image build step? Can you include the relevant Dockerfile in the question? Since the build context is limited to the server directory it can't see the sibling shared directory; see for example How to include files outside of Docker's build context? Delete the volumes: block, which replace code only after the image is built and which mean you're not actually running the reproducible image at all. Commented Sep 18 at 23:41
  • @DavidMaze Thank you for commenting, I really appreciate it. That said, while volumes do update after build, it still is running the reproducible image. Otherwise volumes would be pointless, I'd need a source for that. Also, context points to where the dockerfile is and what files the dockerfile can interact with. If context really did that, then it would be impossible for the client container to work. Just want to clarify if anyone reads this in the future. Commented Oct 22 at 15:48

1 Answer 1

1

If you have a conflicting setup between your local setup and container setup with ts, you can create a docker.tsconfig. To avoid trying to keep two different tsconfig files update to date, just have your docker version extend the local one.

Specifically:
docker.ts.config

{
  "extends": "./local.tsconfig.json",
  "compilerOptions": {
    "baseUrl": "." // change to whatever the directory difference is
  }
}

Then change the docker-compose to rename your local tsconfigs to their docker versions

docker.tsconfig -> tsconfig

tsconfig -> local.tsconfig

    volumes:
      - ./server/docker.tsconfig.json:/app/tsconfig.json
      - ./server/tsconfig.json:/app/local.tsconfig.json

This allows your docker.tsconfig to be loaded on just your container, while leaving your local setup as-is

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.