fix(decorators): let the application own the reflect-metadata polyfill - #74
Merged
Conversation
Four decorators carried `import 'reflect-metadata'`. None of the other eight `@bymax-one` libraries does — the polyfill belongs to the application, which loads it once in `main.ts`, and NestJS itself pulls it in: importing `@nestjs/common` alone takes `Reflect.defineMetadata` from `undefined` to `function`. Carrying it here also contradicted this package's own `"sideEffects": false`. That flag says no module in the package has a side effect, and an import whose entire purpose is its side effect is exactly one. Bundlers happen not to drop it — the decision is made by the imported package's flag, and `reflect-metadata` declares none — but a manifest should not assert something the code disproves. The measurable cost was in a consumer's bundle: with the import present, esbuild inlines the polyfill, taking a minimal bundle from 53 KB to 95 KB even when the application already loaded it. Specs keep their own `import 'reflect-metadata'`: a test file is its own entry point and has no application to load it.
There was a problem hiding this comment.
Pull request overview
This PR removes import 'reflect-metadata' side-effect imports from the library’s production decorators so the consuming application (or NestJS) owns loading the global reflect-metadata polyfill, aligning runtime behavior with "sideEffects": false and avoiding bundling the polyfill into consumer bundles unnecessarily.
Changes:
- Removed
reflect-metadataside-effect imports from four server decorators. - Minor formatting cleanups in
Process(ternary) andWorkerEventName(union type).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/server/decorators/processor.decorator.ts | Drops reflect-metadata side-effect import from @Processor. |
| src/server/decorators/process.decorator.ts | Drops reflect-metadata side-effect import from @Process; minor formatting adjustment. |
| src/server/decorators/on-worker-event.decorator.ts | Drops reflect-metadata side-effect import from @OnWorkerEvent; union type formatting change. |
| src/server/decorators/on-queue-event.decorator.ts | Drops reflect-metadata side-effect import from @OnQueueEvent. |
Suppressed comments (1)
src/server/decorators/processor.decorator.ts:11
- With the
reflect-metadataside-effect import removed, these decorators now assume the polyfill has already been loaded. If a consumer applies@Processorbefore importingreflect-metadata(or otherwise ensuringReflect.defineMetadataexists), they’ll get a confusing runtimeTypeError. Consider adding a small runtime assertion near theReflect.defineMetadata(...)call to throw an actionable error when the polyfill is missing.
import { DEFAULT_WORKER_CONCURRENCY } from '../constants/default-options'
import type { ProcessorMetadata } from '../interfaces/processor-metadata.interface'
import type { WorkerOptions } from '../interfaces/worker-options.interface'
import { PROCESSOR_METADATA_KEY } from './metadata-keys.constants'
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What is different here
Four decorators carry
import 'reflect-metadata'. None of the other eight@bymax-onelibraries does — this package is the only one of nine that both declares"sideEffects": falseand imports something purely for its side effect.sideEffectsreflect-metadatafalsefalseWhy the application should own it
reflect-metadatais a global polyfill: it mutatesReflect, and the application loadsit once in
main.ts. A library that loads it too is asserting a side effect its ownmanifest denies.
And it is unnecessary — NestJS already pulls it in. Measured in a clean consumer:
So any consumer of this library has the polyfill before a decorator ever runs, by way of
@nestjs/common. That is why the other eight work without importing it.The cost it was imposing
With the import present, a bundler inlines the polyfill into the consumer's bundle. A
minimal esbuild bundle of this package goes from 53 KB to 95 KB — the difference is
reflect-metadata, shipped again to an application that already loaded it.What about tree-shaking dropping it?
That was the first worry, and it turned out not to be the problem.
sideEffects: falseon the importing package does not license dropping
import 'x'; the decision is madeby x's own flag, and
reflect-metadata@0.2.2declares none, so bundlers keep it.Verified by bundling and grepping the output. The contradiction is in the manifest, not
in the behaviour — which is why this is a correctness/consistency fix rather than a bug
fix.
Scope
Removed from the four production decorators. The specs keep their own import: a test
file is its own entry point, with no application to load the polyfill for it.
Verification
typecheck·lint·build· 276 tests / 20 suites, 100% coverage · the builtdist/server/index.mjsno longer referencesreflect-metadata· a real consumer appliesProcessor('q')(C)successfully without importing the polyfill itself.