feat: allow control over nexus schema import id (#408)

Currently the typegen output is designed with the assumption that @nexus/schema will be available at node_modules/@nexus/schema. This assumes that either the project depends on @nexus/schema or that @nexus/schema has been hoisted. The former is fine but does not support being wrapped by another tool, while the latter is liable to result in module not found errors for hard-to-debug reasons (especially users who know little or nothing about the internals).
This commit is contained in:
Jason Kuhrt 2020-04-07 11:36:14 -04:00 committed by GitHub
parent 358c33efaa
commit a6c29bae64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 12 deletions

View File

@ -285,6 +285,18 @@ export interface TypegenInfo {
* The type of the context for the resolvers * The type of the context for the resolvers
*/ */
contextType?: string; contextType?: string;
/**
* The path to the @nexus/schema package.
*
* @default '@nexus/schema'
*
* @remarks
*
* This setting is particularly useful when @nexus/schema is being wrapped by
* another library/framework such that @nexus/schema is not expected to be a
* direct dependency at the application level.
*/
nexusSchemaImportId?: string;
} }
export type TypeToWalk = export type TypeToWalk =
@ -1629,7 +1641,6 @@ export function makeSchemaInternal(config: SchemaConfig) {
export function makeSchema(config: SchemaConfig): NexusGraphQLSchema { export function makeSchema(config: SchemaConfig): NexusGraphQLSchema {
const { schema, missingTypes, finalConfig } = makeSchemaInternal(config); const { schema, missingTypes, finalConfig } = makeSchemaInternal(config);
const typegenConfig = resolveTypegenConfig(finalConfig); const typegenConfig = resolveTypegenConfig(finalConfig);
if (typegenConfig.outputs.schema || typegenConfig.outputs.typegen) { if (typegenConfig.outputs.schema || typegenConfig.outputs.typegen) {
// Generating in the next tick allows us to use the schema // Generating in the next tick allows us to use the schema
// in the optional thunk for the typegen config // in the optional thunk for the typegen config

View File

@ -113,6 +113,18 @@ export interface ConnectionPluginConfig {
* Prefix for the Connection / Edge type * Prefix for the Connection / Edge type
*/ */
typePrefix?: string; typePrefix?: string;
/**
* The path to the @nexus/schema package. Needed for typegen.
*
* @default '@nexus/schema'
*
* @remarks
*
* This setting is particularly useful when @nexus/schema is being wrapped by
* another library/framework such that @nexus/schema is not expected to be a
* direct dependency at the application level.
*/
nexusSchemaImportId?: string;
} }
// Extract the node value from the connection for a given field. // Extract the node value from the connection for a given field.
@ -340,7 +352,8 @@ export const connectionPlugin = (
name: "ConnectionPlugin", name: "ConnectionPlugin",
fieldDefTypes: [ fieldDefTypes: [
printedGenTypingImport({ printedGenTypingImport({
module: getOwnPackage().name, module:
connectionPluginConfig?.nexusSchemaImportId ?? getOwnPackage().name,
bindings: ["core", "connectionPluginCore"], bindings: ["core", "connectionPluginCore"],
}), }),
], ],

View File

@ -2,7 +2,7 @@ import { GraphQLNamedType, GraphQLSchema, isOutputType } from "graphql";
import path from "path"; import path from "path";
import { TypegenInfo } from "./builder"; import { TypegenInfo } from "./builder";
import { TYPEGEN_HEADER } from "./lang"; import { TYPEGEN_HEADER } from "./lang";
import { log, objValues, relativePathTo } from "./utils"; import { getOwnPackage, log, objValues, relativePathTo } from "./utils";
/** /**
* Any common types / constants that would otherwise be circular-imported * Any common types / constants that would otherwise be circular-imported
@ -327,6 +327,7 @@ export function typegenAutoConfig(options: TypegenAutoConfigOptions) {
backingTypeMap, backingTypeMap,
imports, imports,
contextType, contextType,
nexusSchemaImportId: getOwnPackage().name,
}; };
return typegenInfo; return typegenInfo;

View File

@ -12,6 +12,7 @@ import { TypegenPrinter } from "./typegenPrinter";
export interface TypegenMetadataConfig export interface TypegenMetadataConfig
extends Omit<BuilderConfig, "outputs" | "shouldGenerateArtifacts"> { extends Omit<BuilderConfig, "outputs" | "shouldGenerateArtifacts"> {
nexusSchemaImportId?: string;
outputs: { outputs: {
schema: false | string; schema: false | string;
typegen: false | string; typegen: false | string;
@ -27,7 +28,7 @@ export class TypegenMetadata {
constructor(protected config: TypegenMetadataConfig) {} constructor(protected config: TypegenMetadataConfig) {}
/** /**
* Generates the artifacts of the buid based on what we * Generates the artifacts of the build based on what we
* know about the schema and how it was defined. * know about the schema and how it was defined.
*/ */
async generateArtifacts(schema: NexusGraphQLSchema) { async generateArtifacts(schema: NexusGraphQLSchema) {
@ -69,7 +70,7 @@ export class TypegenMetadata {
if (typeof filePath !== "string" || !path.isAbsolute(filePath)) { if (typeof filePath !== "string" || !path.isAbsolute(filePath)) {
return Promise.reject( return Promise.reject(
new Error( new Error(
`Expected an absolute path to output the GraphQL Nexus ${type}, saw ${filePath}` `Expected an absolute path to output the Nexus ${type}, saw ${filePath}`
) )
); );
} }
@ -163,6 +164,7 @@ export class TypegenMetadata {
} }
return { return {
nexusSchemaImportId: this.config.nexusSchemaImportId,
headers: [TYPEGEN_HEADER], headers: [TYPEGEN_HEADER],
imports: [], imports: [],
contextType: "any", contextType: "any",

View File

@ -55,6 +55,10 @@ type RootTypeMapping = Record<
string | Record<string, [string, string]> string | Record<string, [string, string]>
>; >;
interface TypegenInfoWithFile extends TypegenInfo {
typegenFile: string;
}
/** /**
* We track and output a few main things: * We track and output a few main things:
* *
@ -72,11 +76,11 @@ type RootTypeMapping = Record<
*/ */
export class TypegenPrinter { export class TypegenPrinter {
groupedTypes: GroupedTypes; groupedTypes: GroupedTypes;
printImports: Record<string, Record<string, any>>; printImports: Record<string, Record<string, boolean | string>>;
constructor( constructor(
protected schema: NexusGraphQLSchema, protected schema: NexusGraphQLSchema,
protected typegenInfo: TypegenInfo & { typegenFile: string } protected typegenInfo: TypegenInfoWithFile
) { ) {
this.groupedTypes = groupTypes(schema); this.groupedTypes = groupTypes(schema);
this.printImports = {}; this.printImports = {};
@ -153,18 +157,21 @@ export class TypegenPrinter {
const imports: string[] = []; const imports: string[] = [];
const importMap: Record<string, Set<string>> = {}; const importMap: Record<string, Set<string>> = {};
const outputPath = this.typegenInfo.typegenFile; const outputPath = this.typegenInfo.typegenFile;
// For backward compat. const nexusSchemaImportId =
this.typegenInfo.nexusSchemaImportId ?? getOwnPackage().name;
const packName = getOwnPackage().name; if (!this.printImports[nexusSchemaImportId]) {
if (!this.printImports[packName]) {
if ( if (
[dynamicInputFields, dynamicOutputFields].some( [dynamicInputFields, dynamicOutputFields].some(
(o) => Object.keys(o).length > 0 (o) => Object.keys(o).length > 0
) )
) { ) {
this.printImports[packName] = { core: true }; this.printImports[nexusSchemaImportId] = {
core: true,
};
} }
} }
eachObj(rootTypings, (val, key) => { eachObj(rootTypings, (val, key) => {
if (typeof val !== "string") { if (typeof val !== "string") {
const importPath = (path.isAbsolute(val.path) const importPath = (path.isAbsolute(val.path)

View File

@ -1,6 +1,6 @@
import { BuilderConfig } from "./builder"; import { BuilderConfig } from "./builder";
import { TypegenMetadataConfig } from "./typegenMetadata"; import { TypegenMetadataConfig } from "./typegenMetadata";
import { assertAbsolutePath } from "./utils"; import { assertAbsolutePath, getOwnPackage } from "./utils";
/** /**
* Normalizes the builder config into the config we need for typegen * Normalizes the builder config into the config we need for typegen
@ -36,6 +36,7 @@ export function resolveTypegenConfig(
return { return {
...rest, ...rest,
nexusSchemaImportId: getOwnPackage().name,
outputs: { outputs: {
typegen: shouldGenerateArtifacts ? typegenPath : false, typegen: shouldGenerateArtifacts ? typegenPath : false,
schema: shouldGenerateArtifacts ? schemaPath : false, schema: shouldGenerateArtifacts ? schemaPath : false,