npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

graphql-let

v0.18.6

Published

A webpack loader/babel-plugin/babel-plugin-macros/CLI/generated file manager of GraphQL code generator.

Downloads

84,965

Readme

graphql-let Node CI npm version downloads Babel Macro Stake to support us

A webpack loader/babel-plugin/babel-plugin-macros/CLI/generated file manager of GraphQL code generator.

Try Create React App example and Next.js example integrating graphql-let. A blog post

🛰 Migration guide to v0.18.0

Table of Contents

Why this exists

One of the strengths of GraphQL is enforcing data types on runtime. Further, TypeScript and GraphQL code generator help it even safer by typing your codebase statically. Both make a truly type-protected development environment with rich IDE assists.

graphql-let enhances that development pattern by minimizing configuration setup, introducing intuitive syntax, and comfortable development experience through HMR (hot module replacement).

import { useNewsQuery } from './news.graphql' // webpack
// or
import { gql, load } from "graphql-let/macro" // babel-plugin-macros
const { useNewsQuery } = gql("query News { braa }")

const News: React.FC = () => {
    // Typed already️⚡️
    const { data: { news } } = useNewsQuery()
    return <div>{news.map(...)}</div>
}

Entrypoints and features

Summary of characteristics of each entrypoint.

  • CLI for efficient code generation before your type checking
  • webpack loader to get HMR even on modifying GraphQL documents
  • babel-plugin-macros for the minimum configuration
  • Babel plugin if you don't want babel-plugin-macros

All of them mostly do the same behind the scene.

  1. Loads your configuration from .graphql-let.yml
  2. Finds GraphQL documents (queries, mutations, subscriptions) from .graphql* and .ts* specified in your config.documents
  3. Processes and passes arguments to GraphQL code generator to generate .ts* s. These are used for runtime.
  4. It also generates the corresponding .d.ts s of the codegen results. These are used for typing checking / IDE code completion.

Note there are a few differences between the entrypoints.

There are things to make graphql-let light and stable.

  • Sharing the processes. Generating files is expensive, so it runs less time to run GraphQL code generator and TypeScript API.
  • Caching. Embedding hashes, as your source states, reduces the number of unnecessary processing.
  • Sharing the promises. The webpack compilation in typical SSR applications as Next.js runs targets of "node" and "web" simultaneously. If sources are the same, the compilation should be once.

Getting started with webpack loader

This is an example of TypeScript + React + Apollo Client on webpack. You may want TypeScript Vue Apollo or TypeScript Urql. Please replace the corresponding lines depending on your needs.

1. Install dependencies

Note graphql-let is in devDependencies.

# Prerequisites
yarn add -D typescript graphql

# Install graphql-let with its peer dependencies
yarn add -D graphql-let @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/import-types-preset

# Install GraphQL code generator plugins depending on your needs. These are in `plugins` of your .graphql-let.yml.
yarn add -D @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo

# Other libraries depending on your scenario
yarn add @apollo/client

2. Configure .graphql-let.yml

Run this command to generate a configuration template.

yarn graphql-let init
# This will generate .graphql-let.yml

Next, add graphql-codegen plugins in it. Please note that you have to generate a TypeScript source by the plugins.

Edit it like this:

  schema: lib/type-defs.graphqls
  documents:
    - '**/*.graphql'
    - '**/*.tsx'
  plugins:
+   - typescript-operations
+   - typescript-react-apollo

3. Check your cacheDir

cacheDir will have .ts(x)s that your sources will import. It's node_modules/.cache/graphql-let by default, but you may exclude node_modules for webpack compilation. In that case, we recommend setting up like this.

  schema: lib/type-defs.graphqls
  documents:
    - '**/*.graphql'
    - '**/*.tsx'
  plugins:
    - typescript-operations
    - typescript-react-apollo
+ cacheDir: .cache

Please note that files in cacheDir are only intermediate cache, possibly having wrong import paths. Your tsconfig.json probably complains, so give it a line for exclusion.

  // tsconfig.json
  {
+   "excludes": [".cache"]
  }

Also, remember you have to .gitignore the .cache directory in the next section.

3. Add lines to .gitignore

graphql-let will generate .d.ts files in the same folder of .graphql. Add these lines in your .gitignore.

