UNPKG

fuse

Version:

The magical GraphQL framework

265 lines (256 loc) 8.06 kB
// src/next/plugin.ts import path2 from "path"; import { generate, CodegenContext } from "@graphql-codegen/cli"; import { existsSync as existsSync2, promises as fs2, watch as watch2 } from "fs"; import { resolve } from "path"; import { DateTimeResolver, JSONResolver } from "graphql-scalars"; // src/utils/gql-tada.ts import { promises as fs, watch, existsSync } from "fs"; import path from "path"; import { buildSchema, introspectionFromSchema } from "graphql"; import { minifyIntrospectionQuery } from "@urql/introspection"; async function isUsingGraphQLTada(cwd) { const [pkgJson, tsConfig] = await Promise.allSettled([ fs.readFile(path.resolve(cwd, "package.json"), "utf-8"), fs.readFile(path.resolve(cwd, "tsconfig.json"), "utf-8") ]); if (pkgJson.status === "rejected" || tsConfig.status === "rejected") { return false; } try { const parsed = JSON.parse(pkgJson.value); const merged = Object.keys({ ...parsed.dependencies, ...parsed.devDependencies }); if (!merged.find((x) => x.includes("gql.tada"))) { return false; } if (!merged.find((x) => x.includes("@0no-co/graphqlsp"))) { return false; } } catch (e) { return false; } try { const parsed = JSON.parse(tsConfig.value); const lspPlugin = parsed.compilerOptions.plugins.find( (plugin) => plugin.name === "@0no-co/graphqlsp" ); if (!lspPlugin) { return false; } if (!lspPlugin.tadaOutputLocation) { return false; } } catch (e) { return tsConfig.value.includes("@0no-co/graphqlsp") && tsConfig.value.includes("tadaOutputLocation"); } return true; } var tadaGqlContents = `import { initGraphQLTada } from 'gql.tada'; import type { introspection } from './introspection'; export const graphql = initGraphQLTada<{ introspection: typeof introspection; }>(); export type { FragmentOf, ResultOf, VariablesOf } from 'gql.tada'; export type { FragmentOf as FragmentType } from 'gql.tada'; export { readFragment } from 'gql.tada'; export { readFragment as useFragment } from 'gql.tada'; `; var preambleComments = ["/* eslint-disable */", "/* prettier-ignore */"].join("\n") + "\n"; var tsAnnotationComment = [ "/** An IntrospectionQuery representation of your schema.", " *", " * @remarks", " * This is an introspection of your schema saved as a file by GraphQLSP.", " * You may import it to create a `graphql()` tag function with `gql.tada`", " * by importing it and passing it to `initGraphQLTada<>()`.", " *", " * @example", " * ```", " * import { initGraphQLTada } from 'gql.tada';", " * import type { introspection } from './introspection';", " *", " * export const graphql = initGraphQLTada<{", " * introspection: typeof introspection;", " * scalars: {", " * DateTime: string;", " * Json: any;", " * };", " * }>();", " * ```", " */" ].join("\n"); // src/next/plugin.ts var isRunningCodegen = false; function nextFusePlugin(options = {}) { return (nextConfig = {}) => { if (process.env.NODE_ENV === "development" && !isRunningCodegen) { isRunningCodegen = true; isUsingGraphQLTada(process.cwd()).then((isUsing) => { boostrapFuse(isUsing); try { if (isUsing) { let exitHandler2 = function() { try { watcher.close(); } catch (e) { } }; var exitHandler = exitHandler2; let baseDirectory = process.cwd(); const hasSrcDir = existsSync2(resolve(baseDirectory, "src")); if (hasSrcDir) { baseDirectory = resolve(baseDirectory, "src"); } setTimeout(() => { fetch( `http://localhost:${options.port || 3e3}/api/${options.path || "fuse"}?query={__typename}` ); }, 1e3); const watcher = watch2( resolve(baseDirectory, "types"), { recursive: true }, () => { setTimeout(() => { fetch( `http://localhost:${options.port || 3e3}/api/${options.path || "fuse"}?query={__typename}` ); }, 1e3); } ); process.on("exit", exitHandler2); process.on("SIGINT", exitHandler2); process.on("SIGUSR1", exitHandler2); process.on("SIGUSR2", exitHandler2); process.on("uncaughtException", exitHandler2); } else { setTimeout(() => { try { boostrapCodegen(options.port || 3e3, options.path || "fuse"); } catch (e) { } }, 1e3); } } catch (e) { } }); } const newNextConfig = Object.assign({}, nextConfig, { webpack(webpackConfig, webpackOptions) { webpackConfig.module.rules.push({ test: [ /pages[\\/]api[\\/]fuse.ts/, /app[\\/]api[\\/]fuse[\\/]route.ts/, /fuse[\\/]server.ts/ ], use: [ webpackOptions.defaultLoaders.babel, { loader: "fuse/next/loader" } ] }); if (typeof nextConfig.webpack === "function") { return nextConfig.webpack(webpackConfig, webpackOptions); } return webpackConfig; } }); return newNextConfig; }; } async function boostrapFuse(isUsingTada) { let baseDirectory = process.cwd(); try { const hasSrcDir = existsSync2(resolve(baseDirectory, "src")); if (hasSrcDir) { baseDirectory = resolve(baseDirectory, "src"); } if (!existsSync2(baseDirectory + "/fuse")) { await fs2.mkdir(baseDirectory + "/fuse"); } await Promise.allSettled( [ fs2.writeFile( baseDirectory + "/fuse/server.ts", `// This is a generated file! export * from 'fuse/next/server' export { __internal_execute as execute } from 'fuse/next/server' ` ), fs2.writeFile( baseDirectory + "/fuse/client.ts", `// This is a generated file! export * from 'fuse/next/client' ` ), fs2.writeFile( baseDirectory + "/fuse/pages.ts", `// This is a generated file! export * from 'fuse/next/pages' ` ), isUsingTada && fs2.writeFile( path2.resolve(baseDirectory, "fuse/index.ts"), `// This is a generated file! export * from './tada' ` ), isUsingTada && fs2.writeFile( path2.resolve(baseDirectory, "fuse/tada.ts"), tadaGqlContents ) ].filter(Boolean) ); } catch (e) { } } async function boostrapCodegen(port, path3) { let baseDirectory = process.cwd(); const hasSrcDir = existsSync2(resolve(baseDirectory, "src")); if (hasSrcDir) { baseDirectory = resolve(baseDirectory, "src"); } const ctx = new CodegenContext({ filepath: "codgen.yml", config: { ignoreNoDocuments: true, errorsOnly: true, noSilentErrors: true, watch: [ baseDirectory + "/**/*.{ts,tsx}", baseDirectory + "/types/**/*.ts", "!./{node_modules,.next,.git}/**/*" ], documents: [ hasSrcDir ? "./src/**/*.{ts,tsx}" : "./**/*.{ts,tsx}", "!./{node_modules,.next,.git}/**/*" ], schema: `http://localhost:${port}/api/${path3}`, debug: true, generates: { [baseDirectory + "/fuse/"]: { preset: "client", config: { scalars: { ID: { input: "string", output: "string" }, DateTime: DateTimeResolver.extensions.codegenScalarType, JSON: JSONResolver.extensions.codegenScalarType }, avoidOptionals: false, enumsAsTypes: true, nonOptionalTypename: true, skipTypename: false } } } } }); await generate(ctx, true); } export { nextFusePlugin };