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

Support for static *.graphql file to define schema #273

Closed
rogchap opened this Issue Feb 8, 2017 · 38 comments

Comments

Projects
None yet
@rogchap
Contributor

rogchap commented Feb 8, 2017

This was breifly mentioned by @stubailo here: #124 (comment)

What I've found is that as my project grows it's increasingly harder to read my schema as it's formatted as a single string. (especially when you're diligently adding descriptions for everything).

We want all of this: https://dev-blog.apollodata.com/5-benefits-of-static-graphql-queries-b7fa90b0b69a but on the server.

@stubailo

This comment has been minimized.

Member

stubailo commented Feb 8, 2017

Great! I think a require hook could be a good first step - then you can just require .graphql files.

@helfer helfer changed the title from Support for static *.graphql file to define shema to Support for static *.graphql file to define schema Feb 10, 2017

@rogchap

This comment has been minimized.

Contributor

rogchap commented Feb 10, 2017

@stubailo Yea that would be awesome. I'll have a crack at putting this PR together.

For the "hook", there is only one way to do this but it's technically depreciated:
https://nodejs.org/api/globals.html#globals_require_extensions

Since the module system is locked, this feature will probably never go away. However, it may have subtle bugs and complexities that are best left untouched.

Other modules are still using this, are we ok with this, I don't know of an alternative?

Also, is there a suitable place to have this extension initiated?

@DxCx

This comment has been minimized.

Member

DxCx commented Feb 11, 2017

i think i saw webpack plugin which gives you the ability to just import them..
but that was for graphql-tag client side.
maybe we should add such loader to graphql-tools?

@rogchap

This comment has been minimized.

Contributor

rogchap commented Feb 20, 2017

So, this should be straightforward however, it does not play nice with TypeScript.

Problem 1: [ts] Can't find module myRootQuery.graphql - This can be resolved by using require instead of import
Problem 2: TypeScript has no --copy-files, therefore won't copy any non-ts/js files to the output dir

Anybody have any smart idea's?

Don't want to have to use a build script / gulp etc.

@bman654

This comment has been minimized.

bman654 commented Feb 21, 2017

This is what I've been doing on the server to "import" a graphql file. Not as pretty, but easy enough:

// read schema.graphql file in same folder as this module
const schema = [fs.readFileSync(path.join(__dirname, "schema.graphql"), "utf8")];
@advance512

This comment has been minimized.

advance512 commented Mar 10, 2017

I've been using require-text for this.

@rigobcastro

This comment has been minimized.

rigobcastro commented Mar 12, 2017

It's a good temp solution @bman654 Thanks!

@abdulhaq-e

This comment has been minimized.

Contributor

abdulhaq-e commented Mar 20, 2017

With TS > 2.0 you can use a wildcard when declaring a module type:

declare module "*.graphql" {
    const value: any;
    export default value;
}

Then you can import it just like a .ts file. (Edit: a loader is still required)

@stubailo

This comment has been minimized.

Member

stubailo commented Mar 20, 2017

@abdulhaq-e whoa - do you have to use that with require-text as well, or does it just work?

@abdulhaq-e

This comment has been minimized.

Contributor

abdulhaq-e commented Mar 20, 2017

Sorry I just tried it and a loader is required.

typings.d.ts:

declare module "*.graphql" {
    const value: any;
    export default value;
}

code:

import * as query from query.graphql

