简体   繁体   中英

How to transpile a Relay query from TypeScript to ES5?

I'm writing a web app in TypeScript. The app uses React and Relay from Facebook. My TypeScript source code gets compiled into ES6 code using the TypeScript compiler TSC. Then, the ES6 code gets transpiled into ES5 code using Babel. In order for Relay to work in the browser, a Babel plugin needs to transform the Relay GraphQL queries: https://facebook.github.io/relay/docs/guides-babel-plugin.html . The problem is, because TSC first transpiles these queries, the Babel Relay plugin doesn't recognize them anymore so they don't get transpiled into something the browser understands, so the browser throws an error:

Uncaught Invariant Violation: RelayQL: Unexpected invocation at runtime. Either the Babel transform was not set up, or it failed to identify this call site. Make sure it is being used verbatim as Relay.QL .

My TypeScript source code:

const SiteQuery = {
    store: () => Relay.QL`query { site }`
};

... this gets compiled by TSC into something like this:

var SiteQuery = {\r\n    store: function () { return (_a = [\"query { site }\"], _a.raw = [\"query { site }\"], Relay.QL(_a)); var _a; }\r\n};

... instead of something like this (because the Babel Relay plugin doesn't do its work properly):

var SiteQuery = {\n    store: function store() {\n        return (function () {\n            return {\n                fieldName: 'site',\n                kind: 'Query',\n                metadata: {},\n                name: 'Router',\n                type: 'Site'\n            };

This is because the Babel Relay plugin doesn't recognize the transpiled version, and as a result it doesn't transpile the query into something the browser understands.

How to make this work?

The answers here were helpful, but I thought I'd share what finally worked for me.

  1. Setup your babel-relay-plugin correctly. If you're running into problems here, I recommend using the npm package babel-relay-plugin-loader which then allows you to specify the location of your schema.json in package.json. For example: { "metadata": { "graphql": { "schema": "./schema.json" } } }
  2. Setup your babel config correctly. It should look something like this:

    { "passPerPreset": true, "presets": [ "react", "es2015", "stage-0" ], "plugins": [ "babel-relay-plugin-loader" ] } },

  3. Setup your tsconfig to target "es6" -- this actually was essential to make my setup work. ts-loader then compiles to es6 and Babel handles the transpile down to es5.

  4. Finally, add the loaders to your webpack config. Remember, it applies these RIGHT to left. So, mine looks like this:

    loaders: [ { test: /.tsx?$/, exclude: /node_modules/, loader: 'react-hot!babel!ts-loader', }, ],

You need to tell the Typescript compiler to transpile to ES6, then use Babel with babel-relay-plugin and es2015 preset to transpile the code to ES5 to run in your browser.

I recommend using Webpack to orchestrate all this. These will get you started:

  1. http://www.jbrantly.com/typescript-and-webpack/
  2. http://www.jbrantly.com/es6-modules-with-typescript-and-webpack/

The posts were written for Babel 5.x, so you'll need to manually add es2015 preset to make sure Babel compiles the ES6 sources to ES6.

Just in case, when you say

My TypeScript source code gets compiled into ES6 code using the TypeScript compiler TSC. Then, the ES6 code gets transpiled into ES5 code using Babel.

You can instruct TypeScript itself to transpile directly to es5, just set target: 'es5' in tsconfig.json and that's it, hope it helps since you can eliminate babel from your compile chain.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM