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

[vite] Files shared between Remix and Express are loaded twice #9202

Open
duailibe opened this issue Apr 5, 2024 · 2 comments
Open

[vite] Files shared between Remix and Express are loaded twice #9202

duailibe opened this issue Apr 5, 2024 · 2 comments

Comments

@duailibe
Copy link

duailibe commented Apr 5, 2024

Reproduction

https://stackblitz.com/edit/remix-run-remix-muutqq?file=server.js,app%2Froutes%2F_index.tsx

Check server.js and routes/_index.tsx (there are comments indicating where).

System Info

System:
    OS: macOS 13.5.2
    CPU: (8) arm64 Apple M1
    Memory: 109.50 MB / 8.00 GB
    Shell: 3.6.1 - /opt/homebrew/bin/fish
  Binaries:
    Node: 18.19.1 - ~/.local/share/mise/installs/node/18.19/bin/node
    npm: 10.2.4 - ~/.local/share/mise/installs/node/18.19/bin/npm
    pnpm: 8.7.5 - /opt/homebrew/bin/pnpm
  Browsers:
    Chrome: 123.0.6312.106
    Safari: 16.6

Used Package Manager

npm

Expected Behavior

In the StackBlitz, I'd expect that all imports of foo-service would resolve to the same memory reference.

Actual Behavior

When importing the same module in express code and in Remix code, the module gets loaded "twice" (once the actual module, and the other is its copy bundled in build/server/index.js)

I tried using ssr.external but that doesn't seem to work with relative files, only node_modules?

With the classic compiler, I was able to work by using the server option in remix.config.js, but I can't find a way to that with Vite (I'm not well versed with Vite's options though). If there's any workaround to this problem I'd appreciate. Otherwise, I won't be able to use the new Vite compiler at all in my projects

@kiliman
Copy link
Collaborator

kiliman commented Apr 5, 2024

Interesting. Yeah, I thought that importing directly from app/services from my server file would work, but you're right. The generated build/server/index.js file contains a copy of the imported code.

Anyway, I played around with a bunch of Vite and esbuild flags, but never could get them to combine since they're not built together.

So I got the crazy idea of simply having Remix import my Express server file directly. My server file actually exports the express app (for use in my Vite plugin)

// app/entry.server.tsx
import app from "#server/index";  // import the created express app
export { app }

// rest of entry.server.tsx

Had Remix build the production file and sure enough, the generated file included both my Express code and the Remix stuff.

Ran NODE_ENV=production node ./build/server/remix.js

Voila!

image

@duailibe
Copy link
Author

duailibe commented Apr 6, 2024

Thanks @kiliman, that's actually not a bad idea

I was able to make it work by (ab)using entry.server.tsx:

  • create an express app in entry.server.tsx that has the Remix handler and other related express code
    • you can create the Remix request handler by importing virtual:remix/server-build directly
  • in my server.ts file I create another express app (this is the one that will actually handle requests)
    • call the ssrLoadModule() to access the build file
    • then you can access the "inner" express app with build.entry.module.app (app is how I exported the express app in entry.server.tsx)

It's cool that I get HMR in the server for my entire app (both express and Remix parts)!

You can see the resulting code here: https://stackblitz.com/edit/remix-run-remix-t9pwxg?file=server.js,app%2Fentry.server.tsx

I'm not sure there's anything in Remix side that could be done to make this better, at least make sure the build file won't change too much in the future (but if it does change, that would be easy to catch in dev because it will fail fast). Either way, I do think this is a reasonable workflow and should be supported by Remix somehow.

PS: One thing I noticed is that the server build file exports some of my components and hooks. I could not understand why that happens, but got worried I could get a name conflict with the app in entry.server.tsx

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

No branches or pull requests

3 participants