Open LorenzoJokhan opened 2 months ago
I encountered a similar issue.
In my case, I separated type definitions into individual files (such as post.model.ts
) and imported them into an index file for the schema.
post.model.ts
import { builder } from '~/lib/graphql/builder';
export const PostStatus = builder.enumType('PostStatus', {
values: ['DRAFT', 'PUBLIC'] as const,
});
builder.prismaObject('PostTag', {
fields: (t) => ({
id: t.exposeString('id'),
post: t.relation('post'),
tag: t.relation('tag'),
}),
});
builder.prismaNode('Post', {
id: { field: 'id' },
findUnique: (id) => ({ id }),
fields: (t) => ({
title: t.exposeString('title'),
emoji: t.exposeString('emoji'),
content: t.exposeString('content'),
status: t.expose('status', { type: PostStatus }),
author: t.relation('author'),
createdAt: t.expose('createdAt', { type: 'DateTime' }),
updatedAt: t.expose('updatedAt', { type: 'DateTime' }),
tags: t.relation('tags'),
}),
});
post/index.ts
import './post.model';
import './post.mutation';
import './post.query';
schema/index.ts
import { builder } from '../builder';
import './post';
import './tag';
import './user';
export const schema = builder.toSchema();
In this setup, during the Vite build, the type definition files imported in schema/index.ts
were being excluded from the build process.
To work around this, I created a load function. Since empty functions are still omitted during the build, I added console logs to ensure the code is included.
post.model.ts
import { builder } from '~/lib/graphql/builder';
export const PostStatus = builder.enumType('PostStatus', {
values: ['DRAFT', 'PUBLIC'] as const,
});
builder.prismaObject('PostTag', {
fields: (t) => ({
id: t.exposeString('id'),
post: t.relation('post'),
tag: t.relation('tag'),
}),
});
builder.prismaNode('Post', {
id: { field: 'id' },
findUnique: (id) => ({ id }),
fields: (t) => ({
title: t.exposeString('title'),
emoji: t.exposeString('emoji'),
content: t.exposeString('content'),
status: t.expose('status', { type: PostStatus }),
author: t.relation('author'),
createdAt: t.expose('createdAt', { type: 'DateTime' }),
updatedAt: t.expose('updatedAt', { type: 'DateTime' }),
tags: t.relation('tags'),
}),
});
// add below
export const loadPostModel = () => {
console.log('Post model loaded');
};
post/index.ts
import { loadPostModel } from './post.model';
import { loadPostMutation } from './post.mutation';
import { loadPostQuery } from './post.query';
export const loadPost = () => {
loadPostModel();
loadPostMutation();
loadPostQuery();
};
schema/index.ts
import { builder } from '../builder';
import { loadPost } from './post';
import { loadTag } from './tag';
import { loadUser } from './user';
// load schemas
loadPost();
loadTag();
loadUser();
export const schema = builder.toSchema();
Hello,
I am having an issue with using the generated PrismaTypes in my graphql server instance using graphql-yoga. When i am running the remix application with npm run dev, then the types are set and i see my scheme:
{ schema: GraphQLSchema { ...TheUsualFields, Organisation: [GraphQLObjectType], Teacher: [GraphQLObjectType], } }
However using npm run build and npm run start results in the scheme without all my types:
{ schema: GraphQLSchema { ...otherFields, _typeMap: [Object: null prototype] { Boolean: [GraphQLScalarType], DateTime: [GraphQLScalarType], Float: [GraphQLScalarType], ID: [GraphQLScalarType], Int: [GraphQLScalarType], JSONObject: [GraphQLScalarType], Mutation: [GraphQLObjectType], Query: [GraphQLObjectType], String: [GraphQLScalarType], __Directive: [GraphQLObjectType], __DirectiveLocation: [GraphQLEnumType], __EnumValue: [GraphQLObjectType], __Field: [GraphQLObjectType], __InputValue: [GraphQLObjectType], __Schema: [GraphQLObjectType], __Type: [GraphQLObjectType], __TypeKind: [GraphQLEnumType] }, _subTypeMap: [Object: null prototype] {}, _implementationsMap: [Object: null prototype] {} } }
[ tsconfig.json ] { "include": [ "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/.server/**/*.ts", "**/.server/**/*.d.ts", "**/.server/**/*.tsx", "**/.client/**/*.d.ts", "**/.client/**/*.tsx" ], "exclude": ["node_modules"], "compilerOptions": { "lib": ["DOM", "DOM.Iterable", "ES2022"], "types": ["@remix-run/node", "vite/client"], "isolatedModules": true, "esModuleInterop": true, "jsx": "react-jsx", "module": "ESNext", "moduleResolution": "Bundler", "resolveJsonModule": true, "target": "ES2022", "strict": true, "allowJs": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "baseUrl": ".", "paths": { "~/": ["./app/"] },
} }
[vite.config] import { sentryVitePlugin } from '@sentry/vite-plugin'; import { vitePlugin as remix } from '@remix-run/dev'; import { defineConfig } from 'vite'; import { installGlobals } from '@remix-run/node'; import tsconfigPaths from 'vite-tsconfig-paths'; import { vercelPreset } from '@vercel/remix/vite';
installGlobals();
export default defineConfig(({}) => { const isProduction = process.env.NODE_ENV === 'production';
return { plugins: [ remix({ presets: [vercelPreset()], future: { v3_fetcherPersist: true, v3_relativeSplatPath: true, v3_throwAbortReason: true, }, }), tsconfigPaths(), sentryVitePlugin({ org: 'savvycodes', project: 'lessenplan-lvs', }), ],
}; });
[Graphql server] // graphql-server.js import { createYoga } from 'graphql-yoga';
import { schema } from './app/services.server/graphql/schema'; export const config = { api: { // Disable body parsing (required for file uploads) bodyParser: false, }, };
const plugins = [];
if (process.env.NODE_ENV === 'production') { // Disable introspection in production build // @todo: persisted-operations or graphql-armor would be a better solution. / eslint-disable react-hooks/rules-of-hooks / // plugins.push(useDisableIntrospection()); }
console.info({ schema });
/**
Create graphql server */ export default createYoga<{ req: Request; res: Response; }>({ // Needed to be defined explicitly because our endpoint lives at a different path other than
/graphql
graphqlEndpoint: '/api/graphql', schema,// We won't handle file uploads via GraphQL so we disable multipart requests which can be used for CSRF attacks multipart: false, plugins, maskedErrors: false, // Boolean(process.env.NODE_ENV === 'production'), });
[Graphql route through remix] import { ActionFunctionArgs, json, LoaderFunctionArgs, } from '@remix-run/server-runtime'; import yoga from '../../graphql.server';
export const loader = async ({ request }: LoaderFunctionArgs) => { return yoga.handleRequest(request, { req: request, res: new Response() }); };
export const action = async ({ request }: ActionFunctionArgs) => { return yoga.handleRequest(request, { req: request, res: new Response() }); };
In development everything works great, but with a production build it does not have any of my own types. Hope that someone can push me in the right direction.
PS: When i navigate to the route /api/graphql i see the message in the editor " "message": "Type Mutation must define one or more fields." "