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

[WIP] Language plugin #5

Closed
wants to merge 25 commits into from
Closed

[WIP] Language plugin #5

wants to merge 25 commits into from

Conversation

alloy
Copy link

@alloy alloy commented Jan 16, 2018

@kastermester Here’s my first pass at the plugin architecture, redone from scratch to leave out any of the TS work I had also done previously.

  • Define plugin interface
  • Refactor relay-compiler to make existing JS/Flow code conform to the plugin interface
  • Don’t leave caching of found GraphQL tags up to each plugin
  • Don’t leave name validation of GraphQL fragments up to each plugin
  • Still need to add support for loading plugins as either CommonJS or ES6 modules (for e.g. TS)
  • Document all of the types in the plugin interface
  • Run prettier
  • Remove version changes from package.json files
  • Rebase on latest upstream version
  • Verify that before and after JS/Flow artefacts are identical

typeGenerator: TypeGenerator,
formatModule: FormatModule,
findGraphQLTags: GraphQLTagFinder,
};
Copy link
Author

Choose a reason for hiding this comment

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

This is the interface that the plugin needs to implement.

@@ -451,5 +450,5 @@ const FLOW_TRANSFORMS: Array<IRTransform> = [

module.exports = {
generate: Profiler.instrument(generate, 'RelayFlowGenerator.generate'),
flowTransforms: FLOW_TRANSFORMS,
transforms: FLOW_TRANSFORMS,
Copy link
Author

Choose a reason for hiding this comment

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

We probably need to use the exact same transforms for our TS plugin. Seeing as the compiler pubic API already exports all of these in predefined sets, I’m inclined to just export all of them individually as well.

Choose a reason for hiding this comment

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

Yeah I believe I used the same transforms as flow in the example I had running. I think passing a "recommended" set of transforms, possibly along with other transforms that could be deemed useful might be a good idea? Either way - I believe all needed for the TS plugin would be the same transforms as the flow type generator uses.

Copy link
Author

Choose a reason for hiding this comment

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

Well… that’s actually a lot more involved, so I’d probably want to discuss that with the Relay team. For now, let’s just pick these few from the currently exported list. i.e. this should work:

import { IRTransforms } from "relay-compiler"

const transforms = [
  IRTransforms.commonTransforms[2], // RelayRelayDirectiveTransform.transform
  IRTransforms.commonTransforms[3], // RelayMaskTransform.transform
  IRTransforms.printTransforms[0], // FlattenTransform.transformWithOptions({})
]

Copy link
Author

Choose a reason for hiding this comment

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

I think passing a "recommended" set of transforms, possibly along with other transforms that could be deemed useful might be a good idea?

Exactly, something along those lines. We’ll suggest something to the team and see what they think is best 👍

Choose a reason for hiding this comment

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

I guess something like that could be done :) Although a named export seems a bit more robust. I will focus on getting something to work to begin with - that probably exposes a few areas where we could make few changes to make things easier and more discoverable :)

Copy link
Author

Choose a reason for hiding this comment

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

Oh totally! I just meant for the interim while we work on the plugin side of things. When we submit this plugin PR upstream I would definitely want to use a more robust solution.

@kastermester
Copy link

kastermester commented Jan 16, 2018

Having just glanced at it, it looks very promising! I will begin work on a TS plugin as soon as I get some time. But it looks like much of the code I shared with you can be used for this.

Some quick comments/questions:

  1. Would it be possible to make the memoizedFind part of the module parser part of the relay-compiler implementation, such that I wouldn't need to implement this myself? (to get the same performance characteristics as the JS module parser) ? I'm not sure if you could simply wrap the plugins findGraphQLTags function?
  2. It could be possible to avoid double parsing the graphql if the findGraphQLTags function of the plugin could receive the contents of the graphql package as required by the relay-compiler, and then changing the return type of the findGraphQLTags to be Array<OperationDefinitionNode | FragmentDefinitionNode>. I'm not sure whether this is worth it - but it could be worth considering.

So far I like the looks of this very much though! It should be relatively easy to build something on top of this. I will try to get a working example running ASAP, so we can make sure we get all the relevant/needed hooks implemented.

@alloy
Copy link
Author

