Skip to content

Commit

Permalink
Support handling gql() by CLI (#137)
Browse files Browse the repository at this point in the history
* Cli for gql() works

* fix: it should pass codegenOpts.config

* organize deps in package.json

* Cli for gql() works

* async function processProgramPath

* fix eslint errors

* README.md

* fix gen.test.ts: cleanup node_modules too

* fix: gen.test.ts.snap

* refac: GqlCodegenContext in types.ts

* refac: CodegenContext in types.ts

* refac

* refac, fix: cacheRelDir is unnecessary

* refac, CreatedPaths in types.ts

* refac: Organize types in types.ts

* refac: Organize types in types.ts

* wip: refac

* wip: refac

* wip: refac

* wip: refac

* wip: refac comment

* wip: refac: {skip: boolean}

* Done. gen generates `.d.ts`s both for FileCodegenContext and LiteralCodegenContext

* fix: decorate .d.ts generated by literalCodegenContext

* refac

* fix gen snapshot

* README.md

* README.md

* fix eslint warnings

* fix: the part of processing dts should be shared

* refac: updateLog()

* refac: processResolverTypesIfNeeded in resolver-types.ts

* refac: literals.ts and documents.ts

* refac: remove full-generate.ts and share logic in all entry points

* refac: share logic between gen and loader

* refac

* fix: only if schema was updated, documents should be handled.

* refac: rename function processLiteralsWithDtsGenerateSync

* refac

* fix: literal uses processDtsForContext()

Make gen() returns codegenContext to be testable

* README.md

* README.md

* refac

* refac

* refac
  • Loading branch information
piglovesyou authored Aug 4, 2020
1 parent e762e93 commit 4556a5b
Show file tree
Hide file tree
Showing 26 changed files with 1,755 additions and 1,061 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module.exports = {
],

ignorePatterns: [
'test/__fixtures/gen/pages/index.tsx',
'test/__fixtures/babel/**/input.tsx',
'test/__fixtures/babel/**/output.mjs',
],
Expand Down
214 changes: 118 additions & 96 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ that integrates graphql-let.

- [Why it exists](#why-it-exists)
- [How it works](#how-it-works)
- [Get started](#get-started)
- [Get started with webpack loader](#get-started-with-webpack-loader)
- [Available options in .graphql-let.yml](#available-options-in-graphql-letyml)
- [Setup Babel Plugin for inline GraphQL documents](#setup-babel-plugin-for-inline-graphql-documents)
- [Jest Transformer](#jest-transformer)
- [Babel Plugin for inline GraphQL documents](#babel-plugin-for-inline-graphql-documents)
- [Experimental feature: Resolver Types](#experimental-feature-resolver-types)
- [FAQ](#faq)
- [Contribution](#contribution)
Expand All @@ -29,15 +29,18 @@ make it safer by typing data statically, so you can write truly type-protected
code with rich IDE assists.

To enhance that development pattern, we should move on to the more specific
use-case than what GraphQL code generator allows. Let's consider TypeScript as a
first-class citizen and forget generating intermediate artifacts to achieve Hot
Module Replacement (HMR).
use-case than what GraphQL code generator allows; Consider TypeScript as a
first-class citizen and forget intermediate artifacts to get Hot Module
Replacement (HMR) work.

graphql-let lets you `import` and call `gql` to get results of GraphQL code
generator per GraphQL documents with TypeScript type definitions.

```typescript jsx
import { useNewsQuery } from './news.graphql'
// or
import gql from 'graphql-let'
const { useNewsQuery } = gql(`query News { ... }`)

const News: React.FC = () => {
// Typed already️⚡️
Expand All @@ -48,8 +51,8 @@ const News: React.FC = () => {

## How it works

There are three entrypoints to graphql-let: a CLI, a webpack loader and a Babel
plugin. Mostly, all do the same.
There are three entry points to graphql-let: a CLI, a webpack loader, and a
Babel plugin. Mostly, all do the same.

1. It loads configurations from `.graphql-let.yml`
2. It passes them to GraphQL code generator to get `.ts(x)`s, which runtime
Expand All @@ -60,13 +63,13 @@ There are a few things it works on to make it happen fast and stable.

- Sharing the processes. Loading remote schema and generating `.d.ts`s are
heavy, so it runs them fewer times when it's possible.
- Caching. By embedding hashes of source states, it reduces number of
- Caching. By embedding hashes of source states, it reduces the number of
unnecessary compilation.
- Sharing the promises. The webpack compilation of the typical SSR
applications as Next.js runs `"node"` and `"web"` simultaniously. If sources
applications as Next.js runs `"node"` and `"web"` simultaneously. If sources
are the same, the compilation should run once.

## Get started
## Get started with webpack loader

This is an example of **TypeScript + React + Apollo Client on webpack**. Please
replace the corresponding lines depending on your needs.
Expand All @@ -89,9 +92,9 @@ yarn graphql-let init
# This will generate .graphql-let.yml
```

Next add
Next, add
[graphql-codegen plugins](https://graphql-code-generator.com/docs/plugins/index)
in it. **Please note that you have to generate TypeScript source** by the
in it. **Please note that you have to generate a TypeScript source** by the
plugins.

Edit it like this:
Expand Down Expand Up @@ -163,8 +166,8 @@ yarn graphql-let --config custom/path/.graphql-let.yml
# /app/custom/path/src/schema.graphqls.d.ts
```

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

```diff
"scripts": {
Expand All @@ -173,7 +176,7 @@ and modify like this.
},
```

### 4. Code more
### 6. Code more

Enjoy HMR (Hot Module Replacement) of webpack with the generated react-apollo
hooks and IDE code assists.
Expand Down Expand Up @@ -206,20 +209,21 @@ schema: lib/type-defs.graphqls
# Please see here for more information: https://graphql-code-generator.com/docs/getting-started/schema-field#available-formats

documents: "**/*.graphql"
# Required to use a webpack loader "graphql-let/loader".
# The GraphQL documents info of quereis and mutations etc.
# Required by both "graphql-let/loader" and "graphql-let/babel".
# The GraphQL documents info of queries and mutations etc.
# Examples:
# documents: 'queries/**/*.graphql'
# documents:
# - 'queries/**/*.graphql'
# - 'pages/**/*.tsx'
# - '!queries/exeption.graphql'

plugins:
- typescript
- typescript-operations
- typescript-react-apollo
# Required. The plugins for GraphQL documents to run GraphQL code generator with.
# It's identical to "documentPlugins" field. Please note you need to generate TypeScript source here.
# It's identical to "documentPlugins" field. Please note you need to generate a TypeScript source here.
# Examples:
# plugins:
# - typescript
Expand Down Expand Up @@ -250,20 +254,77 @@ TSConfigFile: tsconfig.json
# TSConfigFile: tsconfig.compile.json

gqlDtsEntrypoint: node_modules/@types/graphql-let/index.d.ts
# Optional, `node_modules/@types/graphql-let/index.d.ts` by default. Needs to be end with ".d.ts".
# Optional, `node_modules/@types/graphql-let/index.d.ts` by default. Needs to end with ".d.ts".
# It is used for a Babel plugin "graphql-let/babel" to inject types of `gql` functions.
```

## Setup Babel Plugin for inline GraphQL documents

A Babel Plugin allows you to get codegen results from "graphql-tag"-like syntax
as below.

```typescript jsx
import gql from "graphql-let";

// Typed️⚡️
const { useViewerQuery } = gql(`
query Viewer {
viewer { name }
}
`);
```

### Configure `graphql-let/babel`

Install these additional dependencies:

```bash
yarn add -D graphql-let do-sync @babel/core @babel/parser @babel/traverse @babel/helper-plugin-utils
```

Add target `.ts(x)`s to `documents` that contains `gql()` calls. This is used
for the CLI execution.

```diff
documents:
+ - "pages/**/*.tsx"
- "**/*.graphql"
```

Put `graphql-let/babel` to the plugins section in your babel configuration such
as `babel.config.json`.

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

Note: The `.tsx`s are generated in `node_modules/graphql-let/__generated__` by
default, but you may want them to be outside of `node_modules` since it's often
excluded to be TS compilation. Please try `cacheDir: __generated__` in your
.graphql-let.yml then.

### Limitations of `graphql-let/babel`

- **Sadly**, type injection can't be done with TaggedTemplateExpression such
as `` gql`query {}` ``. This is the limitation of TypeScript.
[Please answer me if you have ideas.](https://stackoverflow.com/questions/61917066/can-taggedtempalte-have-overload-signatures-with-a-certain-string-literal-argume)
- Fragments are still not available. Please watch
[the issue.](https://github.com/piglovesyou/graphql-let/issues/65)

## Jest Transformer

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

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

### Use `babel-jest` in Jest
Expand All @@ -282,80 +343,36 @@ And make sure your babel config can compile generated `.ts(x)`s.
The option `subsequentTransformer` is available. If you use `ts-jest`, your
`jest.config.js` will look like this:

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

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

### Transform `.graphqls` in 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`.

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

## Babel Plugin for inline GraphQL documents

A Babel Plugin support allows you to get typed graphql-codegen results from
"graphql-tag"-like syntax as the below.

```typescript jsx
import gql from "graphql-let";

// Typed️⚡️
const { useViewerQuery } = gql(`
query Viewer {
viewer { name }
}
`);
```

### Configure `graphql-let/babel`

Install these additional dependencies:

```bash
yarn add -D graphql-let do-sync @babel/core @babel/parser @babel/traverse @babel/helper-plugin-utils
```

with the plugin configuration in such as `babel.config.json`:

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

Note: The `.tsx`s are generated in `node_modules/graphql-let/__generated__` by
default, but you may want them to be outside of `node_modules`.Please try
`cacheDir: __generated__` in your .graphql-let.yml then.

### Limitations of `graphql-let/babel`

- **Sadly**, type injection can't be done with TaggedTemplateExpression such
as `` gql`query {}` ``. This is the limitation of TypeScript.
[Please answer me if you have ideas.](https://stackoverflow.com/questions/61917066/can-taggedtempalte-have-overload-signatures-with-a-certain-string-literal-argume)
- Fragments are still not available. Please watch
[the issue.](https://github.com/piglovesyou/graphql-let/issues/65)

## Experimental feature: Resolver Types

If:
Expand Down Expand Up @@ -417,18 +434,23 @@ the next loader but it updates resolver types in HMR. Set it up as below:

_Yes._

#### What's the difference between webpack loader and Babel Plugin?
#### Supported combination? / x + y don't work!

Basically both syntax `import './a.graphql'` and `` gql(`query {}` ) `` are
suposed to just work, but currently some of combinations require more effort.
Please vote by creating issues.
[Sponsering me](https://github.com/sponsors/piglovesyou) is another way to get
my attention🍩🍦

The webpack loader is more stable, the Babel Plagin can handle inline GraphQL
documents.
These are the states/tools for the syntaxes.

| features | webpack loader | Babel Plugin |
| ------------------------------------------------------------ | -------------- | ------------ |
| stability/speed || |
| generating `.d.ts`s by cli | | Use `babel` |
| Importing GraphQL document file<br>as `import './a.graphql'` || |
| Inline GraphQL<br>as `` gql(`query {}`) `` | | |
| Experimental: Resolver Types for<br>GraphQL schema | | |
| states/tools for syntax | File import as<br>`import './a.graphql';` | Inline GraphQL as<br>`import gql from 'graphql-tag';`<br>`` gql(`query {}` ); `` |
| -------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| generating `.d.ts`s by command `graphql-let` | | |
| webpack loader `graphql-let/loader` | | [Vote by issuing](https://github.com/piglovesyou/graphql-let/issues) |
| Bable Plugin `graphql-let/babel` | [Vote by issuing](https://github.com/piglovesyou/graphql-let/issues) | |
| Jest Transformer `graphql-let/jestTransfomer` | | [Vote by issuing](https://github.com/piglovesyou/graphql-let/issues) |
| Experimental: Resolver Types for<br>GraphQL schema | ✅ by<br>`import './schema.graphqls'` | [Vote by issuing](https://github.com/piglovesyou/graphql-let/issues) |

#### Is this a tool only for React?

Expand All @@ -437,8 +459,8 @@ No. There are

#### Can I write GraphQL documents in my `.tsx` as `` const query = gql`query News{ ... }`; ``?

Please try the Babel Plugin `graphql-let/babel`, but you need parensesis
(`` gql(`query {}`) ``).
Please try the Babel Plugin `graphql-let/babel`, but you need parenthesis
`` gql(`query {}`) ``.

#### What's the extension `.graphqls`? Should I use it for schema and `.graphql` for documents?

Expand All @@ -461,9 +483,9 @@ You can't, yet.
- **[Create an issue](https://github.com/piglovesyou/graphql-let/issues/new)**
if you have ideas, found a bug or anything.
- **Creating a PR** is always welcome!
- Running `npm run prepublishOnly` localy will get your local development
- Running `npm run prepublishOnly` locally will get your local development
ready.
- Adding test is preferrable. But don't hesitate without it, maybe someone
- Adding tests is preferable, but don't hesitate without it, maybe someone
else will fill it.

## License
Expand Down
15 changes: 6 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,18 @@
"minimist": "^1.2.0",
"rimraf": "^3.0.2",
"slash": "^3.0.0",
"yaml": "^1.7.2"
"yaml": "^1.7.2",
"@babel/core": "^7.0.0",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/parser": "^7.0.0",
"@babel/traverse": "^7.0.0",
"do-sync": "^2.2.0"
},
"devDependencies": {
"@apollo/react-common": "^3.1.3",
"@apollo/react-components": "^3.1.3",
"@apollo/react-hooks": "^3.1.3",
"@babel/core": ">=7.0.0",
"@babel/helper-plugin-utils": ">=7.0.0",
"@babel/helper-transform-fixture-test-runner": ">=7.0.0",
"@babel/parser": ">=7.0.0",
"@babel/plugin-syntax-jsx": ">=7.0.0",
"@babel/preset-env": "^7.8.4",
"@babel/preset-react": ">=7.0.0",
Expand Down Expand Up @@ -110,12 +112,7 @@
"typescript": "*"
},
"optionalDependencies": {
"@babel/core": ">=7.0.0",
"@babel/helper-plugin-utils": ">=7.0.0",
"@babel/parser": ">=7.0.0",
"@babel/traverse": ">=7.0.0",
"@graphql-codegen/typescript-resolvers": "*",
"do-sync": "*",
"babel-jest": "*"
},
"husky": {
Expand Down
Loading

0 comments on commit 4556a5b

Please sign in to comment.