cmd-johnson / deno-reflect-metadata

A Deno-compatible copy of the TypeScript Metadata Reflection API my Microsoft
Apache License 2.0
11 stars 4 forks source link

Usage with "deno bundle" doesn't work #1

Closed arstulke closed 3 years ago

arstulke commented 3 years ago

Problem

When I try to use the Metadata Reflection API and bundle my typescript, I get a runtime error. I use your dependency injector lib and when I bundle and run my app it crashes with the following error:

error: Uncaught TypeError: Reflect.defineMetadata is not a function
     Reflect.defineMetadata("di:metadata", metadata, Type);
             ^
     at setInjectionMetadata (file:///app/main.js:525:13)
     at file:///app/main.js:626:9
     at file:///app/main.js:1774:29

Steps for reproducing

  1. Print deno version: deno --version

    deno 1.6.1 (release, x86_64-unknown-linux-gnu)
    v8 8.8.278.2
    typescript 4.1.2
  2. Create the tsconfig.json (from your README.md):

    "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
    }
    }
  3. Bundle your example.ts: deno bundle -c tsconfig.json https://deno.land/x/reflect_metadata@v0.1.12/example.ts example.ts

    Bundle https://deno.land/x/reflect_metadata@v0.1.12/example.ts
    Check https://deno.land/x/reflect_metadata@v0.1.12/example.ts
    Emit "example.ts" (562B)
  4. Execute the bundle: deno run -c tsconfig.json example.ts

Actual result

The result is the following runtime error:

error: Uncaught TypeError: _dec is not a function
let Example = _class = decorator(_class = _dec1(_class = _dec((_class = class Example {
                                                         ^
    at file:///some_directory/example.js:9:58

Through my initial analysis, I was able to determine that this error occurs because the variables _dec and _dec1 are undefined. This is the case because the function Reflect.metadata does not exist.

Expected result

My expected result was the same result as in your README: deno run -c tsconfig.json https://deno.land/x/reflect_metadata@v0.1.12/example.ts [ [Function: String], [Function: Number], [Function: Example] ]

Question

What changes are required to use the Metadata Reflection API in bundles?

cmd-johnson commented 3 years ago

Nice catch!

I looked at the issue and it appears that the IIFE in Reflect.ts that's responsible for initializing the global Reflect object was not included in the bundles generated by deno bundle. I moved it outside the namespace declaration and now it works for me.

Could you try to create and run a bundle with the following code? If it works, I'll merge my changes in #2 and release a new version with the fixes.

import { Reflect } from "https://raw.githubusercontent.com/cmd-johnson/deno-reflect-metadata/bugfix/deno-bundle/mod.ts";

// deno-lint-ignore no-explicit-any
type Constructor<T = unknown> = new (...args: any[]) => T;

function decorator<T>(_: Constructor<T>): void {}

@decorator
class Example {
  constructor(a: string, b: number, c: Example) {}
}

console.log(Reflect.getMetadata("design:paramtypes", Example));
arstulke commented 3 years ago

Your fix works for your code snippet, my test steps above and for my project. Thank you for fixing this bug so quickly.