alloy commented Jan 16, 2018

  1. Would it be possible to make the memoizedFind part of the module parser part of the relay-compiler implementation, such that I wouldn't need to implement this myself? (to get the same performance characteristics as the JS module parser) ? I'm not sure if you could simply wrap the plugins findGraphQLTags function?

Yup, makes sense 👍

  1. It could be possible to avoid double parsing the graphql if the findGraphQLTags function of the plugin could receive the contents of the graphql package as required by the relay-compiler, and then changing the return type of the findGraphQLTags to be Array<OperationDefinitionNode | FragmentDefinitionNode>. I'm not sure whether this is worth it - but it could be worth considering.

Sounds like we should indeed do this for the final version. I’m wondering if it makes sense to do this iteratively such that we can work on the TS plugin first and then get back to this PR to make the final tweaks needed to polish it?

@kastermester
Copy link

kastermester commented Jan 16, 2018

Sounds like we should indeed do this for the final version. I’m wondering if it makes sense to do this iteratively such that we can work on the TS plugin first and then get back to this PR to make the final tweaks needed to polish it?

Sounds like a plan. It wasn't meant like it had to be done right now, it was just a quick observation.

@kastermester
Copy link

I hope I can get to spend some time on this during this week, but I might get a bit pressured on time, we'll see. I'll let you know the second I have something worth looking at.

@alloy
Copy link
Author

alloy commented Jan 17, 2018

@kastermester I may have some time to get started on making your repo conform to the plugin interface, but I don’t want to step on your toes, so let me know if/when you start on something.

@kastermester
Copy link

@alloy Earliest I should get the chance to look at it will be this weekend (should have some time saturday I would think).

I will merge your pull request and if you have the time to take a stab at it then that would be great :)

I think as soon as we have something running in the repo that sort of works - we should look into porting as many tests as possible from the relay-compiler repo - I'm just not sure where to start with that.

@alloy
Copy link
Author

alloy commented Jan 17, 2018

@kastermester Alright, I made memoizedFind part of the source module parser instead. With regards to the double GraphQL parsing, are you referring to FindGraphQLTags doing its own parsing of the fragment to validate the name?

Come to think of it, the name validation also shouldn’t be left up to the plugin, the only thing the plugin should do is extract the GraphQL fragment.

@kastermester
Copy link

Sounds good!

Yes I was thinking that the plugin needs to do its own validation for now. If we wish to rework this, perhaps the return type from the plugin in find graphql tags should be something like:

type GraphQLTagLocation = GraphQLTagFreeForm | GraphQLTagComponent | GraphQLTagComponentProp;
interface GraphQLTagFreeForm {
  location: 'freeform';
}
interface GraphQLTagComponent {
  location: 'component';
  componentName: string;
}
interface GraphQLTagComponentProp {
  location: 'componentProp';
  componentName: string;
  propName: string;
}
interface GraphQLTaggedText {
  location: GraphQLTagLocation;
  graphQLText: string;
}

declare function findGraphQLTags(...): Array<GraphQLTaggedText>;

This way all the validation could be left inside the relay-compiler package and the various plugins can just deal with figuring out where the tags originated from.

Note: I'm not saying the names for the interfaces and types are the right choices for them - I figure there's some better options.

@alloy
Copy link
Author

alloy commented Jan 19, 2018

@kastermester I moved name validation out of the plugin’s responsibility. I didn’t yet optimise the GraphQL parsing, but that can now be done at a later time independently, the plugin now only needs to find the tag and return just that.

@alloy
Copy link
Author

alloy commented Jan 19, 2018

Alright, just did some testing comparing artefacts produced by the upstream 1.5.0-rc.1 release and this plugin code; everything seems good, there’s no differences in generated artefacts.

@alloy
Copy link
Author

alloy commented Jan 19, 2018

Going to take a look at updating your code to conform to the plugin interface.

@kastermester
Copy link

Sounds great! I expect to have some time tomorrow to work on this as well :)

@alloy
Copy link
Author

alloy commented Jan 21, 2018

Alright, I’ve submitted this code upstream facebook#2293

Will continue the WIP there instead.

@alloy alloy closed this Jan 21, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants