- bumps to GraphQL Code Generator v1
- adds GraphQL named fragment support
- removes `webpack-node-externals`, in favour of building a single `server.js` bundle
- updates README for GraphQL Code Generator v1
- bumps NPM packages:
 @emotion/core                              ^10.0.7  →   ^10.0.10
 @emotion/styled                            ^10.0.7  →   ^10.0.10
 apollo-cache-inmemory                       ^1.4.3  →     ^1.5.1
 apollo-client                              ^2.4.13  →     ^2.5.1
 apollo-link                                 ^1.2.8  →    ^1.2.11
 apollo-link-error                           ^1.1.7  →    ^1.1.10
 apollo-link-http                           ^1.5.11  →    ^1.5.14
 apollo-link-ws                             ^1.0.14  →    ^1.0.17
 apollo-utilities                            ^1.1.3  →     ^1.2.1
 cross-fetch                                 ^3.0.1  →     ^3.0.2
 dotenv                                      ^6.2.0  →     ^7.0.0
 emotion                                    ^10.0.7  →    ^10.0.9
 graphql                                    ^14.1.1  →    ^14.2.1
 history                                     ^4.7.2  →     ^4.9.0
 ora                                         ^3.1.0  →     ^3.4.0
 react                                      ^16.8.2  →    ^16.8.6
 react-apollo                                ^2.4.1  →     ^2.5.3
 react-dom                                  ^16.8.2  →    ^16.8.6
 react-hot-loader                            ^4.7.0  →     ^4.8.2
 react-router-dom                            ^4.3.1  →     ^5.0.0
 subscriptions-transport-ws                 ^0.9.15  →    ^0.9.16
 @babel/core                                 ^7.3.3  →     ^7.4.3
 @hot-loader/react-dom                      ^16.8.2  →    ^16.8.6
 @types/koa-router                          ^7.0.39  →    ^7.0.40
 @types/koa-send                             ^4.1.1  →     ^4.1.2
 @types/lodash                            ^4.14.121  →  ^4.14.123
 @types/node                                ^11.9.4  →   ^11.13.0
 @types/ora                                  ^3.0.0  →     ^3.2.0
 @types/prop-types                          ^15.5.9  →    ^15.7.0
 @types/react                               ^16.8.3  →   ^16.8.12
 @types/react-dom                           ^16.8.2  →    ^16.8.3
 @types/source-map-support                   ^0.4.2  →     ^0.5.0
 @types/webpack                             ^4.4.24  →    ^4.4.27
 @types/webpack-dev-server                   ^3.1.2  →     ^3.1.5
 babel-plugin-emotion                       ^10.0.7  →    ^10.0.9
 css-hot-loader                              ^1.4.3  →     ^1.4.4
 css-loader                                  ^2.1.0  →     ^2.1.1
 koa-webpack                                 ^5.2.1  →     ^5.2.2
 lint-staged                                 ^8.1.4  →     ^8.1.5
 postcss-preset-env                          ^6.5.0  →     ^6.6.0
 resolve-url-loader                          ^3.0.1  →     ^3.1.0
 source-map-support                         ^0.5.10  →    ^0.5.11
 ts-node                                     ^8.0.2  →     ^8.0.3
 tslint                                     ^5.12.1  →    ^5.15.0
 typescript                                  ^3.3.3  →     ^3.4.1
 webpack                                    ^4.29.5  →    ^4.29.6
pull/162/head 4.3.0
Lee Benson 4 years ago
parent 03203323ac
commit 34eee85603
  1. 15
      .prettierignore
  2. 10
      README.md
  3. 9
      codegen.yml
  4. 3865
      package-lock.json
  5. 104
      package.json
  6. 6
      src/components/example/hackernews.tsx
  7. 19
      src/graphql/fragments.tsx
  8. 156
      src/graphql/index.tsx
  9. 14
      src/lib/apollo.ts
  10. 4
      src/runner/app.ts
  11. 4
      src/webpack/server.ts

@ -0,0 +1,15 @@
# git
.github
**/.gitattributes
# editors
.vscode
*.un~
*.swp
# NPM
**/node_modules
# ext to ignore
**/*.svg
**/.DS_Store

