#Share code/instances between app and express server

1 messages · Page 1 of 1 (latest)

jagged cove
#

I want to use the same instance of EventEmitter, as well as constants, in my Remix server code and my express server file. Is this possible?

Using Remix Routing V2, my relevant file structure is:

project
└───app
│   └───routes
│   │   constants.ts
│   │   emitter.server.ts
└───server.mjs

The file emitter.server.ts merely imports EventEmitter and exports a new instance of it. Both my route loaders and my server file need access to that same EventEmitter instance (and access to constants as an aside).

Attemtping to import the emitter into my express server file like this results in the following error:
import { emitter } from './app/emitter.server.ts'
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/usr/app/app/emitter.server' imported from '/user/app/server.mjs

Notes:

  • I'm using esm syntax for my server.mjs file (import instead of require).
  • serverModuleFormat in remix.config.ts is cjs
  • I don't have "type": "module" in package.json because I'm using @mui libraries and that blows up all the @mui imports
  • I was using cjs syntax in server.js until recently. I changed to esm syntax, which required changing its file type from js to mjs
  • No idea if any of these are important

Thanks for taking a look.

quaint minnow
#

I think you should use a separate event broker like Rabbitmq or Kafka instead, imo event emitters should be used within a server only, but in case of server to server, event broker would be a better choice

jagged cove
proven spoke
#

You need to use getLoadContext in your http server to pass the emitter to your remix AppLoadContext

jagged cove
chrome abyss
#

You can also create your own entry.server, then can extend the bundle

declare module '@remix-run/server-runtime' {
     // This is the module that is exported from apps/portal/app/entry.server.ts
    // server.ts always accesses the latest version of this file, enabling the
    // use of the latest code, without reloading the web server
    export interface ServerEntryModule {

        // We export both because we will subscribe once, but we will always
        // use the latest handler implementation when handling jobs
        // If you add new jobs, you will have to restart the web server
        subscribeUsingDefaultHandlers: typeof subscribeUsingDefaultHandlers

        jobHandlers: JobHandlers
    }
}

Then you can use the build

    initialBuild.entry.module.subscribeUsingDefaultHandlers(
        initialBuild.entry.module.getLoadContext(log, 'init'),
        async () => {
            const latestBuild = typeof resolveBuild === 'function' ? await resolveBuild() : resolveBuild
            return latestBuild.entry.module.jobHandlers
        },
    )
#

Then inside entry.server, just export the things you have declared on ServerEntryModule

quaint minnow