microsoft / graphitation Goto Github PK
View Code? Open in Web Editor NEWGraphQL tooling & runtime support needed for MS Teams and beyond
Home Page: https://microsoft.github.io/graphitation/
License: MIT License
GraphQL tooling & runtime support needed for MS Teams and beyond
Home Page: https://microsoft.github.io/graphitation/
License: MIT License
These are known and will NOT be fixed, as they would require substantial complexity changes and are automatically fixed by virtue of updating to React v18 (when that goes stable).
The new variables and the loading status changes are already batched, but the new data coming from the useFragment
hook comes in a separate update.
(NOTE: I did get rid of the needless addition of id: undefined
, but it does not cause any additional renders, just debugging noise.)
@deleteNode, @appendEdge etc
The packages here has main
, types
, module
and exports
field. The exports field can contain the information from the other fields.
When using TyperScript with the moduleResolution: "bundler"
setting, TypeScript will verify that all imports has an entry in the exports map, if the export map exists, and this includes the types entry.
In this repo the exports field doesn't add the types
conditional, and errors with the following message:
packages/nova-dev-app-providers/src/DevAppProvider.tsx:5:26 - error TS7016: Could not find a declaration file for module '@graphitation/apollo-react-relay-duct-tape'. 'node_modules/@graphitation/apollo-react-relay-duct-tape/lib/index.mjs' implicitly has an 'any' type.
There are types at 'node_modules/@graphitation/apollo-react-relay-duct-tape/lib/index.d.ts', but this result could not be resolved when respecting package.json "exports". The '@graphitation/apollo-react-relay-duct-tape' library may need to update its package.json or typings.
5 import * as graphQL from "@graphitation/apollo-react-relay-duct-tape";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error
The fix would be to add the types
conditional for each entry in the exports
map.
If we do AOT compilation of some sort, we can do some of the work that resolvers sometimes do at runtime where they reflect on the request AST to determine what fields are selected and if all data is already available or needs to be fetched from a [remote] I/O bound source.
A contrived example is when only an id
field of an object is selected, in which case we wouldn't need to fetch the full user object:
type User {
id: ID!
name: String!
}
type Query {
user(id: ID!): User
}
query {
user(id: 42) {
id
}
}
function userResolver(_source, args, context, info) {
if (onlyNeedsIdField(info)) {
return { id: args.id }
} else {
return getUser(args.id)
}
}
See mozilla/source-map#216 for details on resolution
Check PR link for repro: #402
In this case after adding complex argument to connection, if defaultValue
is specified for that argument, running yarn duct-tape-compiler
in apollo-watch-fragments
fails with
➜ apollo-watch-fragments (main) yarn duct-tape-compiler
yarn run v1.22.15
$ duct-tape-compiler --schema ./data/schema.graphql --src ./src --emitQueryDebugComments
Writing ts
DeprecationWarning: 'createTypeAliasDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'dec
orators' parameter.
DeprecationWarning: 'createImportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an overload that does not accept a 'decora
tors' parameter.
ERROR:
Error writing modules:
TypeError: value.hasOwnProperty is not a function
at collectMetadata (C:\Users\stwilczy\Repos\graphitation\node_modules\relay-compiler\lib\util\dedupeJSONStringify.js:48:19)
at collectMetadata (C:\Users\stwilczy\Repos\graphitation\node_modules\relay-compiler\lib\util\dedupeJSONStringify.js:49:29)
at collectMetadata (C:\Users\stwilczy\Repos\graphitation\node_modules\relay-compiler\lib\util\dedupeJSONStringify.js:49:29)
at collectMetadata (C:\Users\stwilczy\Repos\graphitation\node_modules\relay-compiler\lib\util\dedupeJSONStringify.js:49:29)
at collectMetadata (C:\Users\stwilczy\Repos\graphitation\node_modules\relay-compiler\lib\util\dedupeJSONStringify.js:49:29)
at dedupeJSONStringify (C:\Users\stwilczy\Repos\graphitation\node_modules\relay-compiler\lib\util\dedupeJSONStringify.js:22:3)
at printExports (C:\Users\stwilczy\Repos\graphitation\packages\apollo-react-relay-duct-tape-compiler\src\formatModule.ts:152:143)
at C:\Users\stwilczy\Repos\graphitation\packages\apollo-react-relay-duct-tape-compiler\src\formatModule.ts:118:18
at C:\Users\stwilczy\Repos\graphitation\node_modules\relay-compiler\lib\codegen\writeRelayGeneratedFile.js:153:22
at Generator.next (<anonymous>)
Here is where we add the defaultValue
:
NOTE: This needs updating based on latest packages and new thinking.
This package aims to provide a React component tree with the means to retrieve data from an abstract GraphQL client, allowing the components to focus on the generic UI needs rather than host specific data resolving.
The following details are not stricly related to just GraphQL in the context of Nova, but until this effort outgrows the current Nova goals, this seems as good a place as any to give this overview.
We want high value components to be shareable with a wide range of host applications, however not all host applications are equal in the data layers—let alone in their offering of a GraphQL layer. Similarly, not all high value components have the same needs of a GraphQL client/layer. Thus there's a need to provide a matrix of runtime/build-time flavours.
At a baseline it will provide an unopiniated way to fetch a fat query operation, leaving distribution of the data among the component tree up to the component implementors.
However, it will also come with an opinionated way of 'fragmentizing' data requirements, such that a component can express its own data needs using a co-located GraphQL fragment and remain fully isolated from its parents' and children's needs, thus aiming to improve maintenanability of a large component tree and making it easier to avoid over/under fetching of data.
For more information on this concept, see for example this article.
Note that this is nothing more than a way to organize code and requirements; at runtime there is no promise that the implementation needs to do anything more than pass through the data from the parent.
With #2 in place, this fragmentized approach will allow us to optimize generic concerns that a larger application has, such as avoiding unnecessary re-renders while staying in-sync with the data it represents, as it exists in a normalized store.
For more information on this topic, see for example this article.
A high value component targeting any of the runtime flavours can use the provided high-performance CLI tool (nova-facade-graphql-compiler
) to codegen TypeScript typings for its GraphQL query operations. However, the opinionated runtime flavours are required to do so due to the specialized manner in which the typings are emitted to enforce data-masking.
A host application that can statically know about all operations that can be performed could compile away any GraphQL schema request execution. Thus entirely doing away with parsing and validating of documents, finding the set of resolvers needed to resolve the request, etc.
A high value component tree that has no normalized store needs could be compiled in such a way that no little to no overhead exists at runtime when distributing resolved data along the component tree.
Likewise, a high value component tree that does have normalized store needs could be compiled in a way that does come with runtime overhead, but would aim to reduce the need for performance optimizations work in every component.
graphql
tag AST at build time. The existing babel-plugin-graphql-tag transform relies on the graphql-tag
package, which is normally known to add AST of referenced fragments, rather than referring to the existing AST objects. We don't want that and are avoiding it currently in the uncompiled use of the graphql
tag.Something like this should be checkable:
MockPayloadGenerator.generate<SchemaTypes>(operation, {
Person: () => ({
defaultName: {
displayName: "Eloy Durán",
},
}),
ChatTextMessage: () => ({
arrivalTime: new Date().toISOString(),
content: "Look mom, I'm in a storybook!",
}),
ChatMessageConnection: () => ({
edges: new Array(40).fill(undefined),
pageInfo: {
hasNextPage: true,
},
}),
})
Use graphql-codegen's own way to track the naming variants. Currently our enums names are not being renamed in terms of casing and it's not clear how graphql-codegen exactly keeps track of that itself.
When node ids are truly unique, Apollo Cache can be configured to not prefix typename. In this case, we need to adjust the cache redirect from the node field policy, which means we can do less work as we don't need to infer the typename from the fragment.
I am trying to integrate the new compiler in 1JS. During that process I stumbled upon error when trying to run the compiler. I was able to reproduce this issue inside graphitation repo by basically bumping TS to version 5 (which is what 1JS is using). The error is during generation is:
➜ apollo-watch-fragments (main) yarn duct-tape-compiler
yarn run v1.22.15
$ duct-tape-compiler --schema ./data/schema.graphql --src ./src --emitQueryDebugComments
Writing ts
ERROR:
Error writing modules:
Error: Debug Failure. Unhandled SyntaxKind: Unknown.
at pipelineEmitWithHintWorker (C:\Users\stwilczy\Repos\graphitation\packages\apollo-react-relay-duct-tape-compiler\node_modules\typescript\lib\typescript.js:111514:13)
at pipelineEmitWithHint (C:\Users\stwilczy\Repos\graphitation\packages\apollo-react-relay-duct-tape-compiler\node_modules\typescript\lib\typescript.js:111058:9)
at pipelineEmitWithComments (C:\Users\stwilczy\Repos\graphitation\packages\apollo-react-relay-duct-tape-compiler\node_modules\typescript\lib\typescript.js:114842:7)
at pipelineEmit (C:\Users\stwilczy\Repos\graphitation\packages\apollo-react-relay-duct-tape-compiler\node_modules\typescript\lib\typescript.js:111007:7)
at emit (C:\Users\stwilczy\Repos\graphitation\packages\apollo-react-relay-duct-tape-compiler\node_modules\typescript\lib\typescript.js:110975:7)
at emitTypeAliasDeclaration (C:\Users\stwilczy\Repos\graphitation\packages\apollo-react-relay-duct-tape-compiler\node_modules\typescript\lib\typescript.js:112937:7)
at pipelineEmitWithHintWorker (C:\Users\stwilczy\Repos\graphitation\packages\apollo-react-relay-duct-tape-compiler\node_modules\typescript\lib\typescript.js:111244:20)
at pipelineEmitWithHint (C:\Users\stwilczy\Repos\graphitation\packages\apollo-react-relay-duct-tape-compiler\node_modules\typescript\lib\typescript.js:111058:9)
at pipelineEmitWithComments (C:\Users\stwilczy\Repos\graphitation\packages\apollo-react-relay-duct-tape-compiler\node_modules\typescript\lib\typescript.js:114842:7)
at pipelineEmit (C:\Users\stwilczy\Repos\graphitation\packages\apollo-react-relay-duct-tape-compiler\node_modules\typescript\lib\typescript.js:111007:7)
error Command failed with exit code 100.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Could we get compiler working with TS 5?
Docs for package X should simply exist at ./packages/X/docs
so a source reader can easily find them.
See
This repo will output several JS (TypeScript) packages. In the future we'll also output some Rust packages, but the first focus is JS.
@kenotron has shown interest in bootstrapping the infrastructure for that 🎉
Current version was a cleanroom implementation, but I think that it makes sense by now to just try a direct port instead to achieve full support/parity.
WIP here https://github.com/microsoft/graphitation/tree/alloy/port-upstream-mock-payload-generator
With highest priority first:
@connection
with filters when duct-tape tries to read from the cache: #300Query.node
field with a field-policyIt would be ideal if our transformer was webpack loader agnostic and not add extra parsing/printing overhead.
For instance, TMP wants to use esbuild-loader instead of ts-loader (and esbuild doesn't have any way to hook in a transformer).
Example plugin that hooks into webpack's native AST is https://github.com/webpack/webpack/blob/fde018300aa52262c384e937c408d5dd97d62951/lib/UseStrictPlugin.js
This would make the API compatibly exactly with react-relay. Will an error boundary suffice?
I created a branch with repro at https://github.com/sjwilczynski/graphitation/tree/stwilczy/NotWorkingBabelLoader. Now I receive there same error as in 1JS when using babel-loader
instead of ts-loader
:
apollo-watch-fragments (main) yarn serve
yarn run v1.22.15
$ webpack serve
<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:8080/
<i> [webpack-dev-server] On Your Network (IPv4): http://192.168.1.38:8080/
<i> [webpack-dev-server] On Your Network (IPv6): http://[fe80::c18f:6677:eac0:c7ed]:8080/
<i> [webpack-dev-server] Content not from webpack is served from './public' directory
1 asset
462 modules
ERROR in ./src/App.tsx
Module build failed (from ../../node_modules/babel-loader/lib/index.js):
Error: .inputSourceMap must be a boolean, object, or undefined
webpack 5.81.0 compiled with 1 error in 7366 ms
If #85 is not enough
Don't re-invent the wheel, check the IR metadata that relay-compiler normally emits to see if it has stuff we re-implemented.
On https://github.com/sjwilczynski/graphitation/tree/user/stwilczy/fragmentRepro I added another fragment to two components in apollo-watch-fragments example. They mimic setup we have in 1JS, where we very often have more than one fragment (view data and domain data, and sometimes even another domain data one). In such case even if the fragment is very simple compiler fails with:
➜ apollo-watch-fragments (user/stwilczy/fragmentRepro) yarn duct-tape-compiler
yarn run v1.22.15
$ duct-tape-compiler --schema ./data/schema.graphql --src ./src --emitQueryDebugComments
Writing ts
DeprecationWarning: 'createTypeAliasDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an
overload that does not accept a 'decorators' parameter.
DeprecationWarning: 'createImportDeclaration' has been deprecated since v4.8.0. Decorators are no longer supported for this function. Callers should switch to an ove
rload that does not accept a 'decorators' parameter.
ERROR:
Error writing modules:
Invariant Violation: Expected to find a @refetchable directive on TodoList_viewDataFragment
at invariant (C:\Users\stwilczy\Repos\graphitation\node_modules\invariant\invariant.js:40:15)
at printWatchNodeQueryReExport (C:\Users\stwilczy\Repos\graphitation\packages\apollo-react-relay-duct-tape-compiler\src\formatModule.ts:118:12)
at C:\Users\stwilczy\Repos\graphitation\packages\apollo-react-relay-duct-tape-compiler\src\formatModule.ts:98:33
at C:\Users\stwilczy\Repos\graphitation\node_modules\relay-compiler\lib\codegen\writeRelayGeneratedFile.js:153:22
at Generator.next (<anonymous>)
at asyncGeneratorStep (C:\Users\stwilczy\Repos\graphitation\node_modules\@babel\runtime\helpers\asyncToGenerator.js:3:24)
at _next (C:\Users\stwilczy\Repos\graphitation\node_modules\@babel\runtime\helpers\asyncToGenerator.js:25:9)
at C:\Users\stwilczy\Repos\graphitation\node_modules\@babel\runtime\helpers\asyncToGenerator.js:32:7
at new Promise (<anonymous>)
at C:\Users\stwilczy\Repos\graphitation\node_modules\@babel\runtime\helpers\asyncToGenerator.js:21:12
error Command failed with exit code 100.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Previously my understanding of the upstream code was that this was only done for pagination queries.
It's being done here https://github.com/facebook/relay/blob/a3c0c0c52976d06a0a48467b6e084aa49ce69916/packages/react-relay/relay-hooks/useQueryLoader.js#L125-L130
When there are two fragments on the same type, the selection sets should be merged. This isn't happening. It might also be related to the object being inside a list.
Needs a failing test case.
/cc @sjwilczynski
We need to allow the user to write imports like the following, so they remain portable with react-relay
import {
graphql,
useLazyLoadQuery,
} from "@graphitation/apollo-react-relay-duct-tape";
I don't recall why I didn't add Suspense support immediately, but I feel like that should be revisited as the changes needed seem minimal.
E.g. usePreloadedQuery
According to @vladar any read from the cache adds entries to optimism. We need to verify this and try to avoid it, perhaps as described here apollographql/apollo-client#9306 (comment)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.