cdn77 / dicc

Dependency Injection Container Compiler for TypeScript
2 stars 0 forks source link

Is it server-side only? #1

Open Serg046 opened 3 weeks ago

Serg046 commented 3 weeks ago

I have successfully compiled a container but once I start using it, I get the following:

Module not found: Error: Can't resolve 'async_hooks' in '/localpath/node_modules/dicc/dist'

That's my generated container:

import { Container } from 'dicc';
import * as ratingservice0 from './services/rating-service';

interface Services {
  '#RatingService.0': ratingservice0.RatingService;
}

export class ServiceProvider extends Container<Services>{
  constructor() {
    super({}, {
      '#RatingService.0': {
        factory: () => new ratingservice0.RatingService(),
      },
    });
  }
}

Then I inspected this dicc module and found this https://github.com/cdn77/dicc/blob/main/core/dicc/src/container.ts#L1C10-L1C27. Is there any fix for that for browsers?

P.S. I am now using just a mock like this and features work (constructors only):

class LocalStorageMock {
    run(store, cb) {
    }

    getStore() {
    }
}
jahudka commented 3 weeks ago

Hi, yes, for now, the DICC runtime is server-side only due to depending on AsyncLocalStorage, which isn't available in browsers. There is a TC39 proposal for a similar API which, if accepted and implemented by browsers, would allow me to support the same features in browsers, and it is Stage 2 already, which means we might see it implemented reasonably soon. Until then, I think I could separate the async context tracking features into a subclass, and allow you to switch e.g. in config which variant you want to use - so you'd get dependency injection in the browser without async context tracking, without sacrificing async context tracking on the server. Would that work?

Serg046 commented 3 weeks ago

Yes, it would be great. I am now using a webpack plugin that patched dicc.js which is not something good to have. I'd even start using dicc inside dicc to describe all its dependencies and expose them for replacement publicly (sort of dogfooding pattern).

jahudka commented 1 week ago

Hi, sorry for the delay, I've been busy rewriting the DICC compiler basically from scratch lol, anyway check out v1.0.0-rc.0 of both packages - the runtime package now externalises the async_hooks dependency using a dynamic import and handles the case when the import fails (as would be the case in browsers), so you should be able to bundle it easily. If your bundler complains about async_hooks, there will usually be an option to define some packages as "external", so the bundler will just leave the dynamic import as-is. This should give you a working implementation of the DICC Container in browsers, obviously minus "local" services / container.fork(). Let me know if it works!

Serg046 commented 1 week ago

The config stopped working: https://github.com/skyscrapercity-ru/skyscrapers/blob/main/dicc.yaml

project: './tsconfig.json'
containers:
  src/service-provider.ts:
    className: 'ServiceProvider'
    typeCheck: true
    resources:
      src/services/*.ts: ~
      src/components/*.ts:
        exclude:
          - src/components/component-template.ts
Configuration error: Invalid config: [
  {
    "code": "unrecognized_keys",
    "keys": [
      "exclude"
    ],
    "path": [
      "containers",
      "src/service-provider.ts",
      "resources",
      "src/components/*.ts"
    ],
    "message": "Unrecognized key(s) in object: 'exclude'"
  },
  {
    "code": "unrecognized_keys",
    "keys": [
      "typeCheck"
    ],
    "path": [
      "containers",
      "src/service-provider.ts"
    ],
    "message": "Unrecognized key(s) in object: 'typeCheck'"
  }
]
jahudka commented 1 week ago

Ouch, sorry, not a very helpful error message.. The config schema changed a bit in the new version:

I'm off to bed for now, it's almost 3am here, I'll look into the other issues more tomorrow!

Serg046 commented 1 week ago

Something else is changed:

project: './tsconfig.json'
containers:
  src/service-provider.ts:
    className: 'ServiceProvider'
    resources:
      src/services/*.ts: ~
      src/components/*.ts:
        excludePaths:
          - src/components/component-template.ts
Unsupported: Overload signatures are not supported
Container: src/service-provider.ts (ServiceProvider)
Resource node_modules/@babel/core/src/transform-file.ts
Path: transformFile

Seems it tries to scan more folders than expected

jahudka commented 1 week ago

Well it means you must've exported something that the resource scanner followed to the mentioned file. The resource scanner picks up everything you export from any resource file which matches the resource pattern and then follows some of those exports further - e.g. namespaces, object literals etc. So apparently you're exporting (or re-exporting) something somewhere that the resource scanner follows to the transformFile function declared in the Babel transform-file.ts file.

Edit: weird thing is, the transformFile path should be the full object path starting from one of the resource files that match your configured pattern to the declaration being examined, so you'd literally have to do something like export { transformFile } from '@babel/core' in a resource file. I don't know if the code that is up in your repository is up to date with what triggered this error, but I can't see anything that should do this in your source files.

Serg046 commented 5 days ago

Yes, I am testing it there in the main branch. The prev. version works fine. It is proved by github actions build. I will try to understand why the thing happens. I felt like dicc started to scan the whole modules folder as it started to work significantly longer than before.

jahudka commented 5 days ago

That shouldn't happen.. I'm literally just passing the resource patterns that you specify in dicc.yaml to TS Morph, and the patterns in your config file should be pretty fool-proof.. weird. I'll try cloning your repo and replicating it locally.

jahudka commented 5 days ago

Actually, could you first push your latest code? The repo looks out of date, at least the dicc.yaml file is still the old one..

Serg046 commented 5 days ago

Yes because I don't want to push something that doesn't work yet. The config I use to try rc version is here above. So I use that config and do npm run di.

Serg046 commented 3 days ago

Interesting thing, the following config

project: './tsconfig.json'
containers:
  src/service-provider.ts:
    className: 'ServiceProvider'
    resources:
      src/services/*.ts: ~
      src/components/*.ts: ~

works fast without intensive scanning and generates this (no services):

import { Container } from 'dicc';

interface PublicServices {

}

interface DynamicServices {}

interface AnonymousServices {}

export class ServiceProvider extends Container<PublicServices, DynamicServices, AnonymousServices> {
  constructor() {
    super({
    });
  }
}

Once I add the exclude path from the example above, it starts scanning node_modules and fails eventually.

Serg046 commented 1 day ago

Explicit service definitions work. So, there are two issues with rc.0: something wrong is with exclusions and implicit registrations don't work.

jahudka commented 12 hours ago

Aah, I see what the second problem is caused by: the new implementation of the compiler builds a list of all known definitions present in your resource files, but when it analyses those definitions, it starts with public services and follows their dependencies; and then during compilation it only includes services which were analyzed. So services which aren't used are not included in the final result. This is actually supposed to be a feature - it avoids dead / unreachable code - but it does mean that you need at least one explicit service definition, because implicit service definitions cannot be public. By design, you should only explicitly call container.get() in application entrypoints - in all other places you should rely on injection. It's documented, but it is new behaviour, sorry about the confusion.

I'll look into the exclusion issue asap and post back when I know more!

jahudka commented 11 hours ago

Okay, so there was a bug caused by eagerly resolving absolute resource & exclusion paths; this is now fixed and released as dicc-cli RC2. Sorry for the delay!