8

How to import a module if it exists ?

I have 2 projects, client & server. Both import one same file.
The file imports a node module which is only installed in the server project. The client doesn't have the module.
So the require must return the module typed when opened from the server project.
And it must return undefined when opened from the client project.

Below an screenshot from the client project. Typescript doesn't compile because it says it cannot find the module. Typescript require cannot find module type-graphql

A simple require doesn't keep the type: enter image description here

1 Answer 1

5

There are 2 parts to this:

  1. A formal import statement must be unconditional. import means the module must always exist. That doesn't mean it has to be the module you actually need.
  2. The desired type is module | undefined on the server side. But on the client side module is unknowable. So to allow for server based calls, we should allow any fields to be used, like {[k:string]:any}, and we need to be able to select which one is appropriate for the side we are on.

So your best bet is probably to add an empty module of the same name to your client side, so a file called type-graphql.ts in the node_modules folder on the client side that only contains:

export {}

This way the unconditional import will always work, client will import this empty module file and server will import the actual library. Then you just need to re-assign the variable to consider possible interfaces:

import * as _TypeGraphQL from 'type-graphql';

// don't check methods on the client side, if we had type definitions on both we could just use that
type CLIENT_SIDE_INTERFACE = {[k:string]:any};
// on server side we can check for case that the module is not present.
type SERVER_SIDE_INTERFACE = typeof _TypeGraphQL | {"ISDUMMY":true}

// if the imported module has our indicator key then we are on the client side
type THIS_SIDE_INTERFACE = "ISDUMMY" extends (keyof typeof _TypeGraphQL) ? CLIENT_SIDE_INTERFACE : SERVER_SIDE_INTERFACE

const TypeGraphQL: THIS_SIDE_INTERFACE = _TypeGraphQL;

After having it pointed out that putting files in the normal node_modules folder is problematic, I can offer a possible solution to this as well.

Node resolves modules (that don't start with ./ or /) by walking up the folder tree from the current file, each level seeing if there is a folder called node_modules. Normally this means in the root of your project there is one folder containing all the modules. However you can add another folder in the middle of your project called node_modules and any imports by files there will search that folder first.

So for a folder structure like this would let you put the dummy file in the project in a way that import * as a from 'test-graphql' will import from a stable folder:

root
- node_modules
- src
  --- SUBFOLDERS
        - node_modules
          -test-graphql.tsx (dummy code)
        - git-sub-module
          - wrapper.tsx (containing the import code mentioned above)

Code in the wrapper.tsx in this case would try to import from the inner node_modules importing the empty module file. Just make sure you add sufficient comments in the empty module explaining what sorcery is going on :)

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for your explanations. I now understood that to import a module and keeping type, the module target must exist, whatever it will be. But how is it possible to import ISDUMMY module while the import states from 'type-graphql' ? It will search for 'type-graphql' in the node_modules. How to make it import from the ISDUMMY module ?
put a file called type-graphql.tsx in the node_modules folder on the client side. Edited answer to clarify.
Adding a file in node_modules is not a stable solution. If dependencies are updated / reinstalled, the module will be deleted. Furthermore the dummy module wont be committed in git, so we have to recreate a dummy module for each dependencies git repo is cloned. Generally, one should never rely on edits made in the node_module folder.
depending on the import resolution you can put it in the top level folder (beside the src folder) or I've seen some import setups that put the src on the resolution path so if that is the case putting it inside src will also work. If your client and server are in the same git repo that would complicate things though... let me think...
Don't worry. Client & server have not the same repo. They share a git sub module which contains the shared classes. Thanks. But I still don't understand how to make import from type-graphql target a project file. To import a project file, the import target must start with a / or a . like ./path/to/module. Just type-graphql make the import look at the node_modules directly.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.