+ *.graphql.d.ts
+ *.graphqls.d.ts
+ /.cache

4. Configure webpack.config.ts

The webpack loader also needs to be configured. Note that the content that graphql-let/loader generates is JSX-TypeScript. You have to compile it to JavaScript with an additional loader such as babel-loader.

  const config: Configuration = {
    module: {
      rules: [
+       {
+         test: /\.(tsx|graphql)$/,
+         use: [
+           { loader: 'babel-loader', options: { presets: ['@babel/preset-typescript', '@babel/preset-react'] } },
+           { loader: 'graphql-let/loader' },
+         ]
+       }
      ]
    }
  }

5. Generate type declarations

Run this to generate .d.ts.

yarn graphql-let

# This will generate files such as:
#   - src/query.graphql.d.ts
#   - src/schema.graphqls.d.ts

By --config option, you can specify the custom path to the .graphql-let.yml. The directory .graphql-let.yml is located at is the basepath of the relative paths in .grpahql-let.yml. Also, the basepath should be identical to webpack's config.context so the loader can find the config file.

pwd # "/app"
yarn graphql-let --config custom/path/.graphql-let.yml

# This will point paths such as:
# /app/custom/path/src/query.graphql.d.ts
# /app/custom/path/src/schema.graphqls.d.ts

You may want to run it every time before calling tsc. Please check your package.json and modify like this.

   "scripts": {
-     "build": "tsc"
+     "build": "graphql-let && tsc"
   },

6. Run webpack serve and Code

Enjoy HMR (Hot Module Replacement) of webpack with the generated react-apollo hooks and IDE code assists.

import { gql } from 'graphql-let'
import { useNewsQuery } from './news.graphql'

const { useViewerQuery } = gql(`query Viewer { blaa }`)

const News: React.FC = () => {
    // Already typed⚡️
    const { data: { news } } = useNewsQuery()
    const { data: { viewer } } = useViewerQuery()
    return <div>{ news.map(...) }</div>
}

Getting started with babel-plugin-macros

babel-plugin-macros requires the least configuration to setup.

Please finish 1. Install dependencies, and 2. Configure .graphql-let.yml as you still need .graphql-let.yml.

3. Make sure your babel-plugin-macros is ready

Put a line "plugins": ["macros"] to your .babelrc. If you use Create React App, it contains babel-plugin-macros out of the box.

If you want a custom path to .graphql-let.yml, you can use configFilePath babel option. <projectRoot>${configFilePath} should point to your .graphql-let.yml.

4. Code

Thanks to babel-plugin-macros's beautiful architecture, you're ready to use GraphQL codegen values.

import { gql, load } from "graphql-let/macro"

// Typed⚡️
const { useNewsQuery } = gql("query News { braa }")
const { useViewerQuery } = load("./viewer.graphql")

Note that your schema types are generated in graphql-let/__generated__/__types__, instead of per-document outputs.

import { News } from 'graphql-let/__generated__/__types__'

Getting started with Babel Plugin

Mostly the same as babel-plugin-macros, only you need to import "graphql-let".

Please finish 1. Install dependencies and 2. Configure .graphql-let.yml as you still need .graphql-let.yml.

3. Setup .babelrc

  {
+   "plugins": ["graphql-let/babel"]
  }

4. Code

import { gql, load } from "graphql-let"

const { useNewsQuery } = gql("query News { braa }")
const { useViewerQuery } = load("./viewer.graphql")

Difference between .graphql-let.yml and codegen.yml

graphql-let half passes your config options to GraphQL code generator API and half controls them. Here explains how different these and why. You can see this section as a migration guide, too.

  schema: https://api.github.com/graphql
  documents: "**/*.graphql"
- generates:
-     ./__generated__/operations.ts:
-         config:
-             key: value
-         plugins:
-             - typescript
-             - typescript-operations
-         preset: xxx
+ plugins:
+     - typescript-operations
+ config:
+     key: value

Plugin typescript should not be specified

You have to have @graphql-codegen/typescript as a dev dependency. graphql-let generates types by default, where it uses the plugin. The plugins in .graphql-let.yml is for per-document, which imports the shared types automatically. If you specify typescript as a plugin, it's still okay, but you can imagine it's kind of redundant.

