Closed 58bits closed 1 year ago
@kiliman - any guesses?
Hey!
Building the project and then running npm run serve
from the apps/server
folder works fine for me. A difference is that by running serve
through turbo the scripts "working folder" will be apps/server
, whereas your CMD script above is run from the project root. Since you are not bundling dependencies into the remix server bundle, it will retrieve them from node_modules on runtime. Make sure to run the serve script from the server folder, and that the node_modules folders exist in the app folders inside the running container.
@dsod - Hi Daniel thanks so much for taking the time to reply as well as merging the PR!
I reached a point where I was printing out console.log(process.cwd()
of every combination of directory location I could think of - including as you suggest, running serve from the apps/server
folder.
When you say you ran npm run serve
above - form the apps/server
folder - do you mean you ran pnpm run serve
? Or did you really run npm run serve
?
Our goal was to call the transpiled apps/server/dist/server.js
file directly - like this...
PAYLOAD_CONFIG_PATH=../cms/dist/payload.config.js NODE_ENV=production node --conditions=serve dist/index.js
...as the start command for our Docker image (actually from supervisord
), and it's this form we're having trouble with - whether called in Docker, or called in the local repo.
but at the moment - whenever we do this.. we get the following (edited to remove local context)
Error: Cannot find module 'form-data'
Require stack:
- /apps/remix/build/index.js
- /apps/server/dist/index.js
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:1075:15)
at Function.Module._load (node:internal/modules/cjs/loader:920:27)
at Module.require (node:internal/modules/cjs/loader:1141:19)
at require (node:internal/modules/cjs/helpers:110:18)
at Object.<anonymous> (/apps/remix/build/index.js:10448:32)
at Module._compile (node:internal/modules/cjs/loader:1254:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
at Module.load (node:internal/modules/cjs/loader:1117:32)
form-data is a dependency in our Remix app - but it's not just form-data - it's a long list of 'require' dependencies.
Actually we get the same error if we run pnpm run serve
or even npm run serve
from the apps/server directory
The only time we don't get any errors at all, is when we run pnpm run serve
from the root directory, and then turbo executes the command for us. And so somehow the combination of pnpm, hoisted node_modules and turbo 'just works' - but I have no idea why. Heh.
Hey,
Any time!
Ah yes, pnpm
, of course. I will reach out on Discord and we can discuss further there.
@dsod Awesome thanks - also noticed that the actually error was missing the error message above - it's there now. Which Discord groups are you in? Turbo? Payload? or Remix?
Hey, I wrote a DM to you. You can find me in the Payload and Remix servers otherwise.
TL;DR
When you want or have to specify a dependency in remix's serverDependenciesToBundle
, and node is unable to resolve transitive dependencies of that package, configure pnpm to "publicly" hoist it:
https://pnpm.io/npmrc#public-hoist-pattern
Explanation
When specifying packages in the remix.config.js > serverDependenciesToBundle: [...]
, esbuild will include said package in the remix server build, and try to resolve and include the package nested/transitive dependencies in the bundle as well. Sometimes, esbuild is unable to resolve transitive packages which results in them not being included in the bundle.
When this happends, and node tries to import/resolve one of the transitive packages, it will fail to do so when using the default pnpm node_modules setting. Long story short, pnpm "hides" packages in node_modules/.pnpm/...
(for good reason) while node tries to find the package in node_modules/...
. So the module can't be found.
By configuring pnpm to publicly hoist the transitive package, it will be placed directly inside the node_modules
folder, and node will be able to resolve it.
Thanks @dsod - this is brilliant!
Confess I've tried just about everything I can think of - but I'm unable to run the production server without Turbo....
For example, in a layered Docker image we've created, I'd like to be able to call
CMD NODE_ENV=production node --conditions=serve ./apps/server/dist/index.js
...as the CMD for Docker.
But when we do this, we get remix require errors - such as
Placing the dependencies in Remix's
serverDependenciesToBundle
setting works, but there are a LOT of them, and this can't possibly be the right approach.We've also tried (but currently failed) to NOT hoist the Remix node_modules installs, but can't seem to get this to work with pnpm. And we've also tried (and have reproduced the error) by calling
NODE_ENV=production node --conditions=serve ./apps/server/dist/index.js
...from our local repo (i.e. without Docker) and are assuming that if we can get this to work, Docker will be fine.
What 'magic' is Turbo using in order to call the serve script in apps/server without any dependency errors?
@dsod - any ideas?
(P.S - we've placed PAYLOAD_CONFIG_PATH in our .env file)