javascriptes6-modulescircular-dependencydynamic-importtop-level-await

how do i dynamically import modules that use a module inside the module itself?


yes that probably sounds confusing, right?

i have the following module called app.js:

import express from 'express'

const app = express()

export default app

as you can see, all it does is create an express instance and export it.

now, i have a folder called routes, and inside of this folder, i want to be able to add as many route modules as i'd like.

oh, and i'd really love to use them like so (e.g. routes/index.js):

import { app } from '../app.js'

app.get('/', (req, res) => {
    res.send('Hello World!')
})

here is where it gets interesting. i want to change my my app.js code so that it will automatically import all of the route modules from inside the routes folder:

new app.js code:

import express from 'express'
import {globby} from 'globby'
import path from 'path'

const app = express()

const routePaths = await globby([
    './routes/**/*.js',
])

for (const routePath of routePaths) {
    await import(path.resolve(routePath))
}

export default app

of course, since the route module is referencing the app module, it suffers from a never ending loop which will continue until long after AI has taken over our planet, humans go extinct, and unconscious cyborgs rule the world.

is it possible to have a module which imports other modules that references itself?

i've tried exporting a function for my route modules which use app as a parameter, and while that works, i think its a much nicer DX with the way i am asking about.


Solution

  • It's a circular dependency. Instead of: app.js imports routes, and routes import app.js, refactor it so both routes and app.js import the same common dependency (and then app.js can import routes).

    // file renamed to, say, express-instance.js - formerly app.js
    import express from 'express'
    const app = express()
    export default app
    
    // new app.js
    import app from './express-instance'
    import { globby } from 'globby'
    import path from 'path'
    
    const routePaths = await globby([
        './routes/**/*.js',
    ]) // etc.
    
    // some route file
    import app from './express-instance'
    
    app.get('/', (req, res) => {
        res.send('Hello World!')
    })