No generates

codegen.yml has an option generates, but it's strictly controlled under graphql-let. Rather, think graphql-let as a tool to let you forget intermediate outputs and import/call GraphQL directly.

Therefore, we don't support output-file level configuration such as Output-file level schema, Output-file level documents, and Output Level config right now. But this could be changed logically, so please vote by issuing if you'd like.

No preset

Presets decide how to split/import each other, which graphql-let manages basically. graphql-let generates per-document .d.ts and binds up schema types into a shared file, that's why @graphql-codegen/import-types-preset is our peer dependency.

I think you don't need to configure Presets, because graphql-let takes care of what Presets does on your behalf. If you notice the use-case you need more flexibility, please issue it.

Limitation: documents expects string | string[]

Document-level options such as noRequir or Custom Document Loader are not supported.

graphql-let specific options

In addition to codegen.yml options, graphql-let accepts these.

# "plugins", required. The plugins for GraphQL documents to run GraphQL code
# generator with. You should omit `typescript` plugin which graphql-let generates internally.
# See here for more information. https://graphql-code-generator.com/docs/plugins/index
# Example:
plugins:
    - typescript-operations
    - typescript-react-apollo
    - add: "/* eslint-disable */"

# "respectGitIgnore", optional. `true` by default.
# If true, graphql-let will ignore files in .gitignore.
# Useful to prevent parsing files in such as `node_modules`.
respectGitIgnore: true

# "cacheDir", optional. `node_modules/.cache/graphql-let` by default.
# graphql-let takes care of intermediate `.ts(x)`s that GraphQL code generator
# generates, but we still need to write them on the disk for caching and
# TypeScript API purposes. This is the directory we store them to.
# Examples:
cacheDir: node_modules/.cache/graphql-let
cacheDir: .cache

# "TSConfigFile", optional. `tsconfig.json` by default.
# You can specify a custom config for generating `.d.ts`s.
# Examples:
TSConfigFile: tsconfig.json
TSConfigFile: tsconfig.compile.json

# "typeInjectEntrypoint", optional.
# `node_modules/@types/graphql-let/index.d.ts` by default. Needs to end with ".d.ts".
# Used as an entrypoint and directory of generated type declarations
# for `gql()` and `load()` calls.
typeInjectEntrypoint: node_modules/@types/graphql-let/index.d.ts

# "silent", optional. `false` by default.
# Pass `true` if you want to suppress all standard output from graphql-let.
silent: false

Simple example:

schema: "schema/**/*.graphqls"
documents:
    - "**/*.graphql"
    - "!shouldBeIgnored1"
plugins:
    - typescript-operations
    - typescript-react-apollo

Example with a bit more complicated options:

schema:
    - https://api.github.com/graphql:
          headers:
              Authorization: YOUR-TOKEN-HERE
documents:
    - "**/*.graphql"
    - "!shouldBeIgnored1"
plugins:
    - typescript-operations
    - typescript-react-apollo
respectGitIgnore: true
config:
    reactApolloVersion: 3
    apolloReactComponentsImportFrom: "@apollo/client/react/components"
    useIndexSignature: true
cacheDir: .cache
TSConfigFile: tsconfig.compile.json
typeInjectEntrypoint: typings/graphql-let.d.ts

Limitations of graphql-let/babel

Jest Transformer

graphql-let/jestTransformer is available. Configure your jest.config.js as:

  module.exports = {
    transform: {
+     "\\.graphql$": "graphql-let/jestTransformer",
    },
  };

Use babel-jest in Jest

babel-jest is the default subsequent transformer of graphql-let/jestTransformer. Install these:

yarn add -D graphql-let babel-jest

And make sure your babel config can compile generated .ts(x)s.

Use ts-jest or other subsequent transformers in Jest

The option subsequentTransformer is available. If you use ts-jest, your jest.config.js will look like this:

  const { defaults: tsjPreset } = require("ts-jest/presets");

  module.exports = {
    preset: "ts-jest",
    transform: {
      ...tsjPreset.transform,
+     "\\.graphql$": [
+       "graphql-let/jestTransformer",
+       { subsequentTransformer: "ts-jest" },
+     ],
    },
  };

Transform .graphqls in Jest

