What happens to "typeDefs: './src/schema.graphql'" in production builds?
zadigus opened this issue · comments
Hi,
This might not be an issue as I didn't actually test it but GraphQLServer instance is initialized with
typeDefs: './src/schema.graphql'.
While this is no problem on dev builds, because we start the server with
ts-node src/index.ts
and thus the './src/schema.graphql' is accessible, this might be a problem on production builds where the typescript code is compiled into javascript code in a 'dist' folder. In that case, only the files present in that folder are deployed to the server which has no reference any more to the './src/schema.graphql' file! As I haven't seen any particular rule in the tsconf file to handle this, I suppose this will not work on production builds.
Cheers
I posted a question related to this here: prisma-labs/graphql-import-loader#11. I still have no idea how to solve this.
Ok. Here's how I solved it:
First, I integrated graphql-import-loader and webpack into my framework:
package.json
[...]
"devDependencies": {
[...]
"graphql-import-loader": "^0.2.1",
[...]
"webpack": "^4.6.0",
"webpack-cli": "^2.0.15",
"webpack-node-externals": "^1.7.2"
}
[...]
"scripts": {
"start": "node server/main.js",
"start:dev": "webpack --config ./webpack.dev.js --watch",
"dev": "npm-run-all --parallel start playground",
"debug": "dotenv -- nodemon -e ts,graphql -x ts-node --inspect src/index.ts",
"clean": "rimraf server",
"playground": "graphql playground",
"build": "npm run clean && webpack --config ./webpack.prod.js",
"deploy:prisma": "cross-var prisma login --key $PRISMA_SERVICE_TOKEN && prisma deploy",
"postinstall": "npm run deploy:prisma && npm run build"
},
[...]
With the above config, I am able to launch a dev server that restarts everytime I change something to the code and I can build the production server too. The graphql-import-loader package allows to load graphql files in the code, so that I can do this:
index.ts
import { GraphQLServer } from 'graphql-yoga';
import { Prisma } from './generated/prisma';
import resolvers from './resolvers';
import * as typeDefs from './schema.graphql';
const server = new GraphQLServer({
typeDefs,
resolvers,
resolverValidationOptions: {
requireResolversForResolveType: false
},
context: req => ({
...req,
db: new Prisma({
endpoint: process.env.PRISMA_ENDPOINT,
secret: process.env.PRISMA_SECRET,
debug: true
})
})
});
[...]
The important change here above is
import * as typeDefs from './schema.graphql';
It could also be a
import typeDefs = require('./schema.graphql');
When the code has been generated for production, then I don't care about the 'src/schema.graphql' any more as well as any of its dependencies in the 'src/generated/' folder.
In order for this to work, though, I need the following typings declaration:
typings.d.ts
declare module '*.graphql' {
const content: any
export = content
}
Here the important part is the syntax to export the content. Indeed, I did not do a
export default content
as this doesn't work. Of course, the tsconfig.json is updated in such a way that this typings declaration is taken into account.
Then, I wrote the following webpack configs:
webpack.dev.js
const webpack = require('webpack');
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const NodemonPlugin = require( 'nodemon-webpack-plugin' )
module.exports = {
target: 'node',
entry: './src/index.ts',
externals: [nodeExternals()],
output: {
filename: '[name].js',
chunkFilename: '[name].js',
path: path.resolve(__dirname, 'server'),
libraryTarget: 'commonjs'
},
resolve: {
extensions: ['.graphql', '.ts', '.js', '.json']
},
node: {
fs: 'empty'
},
module: {
rules: [
{
exclude: /node_modules/,
test: /\.ts$/,
use: [
{ loader: 'babel-loader' },
{ loader: 'ts-loader' },
],
},
{
test: /\.json$/,
exclude: /node_modules/,
loader: 'json-loader'
},
{
test: /\.graphql$/,
exclude: /node_modules/,
loader: 'graphql-import-loader'
}
]
},
plugins: [
new NodemonPlugin()
],
mode: 'development'
};
as well as
webpack.prod.js
const webpack = require('webpack');
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
target: 'node',
entry: './src/index.ts',
externals: [nodeExternals()],
output: {
filename: '[name].js',
chunkFilename: '[name].js',
path: path.resolve(__dirname, 'server'),
libraryTarget: 'commonjs'
},
resolve: {
extensions: ['.graphql', '.ts', '.js', '.json']
},
node: {
fs: 'empty'
},
module: {
rules: [
{
exclude: /node_modules/,
test: /\.ts$/,
use: [
{ loader: 'babel-loader' },
{ loader: 'ts-loader' },
],
},
{
test: /\.json$/,
exclude: /node_modules/,
loader: 'json-loader'
},
{
test: /\.graphql$/,
exclude: /node_modules/,
loader: 'graphql-import-loader',
}
]
},
plugins: [new UglifyJSPlugin()],
mode: 'production',
optimization: {
splitChunks: {
chunks: 'async',
minSize: 30000,
minChunks: 1,
name: false,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
}
}
}
}
};