Reputation: 20940
I'm working on a node script and writing it in typescript. I've had no problems with running builds on my laptop (mac) or from my raspberry pi running raspbian.
I've gotten to the point where I want to set the codebase up on a digital ocean server that's running ubuntu. I moved the codebase up and ran my build script. The build completes successfully, but when I launch the node process I get the error:
node dist/server/source-server/index.js
internal/modules/cjs/loader.js:883
throw err;
^
Error: Cannot find module 'express'
Require stack:
- /var/www/binary-operations-presentation/multi-player-server/dist/server/source-server/index.js
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)
at Function.Module._load (internal/modules/cjs/loader.js:725:27)
at Module.require (internal/modules/cjs/loader.js:952:19)
at require (internal/modules/cjs/helpers.js:88:18)
at Object.<anonymous> (/var/www/binary-operations-presentation/multi-player-server/dist/server/source-server/index.js:6:35)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'/var/www/binary-operations-presentation/multi-player-server/dist/server/source-server/index.js'
]
}
It's weird. I've run this codebase on multiple servers and none have had this issue. I did some searching around, but all of the answers I've found are saying "run npm install express" or "run npm install @types/express", both of which I have:
Plus, if I didn't have them installed, the typescript compiler build would have failed.
I compared the file structure on the ubuntu server to my raspberry pi server and aside from the files that are generated when the codebase actually runs, the directories are the same:
Both servers have the same tsconfig.json file:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"sourceMap": true,
"outDir": "../dist/server",
"rootDirs": ["./", "../project-common/"],
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true
}
}
And both have the same dependency versions:
// from package.json
{
...
"devDependencies": {
"@types/uuid": "^8.3.0",
"@types/ws": "^7.4.0",
"killport": "^1.0.1",
"nodemon": "^2.0.7",
"tsc-watch": "^4.2.9",
"tslint": "^6.1.3",
"typescript": "^4.1.3"
},
"dependencies": {
"@types/express": "^4.17.11",
"@types/lodash.clonedeep": "^4.5.6",
"@types/websocket": "^1.0.1",
"express": "^4.17.1",
"lodash.clonedeep": "^4.5.0",
"uuid": "^8.3.2",
"ws": "^7.4.2"
}
}
Neither of the dist
folders have the node_modules folder, and when I look at the transpiled index.js
file for the server they both import express the same way:
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const http_1 = __importDefault(require("http"));
and both of the index.js.map files refer to the same relative source directory:
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../source-server/index.ts"]
So I'm not sure why one server would be able to refer back to the node_modules folder but the other one wouldn't.
The only big difference (aside from the OS version, the server is running Ubuntu 20.04) that I see is that my raspberry pi is running node 15.x and the ubuntu is running node 14.x, though I don't know that that would necessarily cause this problem.
Any ideas?
I tried making the version of node the same. I installed nvm on my raspberry pi, pulled in 14.6.0 (same version as the digital ocean server), rebuilt the project, and launched the server -> works fine.
so the node version doesn't seem to be a factor :/
Upvotes: 0
Views: 1235
Reputation: 20940
So here's the snag and solution:
The gist is that the compiled version of the index file is firing a regular node require()
function to pull in modules:
Which means it goes through a number of steps to find the modules. When it comes to possible node_modules modules, it looks for the node_modules
folder in the current directory. If node doesn't find it, node will step up to the parent directory and look there, continuing to step back to the root directory if node_modules directories aren't found.
In my case, I previously had all of the server and client code at the same directory level (the directory where the new subfolders now live). When I separated the code into the subfolders, I forgot to blow away the old node_modules folder locally, which is why the dist
folder still found the node_modules
folder that now resided at the parent directory of dist
. When I did a git pull
on my raspberry pi, the folders updated, but because node_modules
is part of my .gitignore
, that folder at the parent level wasn't blown away.
But, in newer clones of the repository of course wouldn't have node_modules at that parent directory, or any other parent directory so they bombed out.
While talking with @cefn I realized that I did want to have the dist
be a "everything needed to run this project" directory, so I added a step to my npm build
script:
"scripts": {
"build": "tsc --build tsconfig.json && npm run build:move-indexes && npm run build:move-node_modules",
"build:move-indexes": "rsync -avz indexes ../dist/server/source-server",
"build:move-node_modules": "rsync -avz node_modules ../dist/server/source-server",
This way, every time I rebuild the source code, the server will sync the node_modules
in the dist
directory with the node_modules
in my source directory.
Tried it out, and it works :)
Upvotes: 1