If you use graphql-let/schema/loader, you may want a corresponding transformer, but remember graphql-let does not transform the content of GraphQL schema. Just use what you need; it's most likely to be jest-transform-graphql.

  module.exports = {
    transform: {
      "\\.graphql$": "graphql-let/jestTransformer",
+     "\\.graphqls$": "jest-transform-graphql",
    },
  };

Experimental feature: Resolver Types

If you meet the following conditions, graphql-let generates Resolver Types.

Run:

yarn add -D @graphql-codegen/typescript-resolvers
yarn graphql-let

Then you will get resolver types in graphql-let/__generated__/__types__.

import { Resolvers } from "graphql-let/__generated__/__types__";

const resolvers: Resolvers = {
  Query: {
    // All typed⚡️
    viewer(parent, args, context, info) {
      return { ... }
    },
  }
};

export default resolvers;

graphql-let/schema/loader is also available to update resolver types. It doesn't transpile anything; just detects file modification and passes the content to the next loader.

  // webpack.config.ts
  const config: Configuration = {
    module: {
      rules: [
+       {
+         test: /\.graphqls$/,
+         use: [
+           { loader: 'graphql-let/schema/loader' },
+         ]
+       }
      ]
    }
  }

FAQ

So, it's just a graphql-codegen wrapper generating d.ts...?

Yes.

Supported combination of tools? / Tools x + y don't work!

The above documentation should work basically, but some of the combinations may require more effort. Please vote by creating issues. Sponsoring me is another way to get my attention🍩🍦👀

These are the states/tools for the syntaxes.

| states/tools for syntax | import GraphQL document asimport './a.graphql'; | Inline GraphQL document asimport {gql} from 'graphql-let';gql(`query {}` ); | | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------- | | generating .d.tss by command graphql-let | ✅ | ✅ | | importing GraphQL content from another as# import A from './a.graphql' | ✅ | ✅ | | webpack loader graphql-let/loader | ✅ | ✅ | | Babel Plugin graphql-let/babel | ✅ | ✅ | | Jest Transformer graphql-let/jestTransfomer | ✅ | Vote by issuing | | Experimental: Resolver Types forGraphQL schema | ✅ byimport {Resolvers} from 'graphql-let/__generated__/__types__' | (I think we don't need this) |

Is this a tool only for React?

No. There are more plugins that also generates .ts(x)s from GraphQL documents.

Can I use Tagged Template as gql`query News { baa }`;?

Sadly, you need gql() instead of gql` ` because of the limitation of TypeScript.

What's the extensions .graphql and .graphqls? Can I use .gql or something else?

You can use what you want. I wanted to recommend distinguishing GraphQL schema and GraphQL documents in the extensions, which will lead to a more understandable configuration for webpack loaders with fewer pitfalls. Another reason for .graphqls is that it's one of the supported extensions in the internal library.

How to integrate Apollo refetchQueries?

Query document exports DocumentNode named ${QueryName}Document that you can make use of.

How to import .graphql from another document, especially GraphQL Fragment?

Thanks to graphql-tools/import, the syntax # import X from './fragment.graphql' is supported.

Define your fragment named as partial.graphql

fragment Partial on User {
    id
    name
}

and import it.

# import Partial from './partial.graphql'
query Viewer {
    viewer {
        ...Partial
    }
}

.tsxes generated in cacheDir (.cache) throw TypeScript errors of wrong import paths

It's not a bug. Please exclude cacheDir from your TypeScript compilation. The files in cacheDir are only intermediates, which will speed your next execution.

Your GraphQL documents -> (call GraphQL code generator API *1) -> .tsx *2 -> (call TypeScript to distribute declarations *3) -> .d.ts

You're seeing the *2. It's used to skip *1 and *3, and recodnized as generated implementations, which graphql-let/loader returns, for example.

Contribution

  • Create an issue if you have ideas, find a bug, or anything.
  • Creating a PR is always welcome!
    • Running npm run prepublishOnly locally will get your local development ready.
    • Adding tests is preferable, but not necessary. Maybe someone else will fill it.
  • We have a chronic accumulation of dependabot PRs. Please help us fix these version conflicts by cloning the dependabot branches.

License

Apache License Version 2.0