jeffijoe / awilix

Extremely powerful Inversion of Control (IoC) container for Node.JS
MIT License
3.42k stars 130 forks source link

Support `loadModules` for apps running in the Browser (with Vite) #363

Open MathiasWP opened 2 weeks ago

MathiasWP commented 2 weeks ago

Awilix works great for enterprise applications running in the browser; but it's missing an API for automatically loading modules.

Vite has an API for loading files which works in the browser. We're currently using this to implement our own version of loadModules, but it would be great to have first-class support for this through Awilix.

Is this something to consider?

jeffijoe commented 2 weeks ago

Doesn’t Vite have to statically analyze the use of that method? If so then I don’t think it would work since Vite wouldn’t know to also look for that pattern via Awilix’ API. Also, wouldn’t doing this hurt code splitting? I have a feeling it comes at a cost.

I would be open to doing this though, as long as it can be agnostic to the use of Vite. Or, why not publish your solution as a library? There’s nothing special about the built-in Node version.

MathiasWP commented 2 weeks ago

Vite will transform

const modules = import.meta.glob('./dir/*.js', { eager: true })

into

// code produced by vite
import * as __glob__0_0 from './dir/foo.js'
import * as __glob__0_1 from './dir/bar.js'
const modules = {
  './dir/foo.js': __glob__0_0,
  './dir/bar.js': __glob__0_1,
}

(see https://vitejs.dev/guide/features#glob-import)

So it's quite easy to achieve the wanted behaviour from the transformed code. I'm currently doing this in our application and it works fine.

Because of the transformation I don't think it will hurt code-splitting, since the output is the same as if the code was written by hand.

Not sure how making the code agnostic to the use of Vite can be achieved. There's a lot of different build tools in the ecosystem, so the library would have to decide what tools to support anyways. And i'm not really sure if any other build tools support this atm. The solution could be available as a library, but i think it would be better for the community if it was available through Awilix.

What about exposing it through a Vite specific import?

import { loadModules } from "awilix/vite"

And you're right that Vite has to statistically analyse the usage of import.meta.glob, so wrapping it in a method will not work as expected (see https://github.com/vitejs/vite/issues/15926). To solve this Awilix could either expose a vite-plugin to transform the code, or it could export a method that expects the result of import.meta.glob and transforms the object into the expected structure for Awilix:

import { registerModules } from "awilix/vite"

// Support non-eager glob
registerModules(import.meta.glob(["/glob/to/files/*.ts"])

// And also eager glob
registerModules(import.meta.glob(["/glob/to/files/*.ts"], { eager: true })
jeffijoe commented 2 weeks ago

In that case I think having that be a separate package makes sense, like:

import { loadModules } from "awilix-vite”

We have the ecosystem section in the readme that we can add it to if you do decide to publish a package.

MathiasWP commented 2 weeks ago

In that case I think having that be a separate package makes sense, like:

import { loadModules } from "awilix-vite”

We have the ecosystem section in the readme that we can add it to if you do decide to publish a package.

Alright, that's fair! Where do you want me to notify you if i create this package?

jeffijoe commented 2 weeks ago

You can open a PR here adding a link in the ecosystem section 😄