For this to work, a loader such as raw-loader for those using webpack will work.

    module: {
      rules: [
        { test: /\.json$/, loader: 'json-loader' },
        { test: /\.html$/, loader: 'raw-loader' },
        { test: /\.graphql$/, loader: 'raw-loader' },
      ]
@advance512

This comment has been minimized.

advance512 commented Mar 21, 2017

A loader is required if you build your server with Webpack.
If you're just using Node.js directly (as you probably should in case of a GraphQL/API endpoint), loaders don't help.

@helfer

This comment has been minimized.

Member

helfer commented Mar 21, 2017

We should suggest a solution in the docs that doesn't require a loader. Most people don't want to use webpack or similar on the server for good reasons.

@DxCx

This comment has been minimized.

Member

DxCx commented Mar 21, 2017

@helfer im not familiar with that most people prefere not to use webpack for server side as well,
can you give example of the good reasons?

@advance512

This comment has been minimized.

advance512 commented Mar 21, 2017

A much more complex build process, more difficult debugging and deploying, and little if any added benefits for GraphQL/API type servers.

What are you bundling, after all?

@DxCx

This comment has been minimized.

Member

DxCx commented Mar 21, 2017

well, bundling gives you alot of power when you go from typescript to javascript...
for example, how much output(s) do you want? where?
also, being able to hook the output gives more values (for example, i've written a plugin which instruments the whole output, so you know exactly how much code is covered out of the whole product you are going to deploy)
maybe it's just me who's appreciate those things..

@advance512

This comment has been minimized.

advance512 commented Mar 23, 2017

These are great things, but I think they're rather better left for the CI and not hidden inside webpack.config..js files..

As for transpiling from TypeScript, I admit I have no experience with that as of yet, so I don't know. I do know that using webpack should be optional.

@jamiter

This comment has been minimized.

Contributor

jamiter commented Mar 27, 2017

Meteor now has a loader for this that allows you to simply import the schema file:

import schema from './schema.graphql'

Underwater this uses the webpack loader from graphql-tag which doesn't return a string, but a parsed schema. It works for the server and client.

Sadly, makeExecutableSchema only accepts strings, so now I need to parse it back again before passing it on:

import schema from './schema.graphql'
import { print } from 'graphql/language/printer';

const schema = makeExecutableSchema({
  typeDefs: print(schema),
  resolvers,
});

What do you all expect from a loader or a require hook to return when importing .graphql files? A string, or the result of parsed schema like the webpack loader in graphql-tag returns? If the latter, then makeExecutableSchema shouldn't just allow strings.

Perhaps this should be discussed in a separate issue, but support for a schema object, and not only a string, would be great.

@stubailo

This comment has been minimized.

Member

stubailo commented Mar 27, 2017

@jamiter actually it might be nice if makeExecutableSchema could accept Schema ASTs just as well as strings, it would just be a matter of running print.

@jamiter

This comment has been minimized.

Contributor

jamiter commented Mar 27, 2017

Cool, I'll make a PR for that!

@jamiter jamiter referenced this issue Mar 28, 2017

Merged

Support schema AST as type definition #300

5 of 5 tasks complete
@jamiter

This comment has been minimized.

Contributor

jamiter commented Mar 28, 2017

@stubailo, see #300

@helfer

This comment has been minimized.

Member

helfer commented Mar 29, 2017

Just merged #300 which should make this possible.

@helfer helfer closed this Mar 29, 2017

@Isigiel

This comment has been minimized.

Isigiel commented May 27, 2017

I am still unclear on the best way to use static schema files on a typescript + node server without webpack. Is there currently a solution to this Problem?

@stubailo

This comment has been minimized.

Member

stubailo commented May 29, 2017

@Isigiel right now there isn't really anything in graphql-tools preventing you from doing that, sounds like you are looking for some kind of static file loader for node. Basically you need something that will let you import or read .graphql files, and then you should just pass the resulting strings into makeExecutableSchema?

@Isigiel

This comment has been minimized.

Isigiel commented May 29, 2017

Yeah right, but I'm unclear on how to import them, webpack seems overkill and just fs.rading them does not work because tsc does not copy the files.
Right now to me, the best option seems to be, have a second gulp task running that will watch the files and copy the graphql files. I was mainly wondering if someone had come up with a more elegant solution.

@jelder

This comment has been minimized.

jelder commented Sep 6, 2017

@Isigiel https://github.com/quadric/babel-plugin-inline-import seems like a good option, if you're already using Babel.

@vincenzo

This comment has been minimized.

vincenzo commented Dec 23, 2017

One issue you have using babel-plugin-inline-import is when you use nodemon. Even if you tell it to monitor .graphql files, the changes to the schema will not be reloaded from file when nodemon is triggered. One must make a change to the file importing the schema in order for that to happen. Developers suggest disabling babel cache, but that doesn't seem like a wise idea.

@stubailo

This comment has been minimized.

Member

stubailo commented Dec 28, 2017

Maybe this tool can also work? https://github.com/graphcool/graphql-import

@ericnograles

This comment has been minimized.

ericnograles commented Jan 18, 2018

Here's a quick way to assemble .graphql strings as one to load into makeExecutableSchema that I've been using: https://gist.github.com/ericnograles/d59e32f244c9ea04e69f66a7caa96940

It'll sweep through .graphql files in a folder and assemble all of them, leaving Query.graphql for the last concat, and finally export out the finished string for usage.

@vincenzo

This comment has been minimized.

vincenzo commented Jan 18, 2018

@stubailo graphql-import is definitely the way to go -- it's also included in https://github.com/graphcool/graphql-yoga, which I would suggest anyone check out.

@ericnograles

This comment has been minimized.

ericnograles commented Jan 18, 2018

graphql-import def looks slick, will need to check that out!

@iamlothian

This comment has been minimized.

iamlothian commented Jan 23, 2018

I am trying to make use of graphql-import with typescript, It loads files fine but I still have to find a way to copy the .qraphql files to a dist folder... which mean involving some more complex build steps. And the idea of maintain both a AST version and AST.ts string version is not ideal.

I'm considering trying out something like the following:
Folder structure for a singe entity

- Book
-- index.ts
-- query.qraphql
-- query.qraphql.ts
-- resolver.ts
-- schema.qraphql
-- schema.qraphql.ts

*.qraphql.ts

import { importSchema } from "graphql-import"
export const Query:string = importSchema(__dirname + '/' + __filename.replace('.ts',''));

when i build i want to take the *.qraphql content and replace the importSchema with the actual qraphql string. so that the dist folder will contain a baked version of the qraphql at build time.

Thoughts?

@vincenzo

This comment has been minimized.

vincenzo commented Jan 23, 2018

@iamlothian I think it's fair to assume that if you take your query to https://github.com/graphcool/graphql-import (open an issue there), the maintainer could help you with that.

@iamlothian

This comment has been minimized.

iamlothian commented Jan 23, 2018

@vincenzo thanks, here is a link for reference

@eliperelman

This comment has been minimized.

eliperelman commented Feb 22, 2018

In a similar vein to @ericnograles's solution, if you are using webpack for Node.js, you can use raw-loader for .graphql files, then use webpack's require.context to load them all as a string:

// ./graphql/index.js

const importer = require.context('./', true, /\.graphql$/);
const keys = importer.keys();
const root = './Query.graphql';

module.exports = [
  ...keys
    .filter(key => key !== root)
    .reduce(
      (typeDefs, key) => typeDefs.add(importer(key)),
      new Set([importer(root)])
    ),
].join('\n');

You can then import this and pass it to makeExecutableSchema:

import { makeExecutableSchema } from 'graphql-tools';
import typeDefs from './graphql';

makeExecutableSchema({ typeDefs });
@mxmzb

This comment has been minimized.

mxmzb commented Mar 19, 2018

You could also take a very dumb approach and copy your .graphql files to your /dist folder with webpack plugin, like: https://github.com/webpack-contrib/copy-webpack-plugin

@FredericLatour

This comment has been minimized.

FredericLatour commented May 6, 2018

Hi,
In case you are still looking for an option I use "copyfiles" node module for this.

package.json
"scripts": {
     
     "build": "yarn run build-ts && copyfiles -u 1 src/*.json src/*.yml src/config/*.* dist"
     
}

You could easily add your ".graphql" files.

@webberwang

This comment has been minimized.

webberwang commented Oct 18, 2018

GraphQL Import works great with importing .graphql

const typeDefs = importSchema('./schema.graphql')

but it requires a Node.js environment & won't work for the front end. The only solution for the browser side is using a Webpack loader for .graphql files, but I hadn't been able to get the loader working with a CRA Typescript version yet.

@nutboltu

This comment has been minimized.

nutboltu commented Dec 5, 2018

I didn't want to use webpack just to copy .graphql files to the dist folder.
I used cpx package to copy my .graphql files keeping same file tree structure. It works fine.

Here's my package.json

"scripts": {
  "copy-schemas": "$(npm bin)/cpx src/**/*.graphql dist",
  "start": "tsc && npm run copy-schemas && node ./dist/index.js"
}

MatiasOlivera added a commit to MatiasOlivera/feedy that referenced this issue Dec 16, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment