-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pluggable schema loading #920
Conversation
this is a great, love it! can't wait to implement this with gls-interface + monaco only caveat of dynamic requires is that they can sometimes break build tooling. for example, common-shake will do a global exit on this, making it so that we can accomplish tree shaking, at least from what I can tell. it might introduce other issues as well, such as making things funky with webpack loaders and how they resolve paths/extensions. see this issue for details #882 |
Alright, alternative idea how to facilitate this:
Then to register a schema loader the developer must import the plugin on a top level. The plugin itself then has some code like this:
Alternatively, could we mark the loader with |
I guess if we think about an LSP itself it might not actually be able to require other packages that our outside of the extension. So alternatively we could just model this as a command line invocation that prints the loaded schema to stdout. Then we just need to reparse it. |
Digging more into that last idea, maybe a platform specific solution is necessary here: For VSCode we communicate via the extensions API (https://stackoverflow.com/questions/50058517/how-to-communicate-between-vscode-extensions). For GraphiQL we communicate via HTTP calls |
@Neitsch yes 98% of the time via HTTP for graphiql, but I do want the new graphiql to be able to support folks using it in an electron/nwjs/RN?!/etc app and thus being able to use json-rpc alongside alternative, vscode-like schema loading mechanisms. Maybe thats a bit ambitious though, haha! Either way, I agree that we need to figure out something platform specific for this. Those two patterns are great, and then in my above case, maybe we could read or stream from file or some clever cacheing mechanism. A tool like insomnia or altair, playground desktop would probably be able to leverage this as well since they are using these libraries. @schickling @imolorhe @gschier @martijnwalraven, thoughts on this interface? |
possibly we need an interface for platform-specific extensions in general... related to the above issue I mentioned, we somewhere along the idea had the idea of making |
} | ||
|
||
getSchemaLoader(): GraphQLSchemaLoader { | ||
return require(this.raw.loaderPackage).init(this.raw.loaderArgs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything about this looks good to me. Love the idea as well. The only part about this that I'm not sure of is this line which you guys were already talking about. I'm not familiar with all the contexts the language server can be used in (for example a browser context might not have the require
method), so when this is called at runtime it would need to work well for all contexts it's used in.
Having the package add itself to a global object is one way to go. Probably there are other approaches for this.
Ps: If the language server always runs in a node context, then I would prefer the require
to the global object approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should try and stay away from the global
object and dynamic require
s. All these concerns should be pushed up the stack so the calling application deals with them directly (and can then choose to do dynamic require vs not depending on what bundling they're using).
With that in mind, should getSchemaLoader
be async?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think we are working towards allowing this to load behavior based on the platform - so in VSCode that would be via an extension, with node it should
be an async file load not a require, and in the browser we will need to load it differently, probably dynamic import. What it needs is to dynamically decide which platform it's using and to attempt to load the schema loading plugin with the matching mechanism. @Neitsch and I were discussing this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have a fix for this now! :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@imolorhe as it turns out, webpack should handle the require method just fine, we will shift towards async imports as well, as should electron/etc, as import() is supported in node 9.7+. The other thing is this is on the server side, so this code won't be loaded by webpack.
@Neitsch if you want to update this for the new file resolution utilities we merged a week or two ago (they are in gls-utils now) they should ensure that this dynamic require()
line works across environments.
also, is it possible we can use graphql-config to load the schema? looks like it has its own capability for this already. check out the latest 3.0.0 alpha, we will be adopting this soon!
Another thing to consider would be if |
I'll close this PR for now, until I/we have a better story around plugin loading. |
@divyenduz what do you think we should do about this? we should be leveraging graphql-config to load the schema correct? |
@Neitsch i think that in order to accomplish this in the ways that you've indicated facebook and other large scale users might need, it could be that making the graphql-config library itself optional (as some have suggested), though the basic config spec format might still be honored if that's so. one should of course be able to provide their own configuration management solution in place of graphql-config, and the interface should expect a configuration object that matches up. so graphql spec, but no graphql-config? what do you think? |
So, to get us started, I've implemented pluggable schema loading. How this works is the following:
schema-loader
that contains two fieldsloaderPackage
andloaderArgs
. The loader package will be dynamically loaded. Subsequently we callinit(loaderArgs)
for it to initialize. (Alternatively we could use ES6 classes)getSchema
, that if called returns the GraphQL Schema it loaded.A couple caveats:
require()
is a good way to do this, but at least the new test passes