Home > Software engineering >  Set a module export before the file finishes in Node.js module (`import`/`export` syntax)
Set a module export before the file finishes in Node.js module (`import`/`export` syntax)

Time:12-20

I am creating an API using express and I want to have a file for each endpoint. Ideally, I'd want to create the router in it's file, have it be exported and then import the endpoints files so they're run. The endpoint files would import the router again and then use .get, or .post or whatever to create the actual endpoint on the router.

So basically, my goal is to have one file run another file that uses a value the first file exports before running the different file.

I've done this before in a project using the require() syntax, but now I am trying to translate this to import/export syntax for a different project.

Before, I've (successfully) used something like this in another project:

Router.js

const express = require("express");

// Create and export a new router
const TestRouter = express.Router();
module.exports = TestRouter;

// Make the endpoints register themselves
require("./getdata.js");
require("./createdata.js");

And then in the endpoints (getdata.js and createdata.js):

const TestRouter = require("./TestRouter.js");

TestRouter.get("/:id", async (req, res) => {
  // ...
});

Now, I am trying to do the same with package syntax (import/export):

TestRouter.js

import { Router } from "express";

// Create and export our new router
const TestRouter = Router();
export default TestRouter;

// Import endpoints so they can register themselves
import "./getdata.js";
import "./createdata.js";

Endpoints (getdata.js and createdata.js):

import TestRouter from "./TestRouter.js";

TestRouter.get("/:id", async (req, res) => {
  // ...
});

But this direct translation doesn't work.

When I now try to run this project, I get an error like this:

file:///.../src/routes/getdata.js:3
TestRouter.get("/:id", async (req, res) => {
^

ReferenceError: Cannot access 'SessionRouter' before initialization
    at file:///.../src/routes/getdata.js:3:1
    ...

My most likely guess for the problem at the moment would be that exports in modules aren't actually set at the time of the export statement, but rather when their respective file reaches the end after processing everything else.

So my question would be if there was a way to set the export at the time of the export statement, or perhaps an easy way (about 1-2 lines in the endpoint files) to make the endpoints wait for the TestRouter to actually be set before calling .get, .post or whatever on it.

I know I could have the endpoint files just export the actual endpoint handlers:

const getdata = async (req, res) => {
  // ...
}
export default getdata;

and then have the .get calls in the router file:

import { Router } from "express";

// Import endpoint handlers
import getdata from "./getdata.js";

// Create our new router
const TestRouter = Router();

// Register endpints
TestRouter.get("/:id", getdata);

But I would like to avoid this - if at all possible - because every endpoint will need different middleware configurations, meaning that I have to specify all the middleware in the TestRouter.get (etc.) calls, which I don't really want to cram into the router file due to readability.

CodePudding user response:

You can solve this by splitting TestRouter.js into two parts:

  • The part that creates the router (let's leave that in TestRouter.js)
  • The part that loads the endpoints (let's call that main.js)

...and make the second part your entry point. That breaks the cycle between TestRouter.js and getdata.js/createdata.js that causes the latter to try to access the exported binding from TestRouter.js before it's initialized.

main.js:

// Create and export our new router
import TestRouter from "./TestRouter.js";
// Or, actually, just: import "./TestRouter.js";

// Import endpoints so they can register themselves
import "./getdata.js";
import "./createdata.js";

TestRouter.js:

import { Router } from "express";

// Create and export our new router
const TestRouter = Router();
export default TestRouter;

getdata.js / createdata.js remain unchanged.

  • Related