-
Notifications
You must be signed in to change notification settings - Fork 29.2k
Relay Support in Rust Compiler #33240
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
Changes from 8 commits
2aaa426
f794fcf
6c966d2
8ee3e6c
46e2534
66e6859
eb88c71
4ef5e23
90d3bce
718929c
6d03ee9
523bc25
61826a4
3fe7119
eb7daa1
4f75ae5
46f46f2
400def3
b6d924f
d419ba0
3830a8d
5fa72cf
cd6ed9c
f7cfd1c
fee2e11
2b53fa1
5612526
244a4da
ba4e846
8ba0998
8782671
8343e17
686ff01
27057e5
acea05f
85ac72c
7d35873
d24ae71
5f3f298
aa0f676
4a4a5b6
f6cc9d7
fffa3e1
b5f89bc
1682ac3
464dd97
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,6 +59,7 @@ | |
"@types/http-proxy": "1.17.3", | ||
"@types/jest": "24.0.13", | ||
"@types/node": "13.11.0", | ||
"@types/relay-runtime": "13.0.0", | ||
"@types/selenium-webdriver": "4.0.15", | ||
"@types/sharp": "0.29.3", | ||
"@types/string-hash": "1.1.1", | ||
|
@@ -145,6 +146,8 @@ | |
"react-dom": "17.0.2", | ||
"react-dom-18": "npm:[email protected]", | ||
"react-ssr-prepass": "1.0.8", | ||
"relay-compiler": "13.0.1", | ||
"relay-runtime": "13.0.1", | ||
"release": "6.3.0", | ||
"request-promise-core": "1.1.2", | ||
"resolve-from": "5.0.0", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
use std::path::PathBuf; | ||
|
||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
use pathdiff::diff_paths; | ||
use serde::Deserialize; | ||
use swc_atoms::{js_word, JsWord}; | ||
use swc_common::FileName::Real; | ||
use swc_common::{FileName, Span}; | ||
use swc_ecmascript::ast::*; | ||
use swc_ecmascript::visit::{Fold, FoldWith}; | ||
|
||
#[derive(Clone, Debug, Deserialize)] | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#[serde(rename_all = "snake_case")] | ||
pub enum RelayLanguageConfig { | ||
Typescript, | ||
Flow, | ||
} | ||
|
||
#[derive(Clone, Debug, Deserialize)] | ||
pub struct Config { | ||
pub artifact_directory: Option<PathBuf>, | ||
pub language: RelayLanguageConfig, | ||
} | ||
|
||
impl Config { | ||
fn file_extension(&mut self) -> &'static str { | ||
match self.language { | ||
RelayLanguageConfig::Typescript => "ts", | ||
RelayLanguageConfig::Flow => "js", | ||
} | ||
} | ||
} | ||
|
||
struct Relay { | ||
config: Config, | ||
file_name: FileName, | ||
} | ||
|
||
fn pull_first_operation_name_from_tpl(tpl: TaggedTpl) -> Option<String> { | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tpl.tpl | ||
.quasis | ||
.into_iter() | ||
.filter_map(|quasis| { | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let template_string_content = String::from(quasis.raw.value.to_string()); | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let split_content = template_string_content.split(" ").collect::<Vec<&str>>(); | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
let operation = split_content | ||
.chunks(2) | ||
.filter_map(|slice| { | ||
if slice.len() == 1 { | ||
return None; | ||
} | ||
|
||
let word = slice[0]; | ||
let next_word = slice[1]; | ||
|
||
if word == "query" || word == "subscription" || word == "mutation" { | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return Some(String::from(next_word)); | ||
} | ||
|
||
None | ||
}) | ||
.next(); | ||
|
||
return operation; | ||
}) | ||
.next() | ||
} | ||
|
||
fn build_require_expr_from_path(path: String) -> Expr { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not directly related to this specific PR, but I wonder how this can be implemented here. Currently, our Not sure if there is JS runtime part in next.js that can also handle that second part. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alunyov Can you explain the use case for 2? Might be able to get away with less complexity if we don't add it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tbezman Sure! A developer changed the fragment or a query (added/changed field, etc), but didn't run the To reduce the confusion, In the babel plugin we're comping the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes a ton of sense. @alunyov Is there somewhere in the relay source where y'all export a function to hash a query / mutation / fragment / subscription? Hoping we can avoid duplicating functionality here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, maybe we can address this in a follow up PR. I'm helping a team migrate to Relay / GraphQL this week and want to keep them on the Rust compiler. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @tbezman sure, totally fine to do this in a follow-up. This is what we're using to create these
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Expr::Call(CallExpr { | ||
span: Default::default(), | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
callee: ExprOrSuper::Expr(Box::new(Expr::Ident(Ident::new( | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
js_word!("require"), | ||
Span::default(), | ||
)))), | ||
args: vec![ExprOrSpread { | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
spread: None, | ||
expr: Box::new(Expr::Lit(Lit::Str(Str { | ||
span: Default::default(), | ||
value: JsWord::from(path), | ||
has_escape: false, | ||
kind: Default::default(), | ||
}))), | ||
}], | ||
type_args: None, | ||
}) | ||
} | ||
|
||
impl Fold for Relay { | ||
fn fold_expr(&mut self, expr: Expr) -> Expr { | ||
let expr = expr.fold_children_with(self); | ||
|
||
match expr.clone() { | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Expr::TaggedTpl(tpl) => { | ||
if let Some(built_expr) = self.build_call_expr_from_tpl(tpl) { | ||
built_expr | ||
} else { | ||
expr | ||
} | ||
} | ||
_ => expr, | ||
} | ||
} | ||
} | ||
|
||
impl Relay { | ||
fn build_call_expr_from_tpl(&mut self, tpl: TaggedTpl) -> Option<Expr> { | ||
if let Expr::Ident(ident) = *tpl.tag.clone() { | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if ident.sym.to_string() != "graphql" { | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return None; | ||
} | ||
} | ||
|
||
let operation_name = pull_first_operation_name_from_tpl(tpl); | ||
|
||
if let (Some(operation_name), Real(source_path_buf)) = | ||
(operation_name, self.file_name.clone()) | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
let path_to_source_dir = source_path_buf.parent().unwrap(); | ||
let generated_file_name = format!( | ||
"{}.graphql.{}", | ||
operation_name, | ||
self.config.file_extension().clone() | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
); | ||
|
||
let fully_qualified_require_path = match self.config.artifact_directory.clone() { | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Some(artifact_directory) => std::env::current_dir() | ||
tbezman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
.unwrap() | ||
.join(artifact_directory) | ||
.join(generated_file_name), | ||
_ => path_to_source_dir | ||
.clone() | ||
.join("__generated__") | ||
.join(generated_file_name), | ||
}; | ||
|
||
let mut require_path = String::from( | ||
diff_paths(fully_qualified_require_path, path_to_source_dir) | ||
.unwrap() | ||
.to_str() | ||
.unwrap(), | ||
); | ||
|
||
if !require_path.starts_with(".") { | ||
require_path = format!("./{}", require_path); | ||
} | ||
|
||
return Some(build_require_expr_from_path(require_path)); | ||
} | ||
|
||
None | ||
} | ||
} | ||
|
||
pub fn relay(config: Config, file_name: FileName) -> impl Fold { | ||
Relay { config, file_name } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
const variableQuery = graphql` | ||
query InputVariableQuery { | ||
hello | ||
} | ||
` | ||
|
||
fetchQuery(graphql` | ||
query InputUsedInFunctionCallQuery { | ||
hello | ||
} | ||
`) | ||
|
||
function SomeQueryComponent() { | ||
useLazyLoadQuery(graphql` | ||
query InputInHookQuery { | ||
hello | ||
} | ||
`) | ||
} | ||
|
||
const variableMutation = graphql` | ||
query InputVariableMutation { | ||
someMutation | ||
} | ||
` | ||
|
||
commitMutation( | ||
environment, | ||
graphql` | ||
query InputUsedInFunctionCallMutation { | ||
someMutation | ||
} | ||
` | ||
) | ||
|
||
function SomeMutationComponent() { | ||
useMutation(graphql` | ||
query InputInHookMutation { | ||
someMutation | ||
} | ||
`) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
const variableQuery = require("../../../../../../some/generated/dir/InputVariableQuery.graphql.ts"); | ||
fetchQuery(require("../../../../../../some/generated/dir/InputUsedInFunctionCallQuery.graphql.ts")); | ||
function SomeQueryComponent() { | ||
useLazyLoadQuery(require("../../../../../../some/generated/dir/InputInHookQuery.graphql.ts")); | ||
} | ||
const variableMutation = require("../../../../../../some/generated/dir/InputVariableMutation.graphql.ts"); | ||
commitMutation(environment, require("../../../../../../some/generated/dir/InputUsedInFunctionCallMutation.graphql.ts")); | ||
function SomeMutationComponent() { | ||
useMutation(require("../../../../../../some/generated/dir/InputInHookMutation.graphql.ts")); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
const variableQuery = graphql` | ||
query InputVariableQuery { | ||
hello | ||
} | ||
` | ||
|
||
fetchQuery(graphql` | ||
query InputUsedInFunctionCallQuery { | ||
hello | ||
} | ||
`) | ||
|
||
function SomeQueryComponent() { | ||
useLazyLoadQuery(graphql` | ||
query InputInHookQuery { | ||
hello | ||
} | ||
`) | ||
} | ||
|
||
const variableMutation = graphql` | ||
query InputVariableMutation { | ||
someMutation | ||
} | ||
` | ||
|
||
commitMutation( | ||
environment, | ||
graphql` | ||
query InputUsedInFunctionCallMutation { | ||
someMutation | ||
} | ||
` | ||
) | ||
|
||
function SomeMutationComponent() { | ||
useMutation(graphql` | ||
query InputInHookMutation { | ||
someMutation | ||
} | ||
`) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
const variableQuery = require('./__generated__/InputVariableQuery.graphql.ts') | ||
fetchQuery(require('./__generated__/InputUsedInFunctionCallQuery.graphql.ts')) | ||
function SomeQueryComponent() { | ||
useLazyLoadQuery(require('./__generated__/InputInHookQuery.graphql.ts')) | ||
} | ||
const variableMutation = require('./__generated__/InputVariableMutation.graphql.ts') | ||
commitMutation( | ||
environment, | ||
require('./__generated__/InputUsedInFunctionCallMutation.graphql.ts') | ||
) | ||
function SomeMutationComponent() { | ||
useMutation(require('./__generated__/InputInHookMutation.graphql.ts')) | ||
} |
Uh oh!
There was an error while loading. Please reload this page.