graphql-mesh icon indicating copy to clipboard operation
graphql-mesh copied to clipboard

Bug in mesh build when composer does not export `defaults`

Open ntziolis opened this issue 2 years ago • 3 comments

The mesh build command produces invalid index.js file when no default exports are defined. This is a very common scenario when using typescript, but does also applies to js composers without default exports.

To Reproduce

# Mesh config excerpt
transforms:
  - resolversComposition:
      mode: bare
      compositions:
        - resolver: Query.*
          composer: ./composers#isAuth
require:
  - ts-node/register/transpile-only
// composers.ts
export function isAuth(next) => {
   return (root, args, context, info) => {
      // Check if Authorization header is present
      if(!context.headers.authorization) {
          throw new Error('Unauthorized');
      }
      return next(root, args, context, info);
   }
}

This does generate the following code in the index file:

import ExternalModule_1 from './composers';  //<- since there is no default export this does not work

Expected behavior Mesh build should generate a valid import for composers without default export.

Additional context There three ways I can think of to check if a composer has defaults exports:

  • Identify if a composer has default export
    • by looking into the source file and search for export defaults
    • by importing the composer during build via import * as DUMMY from '.mycomposer' and then check if DUMMY['defaults'] is undefined
    • by intermediary importing the composer in generated index file via a * as import, but use the default import as actual import + fallback to * as if no default export exists
import * as ExternalModule_1_all  from './composers';
const ExternalModule_13 = ExternalModule_13_all['defaults'] || ExternalModule_13_all;

// if possible this would only be done for custom composers and not for handlers + transform packages itself.

Summary The last solution seems to be the most straight forward. It does not extend build time, while only having a absolutely tiny effect on startup time.

Let me know if you agree with the approach (or suggest a different one) and I will make a PR.

ntziolis avatar Oct 13 '21 17:10 ntziolis

It needs some work on runtime package because * as is not valid for the actual ESM spec.

ardatan avatar Oct 13 '21 17:10 ardatan

I did a test run via patch-package and it does seem to work without issues. Since you are generating a typescript document first and then compile to js the typescript compiler seems to resolve the * as import somehow successfully and my mesh then starts without issues.

In js: const ExternalModule_0 = (0, tslib_1.__importStar)(require("ts-node/register/transpile-only"));

In mjs: import * as ExternalModule_0 from 'ts-node/register/transpile-only';

Since I couldn't keep my hands still in #2970 you can see a the first swing at a solution meant for discussion. Also fixed a minor typing error.

ntziolis avatar Oct 13 '21 18:10 ntziolis

@ardatan Might have missed something completely, what do you mean by needs some work on runtime package?

ntziolis avatar Oct 14 '21 04:10 ntziolis