@ -17,7 +17,7 @@ https://reactql.org
- [Emotion](https://emotion.sh/) CSS-in-JS, with inline `<style>` tag generation that contains only the CSS that needs to be rendered.
- [Sass](https://sass-lang.com/), [Less](http://lesscss.org/) and [PostCSS](https://postcss.org/) when importing `.css/.scss/.less` files.
- [React Router 4](https://reacttraining.com/react-router/) for declarative browser + server routes.
- [GraphQL Code Generator](https://graphql-code-generator.com/) for parsing remote GraphQL server schemas, for automatically building fully-typed Apollo React HOCs instead of writing `<Query>` / `<Mutation>` queries manually
- [GraphQL Code Generator v1](https://graphql-code-generator.com/) for parsing remote GraphQL server schemas, for automatically building fully-typed Apollo React HOCs instead of writing `<Query>` / `<Mutation>` queries manually
- Declarative/dynamic `<head>` section, using [react-helmet](https://github.com/nfl/react-helmet).
### Server-side rendering
@ -92,18 +92,18 @@ You can then import the query like we do in the [HackerNews demo component](src/
```ts
// Query to get top stories from HackerNews
import { GetHackerNewsTopStories } from "@/graphql";
import { GetHackerNewsTopStoriesComponent } from "@/graphql";
```
And use it as follows:
```ts
<GetHackerNewsTopStories.Component>
<GetHackerNewsTopStoriesComponent>
{({ data, loading, error }) => (...)
</GetHackerNewsTopStories.Component>
</GetHackerNewsTopStoriesComponent>
```
To get access to the underlying `gql`-templated query (in case you need it for refetching, etc), in this case it'd be `GetHackerNewsTopStories.Document`.
To get access to the underlying `gql`-templated query (in case you need it for refetching, etc), in this case it'd be `GetHackerNewsTopStoriesDocument`.
See [GraphQL Code Generator](https://graphql-code-generator.com/) for more details on how it works.

@ -4,6 +4,9 @@ documents: "src/**/*.graphql"
generates:
src/graphql/index.tsx:
plugins:
- "typescript-common"
- "typescript-client"
- "typescript-react-apollo"
- typescript
- typescript-operations
- typescript-react-apollo
src/graphql/fragments.tsx:
plugins:
- fragment-matcher

3865
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
{
"name": "reactql",
"version": "4.2.1",
"version": "4.3.0",
"description": "ReactQL - front-end React/GraphQL starter kit",
"main": "index.js",
"scripts": {
@ -32,87 +32,87 @@
"author": "Lee Benson <lee@leebenson.com>",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.3.3",
"@babel/core": "^7.4.3",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@hot-loader/react-dom": "^16.8.2",
"@graphql-codegen/cli": "^1.0.6",
"@graphql-codegen/fragment-matcher": "^1.0.6",
"@graphql-codegen/typescript": "^1.0.6",
"@graphql-codegen/typescript-operations": "^1.0.6",
"@graphql-codegen/typescript-react-apollo": "^1.0.6",
"@hot-loader/react-dom": "^16.8.6",
"@types/compression-webpack-plugin": "^2.0.0",
"@types/history": "^4.7.2",
"@types/html-webpack-plugin": "^3.2.0",
"@types/kcors": "^2.2.3",
"@types/koa": "^2.0.48",
"@types/koa-router": "^7.0.39",
"@types/koa-send": "^4.1.1",
"@types/koa-router": "^7.0.40",
"@types/koa-send": "^4.1.2",
"@types/koa-webpack": "^5.0.1",
"@types/lodash": "^4.14.121",
"@types/lodash": "^4.14.123",
"@types/mini-css-extract-plugin": "^0.2.0",
"@types/node": "^11.9.4",
"@types/ora": "^3.0.0",
"@types/prop-types": "^15.5.9",
"@types/react": "^16.8.3",
"@types/react-dom": "^16.8.2",
"@types/node": "^11.13.0",
"@types/ora": "^3.2.0",
"@types/prop-types": "^15.7.0",
"@types/react": "^16.8.12",
"@types/react-dom": "^16.8.3",
"@types/react-helmet": "^5.0.8",
"@types/react-hot-loader": "^4.1.0",
"@types/react-router-dom": "^4.3.1",
"@types/require-from-string": "^1.2.0",
"@types/source-map-support": "^0.4.2",
"@types/webpack": "^4.4.24",
"@types/webpack-dev-server": "^3.1.2",
"@types/source-map-support": "^0.5.0",
"@types/webpack": "^4.4.27",
"@types/webpack-dev-server": "^3.1.5",
"@types/webpack-node-externals": "^1.6.3",
"babel-core": "^6.26.3",
"babel-loader": "^8.0.5",
"babel-plugin-emotion": "^10.0.7",
"babel-plugin-emotion": "^10.0.9",
"brotli-webpack-plugin": "^1.1.0",
"compression-webpack-plugin": "^2.0.0",
"css-hot-loader": "^1.4.3",
"css-loader": "^2.1.0",
"css-hot-loader": "^1.4.4",
"css-loader": "^2.1.1",
"cssnano": "^4.1.10",
"file-loader": "^3.0.1",
"graphql-code-generator": "^0.16.1",
"graphql-codegen-typescript-client": "^0.16.1",
"graphql-codegen-typescript-common": "^0.16.1",
"graphql-codegen-typescript-react-apollo": "^0.16.1",
"html-webpack-plugin": "^3.2.0",
"husky": "^1.3.1",
"koa-webpack": "^5.2.1",
"koa-webpack": "^5.2.2",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"lint-staged": "^8.1.4",
"lint-staged": "^8.1.5",
"mini-css-extract-plugin": "^0.5.0",
"node-sass": "^4.11.0",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.5.0",
"postcss-preset-env": "^6.6.0",
"prettier": "^1.16.4",
"require-from-string": "^2.0.2",
"resolve-url-loader": "^3.0.1",
"resolve-url-loader": "^3.1.0",
"rimraf": "^2.6.3",
"sass-loader": "^7.1.0",
"source-map-support": "^0.5.10",
"source-map-support": "^0.5.11",
"ts-loader": "^5.3.3",
"ts-node": "^8.0.2",
"tslint": "^5.12.1",
"typescript": "^3.3.3",
"webpack": "^4.29.5",
"webpack-node-externals": "^1.7.2"
"ts-node": "^8.0.3",
"tslint": "^5.15.0",
"typescript": "^3.4.1",
"webpack": "^4.29.6"
},
"dependencies": {
"@emotion/core": "^10.0.7",
"@emotion/styled": "^10.0.7",
"apollo-cache-inmemory": "^1.4.3",
"apollo-client": "^2.4.13",
"apollo-link": "^1.2.8",
"apollo-link-error": "^1.1.7",
"apollo-link-http": "^1.5.11",
"@emotion/core": "^10.0.10",
"@emotion/styled": "^10.0.10",
"apollo-cache-inmemory": "^1.5.1",
"apollo-client": "^2.5.1",
"apollo-link": "^1.2.11",
"apollo-link-error": "^1.1.10",
"apollo-link-http": "^1.5.14",
"apollo-link-state": "^0.4.2",
"apollo-link-ws": "^1.0.14",
"apollo-utilities": "^1.1.3",
"apollo-link-ws": "^1.0.17",
"apollo-utilities": "^1.2.1",
"chalk": "^2.4.2",
"cross-env": "^5.2.0",
"cross-fetch": "^3.0.1",
"dotenv": "^6.2.0",
"emotion": "^10.0.7",
"graphql": "^14.1.1",
"cross-fetch": "^3.0.2",
"dotenv": "^7.0.0",
"emotion": "^10.0.9",
"graphql": "^14.2.1",
"graphql-tag": "^2.10.1",
"history": "^4.7.2",
"history": "^4.9.0",
"kcors": "^2.2.2",
"koa": "^2.7.0",
"koa-router": "^7.4.0",
@ -121,15 +121,15 @@
"microseconds": "^0.1.0",
"mobx": "^4.9.2",
"mobx-react": "^5.4.3",
"ora": "^3.1.0",
"react": "^16.8.2",
"ora": "^3.4.0",
"react": "^16.8.6",
"react-addons-css-transition-group": "^15.6.2",
"react-addons-transition-group": "^15.6.2",
"react-apollo": "^2.4.1",
"react-dom": "^16.8.2",
"react-apollo": "^2.5.3",
"react-dom": "^16.8.6",
"react-helmet": "^5.2.0",
"react-hot-loader": "^4.7.0",
"react-router-dom": "^4.3.1",
"subscriptions-transport-ws": "^0.9.15"
"react-hot-loader": "^4.8.2",
"react-router-dom": "^5.0.0",
"subscriptions-transport-ws": "^0.9.16"
}
}

@ -12,7 +12,7 @@ import styled from "@emotion/styled";
/* Local */
// Query to get top stories from HackerNews
import { GetHackerNewsTopStories } from "@/graphql";
import { GetHackerNewsTopStoriesComponent } from "@/graphql";
// ----------------------------------------------------------------------------
@ -36,7 +36,7 @@ const Story = styled("li")`
// doesn't already have data from the server -- it'll display a loading message
// while the data is being retrieved
export const HackerNews: React.FunctionComponent = () => (
<GetHackerNewsTopStories.Component>
<GetHackerNewsTopStoriesComponent>
{({ data, loading, error }) => {
// Any errors? Say so!
if (error) {
@ -66,5 +66,5 @@ export const HackerNews: React.FunctionComponent = () => (
</>
);
}}
</GetHackerNewsTopStories.Component>
</GetHackerNewsTopStoriesComponent>
);

@ -0,0 +1,19 @@
export interface IntrospectionResultData {
__schema: {
types: {
kind: string;
name: string;
possibleTypes: {
name: string;
}[];
}[];
};
}
const result: IntrospectionResultData = {
__schema: {
types: []
}
};
export default result;

@ -1,85 +1,97 @@
export type Maybe<T> = T | null;
type Maybe<T> = T | null;
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID: string;
String: string;
Boolean: boolean;
Int: number;
Float: number;
};
// ====================================================
// Documents
// ====================================================
export type HackerNews = {
topStories?: Maybe<Array<Maybe<Story>>>;
};
export namespace GetHackerNewsTopStories {
export type Variables = {};
export type Query = {
hn?: Maybe<HackerNews>;
};
export type Query = {
__typename?: "Query";
export type Story = {
id?: Maybe<Scalars["String"]>;
title?: Maybe<Scalars["String"]>;
url?: Maybe<Scalars["String"]>;
};
export type GetHackerNewsTopStoriesQueryVariables = {};
hn: Maybe<Hn>;
};
export type Hn = {
__typename?: "HackerNews";
topStories: Maybe<(Maybe<TopStories>)[]>;
};
export type TopStories = {
__typename?: "Story";
id: Maybe<string>;
title: Maybe<string>;
url: Maybe<string>;
};
}
import * as ReactApollo from "react-apollo";
import * as React from "react";
export type GetHackerNewsTopStoriesQuery = { __typename?: "Query" } & {
hn: Maybe<
{ __typename?: "HackerNews" } & {
topStories: Maybe<
Array<
Maybe<{ __typename?: "Story" } & Pick<Story, "id" | "title" | "url">>
>
>;
}
>;
};
import gql from "graphql-tag";
import * as React from "react";
import * as ReactApollo from "react-apollo";
// ====================================================
// Components
// ====================================================
export namespace GetHackerNewsTopStories {
export const Document = gql`
query GetHackerNewsTopStories {
hn {
topStories {
id
title
url
}
export const GetHackerNewsTopStoriesDocument = gql`
query GetHackerNewsTopStories {
hn {
topStories {
id
title
url
}
}
`;
export class Component extends React.Component<
Partial<ReactApollo.QueryProps<Query, Variables>>
> {
render() {
return (
<ReactApollo.Query<Query, Variables>
query={Document}
{...(this as any)["props"] as any}
/>
);
}
}
export type Props<TChildProps = any> = Partial<
ReactApollo.DataProps<Query, Variables>
> &
TChildProps;
export function HOC<TProps, TChildProps = any>(
operationOptions:
| ReactApollo.OperationOption<
TProps,
Query,
Variables,
Props<TChildProps>
>
| undefined
) {
return ReactApollo.graphql<TProps, Query, Variables, Props<TChildProps>>(
Document,
operationOptions
`;
export class GetHackerNewsTopStoriesComponent extends React.Component<
Partial<
ReactApollo.QueryProps<
GetHackerNewsTopStoriesQuery,
GetHackerNewsTopStoriesQueryVariables
>
>
> {
render() {
return (
<ReactApollo.Query<
GetHackerNewsTopStoriesQuery,
GetHackerNewsTopStoriesQueryVariables
>
query={GetHackerNewsTopStoriesDocument}
{...(this as any)["props"] as any}
/>
);
}
}
export type GetHackerNewsTopStoriesProps<TChildProps = {}> = Partial<
ReactApollo.DataProps<
GetHackerNewsTopStoriesQuery,
GetHackerNewsTopStoriesQueryVariables
>
> &
TChildProps;
export function withGetHackerNewsTopStories<TProps, TChildProps = {}>(
operationOptions:
| ReactApollo.OperationOption<
TProps,
GetHackerNewsTopStoriesQuery,
GetHackerNewsTopStoriesQueryVariables,
GetHackerNewsTopStoriesProps<TChildProps>
>
| undefined
) {
return ReactApollo.withQuery<
TProps,
GetHackerNewsTopStoriesQuery,
GetHackerNewsTopStoriesQueryVariables,
GetHackerNewsTopStoriesProps<TChildProps>
>(GetHackerNewsTopStoriesDocument, operationOptions);
}

@ -4,7 +4,11 @@
// IMPORTS
/* NPM */
import { InMemoryCache, NormalizedCacheObject } from "apollo-cache-inmemory";
import {
InMemoryCache,
NormalizedCacheObject,
IntrospectionFragmentMatcher
} from "apollo-cache-inmemory";
import { ApolloClient } from "apollo-client";
import { ApolloLink, split } from "apollo-link";
import { onError } from "apollo-link-error";
@ -15,9 +19,15 @@ import { SubscriptionClient } from "subscriptions-transport-ws";
/* Local */
import { Store } from "@/data/store";
import introspectionQueryResultData from "@/graphql/fragments";
// ----------------------------------------------------------------------------
// Match up fragments
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData
});
export function createClient(
// @ts-ignore - useful to pass in the store for `Authorization` headers, etc
store: Store
@ -27,7 +37,7 @@ export function createClient(
// universally, the cache will survive until the HTTP request is
// responded to (on the server) or for the whole of the user's visit (in
// the browser)
const cache = new InMemoryCache();
const cache = new InMemoryCache({ fragmentMatcher });
// Create a HTTP client (both server/client). It takes the GraphQL
// server from the `GRAPHQL` environment variable, which by default is

@ -32,7 +32,7 @@ import * as webpack from "webpack";
import * as KoaWebpack from "koa-webpack";
/* Ora spinner */
import * as ora from "ora";
import ora from "ora";
// Lodash utility for merging objects
import { mergeWith } from "lodash";
@ -91,7 +91,7 @@ export const common = {
(process.env.WS_PORT && parseInt(process.env.WS_PORT)) || undefined,
// Spinner
spinner: ora() as any
spinner: ora()
};
// Webpack compiler

@ -9,7 +9,6 @@ import * as path from "path";
/* NPM */
import { mergeWith } from "lodash";
import * as webpack from "webpack";
import * as nodeModules from "webpack-node-externals";
/* Local */
import common, { defaultMerger, files } from "./common";
@ -23,9 +22,6 @@ const isProduction = process.env.NODE_ENV === "production";
const base: webpack.Configuration = {
entry: [path.resolve(__dirname, "..", "entry", "server.tsx")],
// External modules that we avoid transpiling
externals: nodeModules(),
module: {
rules: [
...css(false),

Loading…
Cancel
Save