npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

scala-relay-compiler

v0.12.4

Published

A compiler tool for building GraphQL-driven Scala.js applications.

Downloads

120

Readme

scala-relay-compiler

The purpose of this project is to generate Scala.js bindings for the relay-compiler. Typically the relay-compiler generates flow bindings along with the compiled queries. This project replaces that generation and outputs js.native traits instead. It is experimental and the code needs work, but it can generated traits for deep hierarchical graphs.

It uses flow because it's what relay uses, and its better than raw javascript.

It uses outputDir to generate all the source files and whatnot in the same package. So its a big flat package repository in the same directory. Typically (resourceManaged in Compile).value / "relay-compiler-out" is where it outputs in sbt parlance.

Versions

  • 0.11.0 - Relay 1.6.2
  • 0.9.0 - Relay 1.5.0
  • 0.8.2 - Relay 1.4.0

Example

$ ./bin/scala-relay-compiler.js --src example/src/ --schema example/schema.graphql --out example/out/

Features

  • Handles names elegantly by scoping them to the companion object.
  • Handles first layer of spreading, right now we spit out js.| to join disjoint fields, even though in fact they are not disjoint, they are a union, however, this requires a fix later down the line.
  • @scalajs(extends: String) This can give you a parent class to mixin. It's your job to verify it.
  • @scalajs(useNulls: Boolean) this can give you finer control on using A | Null on a Fragment, field or inline fragment.

Example

Ill walk you through a simple example. I'll assume you know roughly how Relay Modern works.

We'll obviously need a schema, for which we'll use the example provided.

schema {
  query: Root
}

type Root {
  dictionary: [Word]
}

type Word {
  id: String!
  definition: WordDefinition
}

type WordDefinition {
  id: String
  text: String
  image: String
}

From this we'll want to generate some queries in which Ill list one top level query including two fragments. Now this is where we start to diverge from the stock relay-compiler. Our method of collecting queries/fragments/mutations is a regex (I know, ugly) through *.scala files. We look for the @gql(""" indicator and its corresponding """) to isolate the queries.

Here is an example taken straight from the repository.

object Foo {

  val otherGql = @gql("""
  fragment DictionaryComponent_definition on WordDefinition {
    text
    image
  }
  """)

  val gql = @gql("""
  fragment DictionaryComponent_word on Word {
    id
    definition {
      ...DictionaryComponent_definition
      text
      id
    }
  }
  """)

  val query = @gql("""
  query DictionaryQuery {
    dictionary {
      ...DictionaryComponent_word
    }
  }
  """)
}

So now we have the schema, and a query + two fragments. Time to generate! So we run the following command.

$ ./bin/scala-relay-compiler.js --src example/src/ --schema example/schema.graphql --out example/out/

And get three files. Queries and Mutations or top level components all have the same structure. The object represents the top level query, and the trait represents the data coming over the wire.

This basically replaces the js files that typically get generated by the compiler. Specifically the part the runtime needs is in DictionaryQuery.query

So the generation below handles DictionaryQuery. I cut some text for brevity

trait DictionaryQuery extends js.Object {
  /** Combined the fields on a spread: DictionaryComponent_word */
   val dictionary : js.Array[DictionaryComponent_word]
}


object DictionaryQuery extends _root_.relay.graphql.GenericGraphQLTaggedNode {
  val query: _root_.relay.graphql.ConcreteBatch = _root_.scala.scalajs.js.JSON.parse("""{
  "fragment": {
    ....
    "text": "query DictionaryQuery {\n  dictionary {\n    ...DictionaryComponent_word\n  }\n}\n\nfragment DictionaryComponent_word on Word {\n  id\n  definition {\n    ...DictionaryComponent_definition\n    text\n    id\n  }\n}\n\nfragment DictionaryComponent_definition on WordDefinition {\n  text\n  image\n}\n"
}""").asInstanceOf[_root_.relay.graphql.ConcreteBatch]

What does fragments look like you ask? You'll notice some comments, its basically a way to look up what happened in the code to make sure the generator didn't do something wonky.

As you can see the top level definition lives at the root package relay.generated And all the sub traits get generated underneath the trait's companion object.

package relay.generated

trait DictionaryComponent_word extends js.Object {
  /** New fields added, conflicts detected. */
   val definition : DictionaryComponent_word.Definition
   val id : String
}

object DictionaryComponent_word extends _root_.relay.graphql.GenericGraphQLTaggedNode {

  trait Definition extends js.Object {
    val id : String
    /** getDirectMembersForFrag child of DictionaryComponent_definition Combining fields, with or? "true"  */
    val text : String
    /** getDirectMembersForFrag child of DictionaryComponent_definition */
    val image : String
  }

  val query: _root_.relay.graphql.ConcreteFragment = _root_.scala.scalajs.js.JSON.parse("""{
    ....
    """)
}

Ill skip the other definition because there's nothing additionally interesting.

So that's it.

You can use from sbt by using, and it will include the tiny shim of javascript traits to use.

addSbtPlugin("com.dispalt.relay" % "sbt-relay-compiler" % "<version>")

TODO

A list of tasks/ideas the community could help with. High | Med | Low refers to the complexity/difficulty.

  • [x] Med: Fix InlineFragments so they work properly. Right now we just really don't handle them.
  • [ ] Big: Fix spreading so it goes recursively? Right now spreading is difficult because the types that are mixed in couple potentially conflict
    • [ ] Med: Make it work recursively
    • [ ] Med: Generate the necessary class depth.
    • [ ] Big: How to handle traversing since the order of the frags are unable to to be changed.
  • [ ] Med: Handle connections and edges with a superclass.
  • [ ] High: Handle exotic features of graphql.
    • [ ] Low: Handle conditionals.
    • [ ] Low: Figure out what is not working.
  • [ ] High: Does recursion work?
  • [ ] Low: handle indents in generated code better
  • [ ]