Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cwd option to fix loader + jestTransformer when using moved cache + config options #626

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 70 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ integrating graphql-let. [A blog post](https://the-guild.dev/blog/graphql-let)

## Table of Contents

- [Why this exists](#why-this-exists)
- [Entrypoints and features](#entrypoints-and-features)
- [Getting started with webpack loader](#getting-started-with-webpack-loader)
- [Getting started with babel-plugin-macros](#getting-started-with-babel-plugin-macros)
- [Getting started with Babel Plugin](#getting-started-with-babel-plugin)
- [Difference between .graphql-let.yml and codegen.yml](#difference-between-graphql-letyml-and-codegenyml)
- [Jest Transformer](#jest-transformer)
- [Experimental feature: Resolver Types](#experimental-feature-resolver-types)
- [FAQ](#faq)
- [Contribution](#contribution)
- [License](#license)
- [Why this exists](#why-this-exists)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of this file is Prettier formatting this

- [Entrypoints and features](#entrypoints-and-features)
- [Getting started with webpack loader](#getting-started-with-webpack-loader)
- [Getting started with babel-plugin-macros](#getting-started-with-babel-plugin-macros)
- [Getting started with Babel Plugin](#getting-started-with-babel-plugin)
- [Difference between .graphql-let.yml and codegen.yml](#difference-between-graphql-letyml-and-codegenyml)
- [Jest Transformer](#jest-transformer)
- [Experimental feature: Resolver Types](#experimental-feature-resolver-types)
- [FAQ](#faq)
- [Contribution](#contribution)
- [License](#license)

## Why this exists

Expand Down Expand Up @@ -55,10 +55,10 @@ const News: React.FC = () => {

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
- **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.

Expand Down Expand Up @@ -125,14 +125,14 @@ 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](https://webpack.js.org/concepts/targets/) of `"node"`
and `"web"` simultaneously. If sources are the same, the compilation should
be once.
- 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](https://webpack.js.org/concepts/targets/) of `"node"`
and `"web"` simultaneously. If sources are the same, the compilation should
be once.

</details>

Expand Down Expand Up @@ -214,6 +214,7 @@ Please note that files in `cacheDir` are only intermediate cache, possibly havin
+ "excludes": [".cache"]
}
```

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

### 3. Add lines to .gitignore
Expand Down Expand Up @@ -460,6 +461,15 @@ respectGitIgnore: true
cacheDir: node_modules/.cache/graphql-let
cacheDir: .cache

# "cwd", optional. Directory of the config file itself by default.
# When evaluating `documents`, `cacheDir`, `schema`, what should be the "root" dir.
# Because the cache is stored as a literal subdirectory matching the documents,
# the search paths must share a common ancestor defined here.
# Practically, this allows the config file and other folders
# to be stored outside the process directory
# Example:
cwd: ../../

# "TSConfigFile", optional. `tsconfig.json` by default.
# You can specify a custom config for generating `.d.ts`s.
# Examples:
Expand All @@ -480,45 +490,45 @@ silent: false
Simple example:

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

Example with a bit more complicated options:

```yaml
schema:
- https://api.github.com/graphql:
headers:
Authorization: YOUR-TOKEN-HERE
- https://api.github.com/graphql:
headers:
Authorization: YOUR-TOKEN-HERE
documents:
- "**/*.graphql"
- "!shouldBeIgnored1"
- '**/*.graphql'
- '!shouldBeIgnored1'
plugins:
- typescript-operations
- typescript-react-apollo
- typescript-operations
- typescript-react-apollo
respectGitIgnore: true
config:
reactApolloVersion: 3
apolloReactComponentsImportFrom: "@apollo/client/react/components"
useIndexSignature: true
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`

- **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 any 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)
- **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 any 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

Expand Down Expand Up @@ -582,10 +592,10 @@ schema. Just use what you need; it's most likely to be `jest-transform-graphql`.

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

- You have file paths including glob patterns in `schema`
- You have
[`@graphql-codegen/typescript-resolvers`](https://graphql-code-generator.com/docs/plugins/typescript-resolvers)
installed
- You have file paths including glob patterns in `schema`
- You have
[`@graphql-codegen/typescript-resolvers`](https://graphql-code-generator.com/docs/plugins/typescript-resolvers)
installed

Run:

Expand Down Expand Up @@ -686,8 +696,8 @@ Define your fragment named as `partial.graphql`

```graphql
fragment Partial on User {
id
name
id
name
}
```

Expand All @@ -696,9 +706,9 @@ and import it.
```graphql
# import Partial from './partial.graphql'
query Viewer {
viewer {
...Partial
}
viewer {
...Partial
}
}
```

Expand All @@ -714,14 +724,14 @@ You're seeing the `*2`. It's used to skip `*1` and `*3`, and recodnized as gener

## Contribution

- **[Create an issue](https://github.com/piglovesyou/graphql-let/issues/new)**
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](https://github.com/piglovesyou/graphql-let/pulls/app%2Fdependabot). Please help us fix these version conflicts by cloning the dependabot branches.
- **[Create an issue](https://github.com/piglovesyou/graphql-let/issues/new)**
if you have ideas, find a bug, or anything.
- **Creating a PR** is always welcome!
- Running `yarn run prepack` 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](https://github.com/piglovesyou/graphql-let/pulls/app%2Fdependabot). Please help us fix these version conflicts by cloning the dependabot branches.

## License

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
schema: ./schema/type-defs.graphqls
documents: "**/*.graphql"
plugins:
- typescript-operations
- typescript-react-apollo
respectGitIgnore: true
cacheDir: ../.cache
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
presets: [
'@babel/preset-env',
'@babel/preset-typescript',
'@babel/preset-react',
],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
query Viewer {
viewer {
id
name
status
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type User {
id: ID!
name: String!
status: String!
}

type Query {
viewer: User
}
9 changes: 5 additions & 4 deletions src/__fixtures/loader/monorepo/config/.graphql-let.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
schema: ../../packages/schema/type-defs.graphqls
documents: "**/*.graphql"
schema: ../schema/type-defs.graphqls
documents: '**/*.graphql'
plugins:
- typescript-operations
- typescript-react-apollo
- typescript-operations
- typescript-react-apollo
respectGitIgnore: true
cwd: ../packages/app
cacheDir: .cache
61 changes: 61 additions & 0 deletions src/__snapshots__/jestTransformer.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,64 @@ function useViewerLazyQuery(baseOptions) {
return Apollo.useLazyQuery(ViewerDocument, options);
}"
`;

exports[`graphql-let/jestTransformer transforms .graphql when custom configFile and cache dirs set 1`] = `
"\\"use strict\\";

function _typeof(obj) { \\"@babel/helpers - typeof\\"; if (typeof Symbol === \\"function\\" && typeof Symbol.iterator === \\"symbol\\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \\"function\\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \\"symbol\\" : typeof obj; }; } return _typeof(obj); }

Object.defineProperty(exports, \\"__esModule\\", {
value: true
});
exports.useViewerQuery = useViewerQuery;
exports.useViewerLazyQuery = useViewerLazyQuery;
exports.ViewerDocument = void 0;

var Apollo = _interopRequireWildcard(require(\\"@apollo/client\\"));

var _templateObject;

function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== \\"function\\") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== \\"object\\" && typeof obj !== \\"function\\") { return { \\"default\\": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== \\"default\\" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj[\\"default\\"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }

var defaultOptions = {};
var ViewerDocument = (0, Apollo.gql)(_templateObject || (_templateObject = _taggedTemplateLiteral([\\"\\\\n query Viewer {\\\\n viewer {\\\\n id\\\\n name\\\\n status\\\\n }\\\\n}\\\\n \\"])));
/**
* __useViewerQuery__
*
* To run a query within a React component, call \`useViewerQuery\` and pass it any options that fit your needs.
* When your component renders, \`useViewerQuery\` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useViewerQuery({
* variables: {
* },
* });
*/

exports.ViewerDocument = ViewerDocument;

function useViewerQuery(baseOptions) {
var options = _objectSpread(_objectSpread({}, defaultOptions), baseOptions);

return Apollo.useQuery(ViewerDocument, options);
}

function useViewerLazyQuery(baseOptions) {
var options = _objectSpread(_objectSpread({}, defaultOptions), baseOptions);

return Apollo.useLazyQuery(ViewerDocument, options);
}"
`;
43 changes: 39 additions & 4 deletions src/jestTransformer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@ let cwd: string;
let config: Config.ProjectConfig;

describe('graphql-let/jestTransformer', () => {
beforeAll(async () => {
test('transforms .graphql', async () => {
[cwd] = await prepareFixtures(__dirname, '__fixtures/jestTransformer');
config = { rootDir: cwd } as Config.ProjectConfig;
});

test('transforms .graphql', async () => {
const fileName = 'pages/viewer.graphql';
const stats = await compiler(cwd, [fileName], 'node');
const { 0: fileData } = stats
Expand All @@ -30,6 +27,44 @@ describe('graphql-let/jestTransformer', () => {
) as { code: string };
expect(removeSourcemapReference(transformedContent)).toMatchSnapshot();
});

test('transforms .graphql when custom configFile and cache dirs set', async () => {
[cwd] = await prepareFixtures(
__dirname,
'__fixtures/jestTransformerCustomPaths',
);

// Compile the file
const fileName = 'pages/viewer.graphql';
const stats = await compiler(cwd + '/subdir', [fileName], 'node', {
configFile: './.graphql-let.yml',
});
const { 0: fileData } = stats
.toJson()
.modules!.map((m) => m.source)
.filter(Boolean);

// Run the config
config = {
rootDir: cwd,
transform: [
[
'filePattern',
'graphql-let/jestTransformer.js',
{
configFile: './subdir/.graphql-let.yml',
},
],
],
} as any;
const fullPath = join(cwd + '/subdir', fileName);
const { code: transformedContent } = jestTransformer.process(
fileData!,
fullPath,
{ config } as TransformOptions<JestTransformerOptions>,
) as { code: string };
expect(removeSourcemapReference(transformedContent)).toMatchSnapshot();
});
});

function removeSourcemapReference(code: string) {
Expand Down
Loading