Convert an App Built with Reason & ReasonReact into JavaScript & React.

Sean Grove
InstructorSean Grove
Share this video with your friends

Social Share Links

Send Tweet
Published 4 years ago
Updated 3 years ago

A live stream where Sean shows John what it takes to port Reason to JavaScript

Sean: [00:00] I think we'll need lots of questions. As a disclaimer, my experience is only with going from JavaScript to Reason. This will be a new experience for me as well, going from Reason to JavaScript.

[00:12] The reason that I wrote it in Reason was it's a much faster way for me to prototype. As I was new to say, egghead's API and a few other modules, I was able to just take notes using Reason about my assumptions and then build this thing out quickly.

[00:32] Anytime it turns out that I had made a wrong assumption, I could change that in one place and it would tell me everywhere I needed to fix it. It really saved me because I stepped away from this project for a couple of weeks. I just finished it up a couple days ago.

[00:44] Coming back to a project you haven't worked on for a while, especially when it's in a prototype phase can often be a very painful experience. I was able to just dive right in. I was pretty vicious and just changed a bunch of stuff and it's just worked.

[00:58] Now that it's prototyped and good to go, I will hand it over to AKed in a JavaScript form. We'll see how this goes. It may be an interesting learning experience for everyone involved.

John: [01:13] Yeah, this is not practiced or anything, so the final product after an hour or however long we spend probably won't be done, but it'll show the process. Lots to learn here.

Sean: [01:28] Lots of questions, feel free to ask questions along the way. There are probably concepts that are new to a lot of viewers or to anyone, so feel free. I'll go ahead and share my screen and maybe go through the flow once and then walk through the code a little bit and we can start migrating individual modules over from Reason to JavaScript, if that sounds good.

John: [01:49] Yup, awesome.

Sean: [01:51] Go ahead and share this. This is a Gatsby site, so it's a static site that basically is pulled out using AKed's API. I'll list out all of the courses, their lessons and their transcripts and whatnot. Maybe we want to look at Nick Graff's graphical data in React. You're going to open up this course and you need to be logged in with both GitHub, for reasons we'll see, and AKed as well.

[02:30] Now I'm in this course and we have a list of lessons over here, and I can just click on them and it will download the entire transcript, I can see it, and I can edit it. If I see something like a title or something I'd like to change, I can option click on it, and it will actually highlight it down here in the Monaco Editor.

[02:48] I can say, maybe I want to add a title. Once I'm happy with my changes, and I can see the live edits here, I can go ahead and say, create [inaudible] . I'm going to say add a title. Create title. I'll go ahead and submit this. This should have some more feedback right now. It's still in the prototype phase.

[03:15] What it's doing right now is actually forking the Egghead repository on GitHub into my own account. It's then creating a new branch for this change. It's uploading the changed file with the changes I made and then creating a PR directly.

[03:32] If we go over to Egghead, we can see that it's already created a PR here with my changes, including some front matter about what was actually changed. If we go into files change, we can see this is the change that was actually made.

[03:47] The idea here is that Egghead can have this nice GitHub flow where there's a PR workflow. They can review changes and see what needs to be merged in, while also keeping attribution for who changed what. That's not really exposed to any of the people who are editing the transcripts. No one has to worry about the GitHub part.

[04:08] You come in here, you change the parts that you want, and then you can see the changes. If I come down here, I can see that I have two PRs for this lesson already. I can add comments here. Those will, of course, go over into GitHub.

[04:26] This is all done directly from the browser using both Egghead and the GitHub APIs. With that, let's go ahead and start. Take a look at the code. There are basically three files in here. All of that was written in Reason and it compiles down to JavaScript.

[04:52] The convention is, you can see here in courseeditor.re.reason. Every .re file will create a .bs.js file. That's a BuckleScript JavaScript file. From the rest of the world, like in the JavaScript tooling, it looks like JavaScript. You can include that in a Gatsby site, and you don't have to have any additional support, which is great.

[05:21] Let's go ahead and start. The thought was we have lots of individual components here. I thought maybe what we can do is just start with the some of the GUI parts.

[05:34] Maybe we can start with the editor, might be an interesting one, where we can see if we can swap this out from the current Reason implementation to a JavaScript implementation. We're using Monaco. I had to write the bindings to that. Just like TypeScript, where have to tell TypeScript about modules that exist, the functions that they have, the types that they take, and whatnot.

[06:05] I wrote some bindings for React Monaco. Let's see. Where do we actually edit this? Inside of here, we have our editor class. I'm just going to remove this initially, entirely. I'm going to just add a string, hello world, run that through the compiler, and make sure that this is going to do what we expect it to do.

[06:36] Let's go ahead and check in our compiler if it's OK. You can see we have hello world down here. Actually, I meant to edit this one up here. That's why [laughs] I thought we should test it beforehand. Let me go ahead and do that.

[06:53] I'm going to look for a no lesson transcripts, see where that string comes up. Let me know if the font is too small or anything like that. We have right here. We're going to render our login guard, which then is going to, if we're logged in, it's going to render our editor module. This is probably all we need to start with.

[07:25] I'm going to create a new JavaScript file called editor.js. We'll see how this goes. Actually, how does one create a React component? I'm going to use VS code for this JavaScript part of things. Let's see if we can find the editor.js. Let me go ahead and save this over here. Cool.

[08:41] Let's get it so that we can render a React component that has a hello world. I think you just do something like const export component. That's going to be a function that takes component to import React.

John: [09:04] Pretty sure it's export const.

Sean: [09:06] Const, yes. Thank you. [laughs]

John: [09:07] Our key word.

Sean: [09:12] Let's see if we can return just [inaudible] . Now what we need to do is we need to tell Reason that, "Hey, there's this JavaScript module that we wants to interact with." I'm going to pop back up to where we actually call the editor here. I'm going to say, create a new module called JS Editor.

[09:44] We need to tell that use the external. The external is how you say, "Hey, there's a thing that the OCaml compiler doesn't know about." It exists in NPM, JavaScript, C, or whatever. I can come in here and say it comes from this module, which is inside of editor.js. It has this function that we called...What do we call it? Component. We'll give this a better name in just a bit.

[10:22] We'll just say it takes a string and it returns a React element. This one in the string here, this is what it's actually called in JavaScript land. This is what it needs to compile out and refer to.

[10:42] This name right here is what we want to call it over in Reason. Oftentimes, they're the same thing. You might have a bad name in JavaScript for some reason. Maybe the good name was taken by legacy component, and you want to rename it here.

[10:55] I'm going to comment out this suspense bit here. Let's go ahead and render the JS editor.component. I think we need to call this make. It's like a special word. Let's go ahead and call this one make. Let's do that. Now if I just say JS editor and let's do...We have labeled arguments. One second. This is what I want.

John: [11:42] [inaudible] to make this the naming convention that...?

Sean: [11:46] Yeah. This is just like a Babel transform when you do JSX. Whenever you do, for example, my component and name equals Shawn, what this really compiles out to is my component.make and name is Sean.

John: [12:03] Got you.

Sean: [12:05] It's just like a little bit of sugar so that it looks familiar for JSX people, which is pretty nice. I'll copy this one over here, which is what I should have done beforehand.

[12:21] Comes from editor JS, a React component. Let's make it take a name, and we'll do that. Does that work? OK. It takes a name, and this is going to be a string. It cannot take any children for the time being. We'll call this [inaudible] . If we did export defaults, then we would call this one default.

[13:03] Let's see if that worked at all. We undo that real quick. I'm afraid I might have messed up the syntax here. I don't know where this one is. This is probably fine.

[13:28] Say name is Sean. Hopefully, this should render our JavaScript component from Reason land. It's telling you that the types line up. For example, if I had called this none, like I don't have any name, or if I'd given it a number, it will say, "Hey, I expected a string here, but you gave me an integer." The fact that the type bit is happening is good.

[13:59] I'm going to look at the compiled output. Just like I said, we have courseeditor.re. That's always going to translate to a courseeditor.ps.js.

[14:10] This is the compiled output. If you run this through Prettier, it's actually pretty readable. As you can see here, it's just JavaScript objects, for example, over here. What I want to find is, is there an editor.js? There is. You can see here that it has imported editor.js properly, if we search for it.

[14:30] You can see that we have this make here, jseditor.make. Let's see if it's actually going to render it now. First, we'll check the compiler and see if there's any issue. There is a warning that we define React but we never use it just fair inside of our editor.js.

[15:03] I think it's relatively happy with everything else. Let's go ahead and refresh course editor, course.lessons. Let's see. Cool. This is a JavaScript component that's now rendering from Reason. Reason's still checking to make sure that we pass all the right types for those named props.

[15:24] We still have some type safety, but whatever we do inside of here is free for all. We told here Reason that we have this module, it takes the name string, and it returns a React element. It's possible that we could return false or something like that.

[15:45] The Reason compiler is like a baby. It will believe whatever you tell it. You have to be careful like that whenever you're interacting with JavaScript that you get those types right. On the other hand, one nice thing is if we were going the other way, there's a product called genType.

[16:05] Because the type system for Reason is really, really strong, and there's a lot of tooling built around it, there's this ability to just add a...I don't have it installed right now, but you do genType, and it will actually generate full flow or TypeScript bindings for all this stuff. It'll always keep your JavaScript in sync with your Reason.

[16:29] Let's go ahead and take a look at our editor. This is the real editor module. We have a couple of types here. This is what I mean by I have this assumption about the data that I'm working with. I say, all right, I have a payload that I'm trying to edit, which is going to be a transcript, whether notes or the entire edited.

[16:56] The original transcript, the edited transcript. Then the SHA of the original file. We'll see why we need that a little bit later. That's whenever we actually commit to GitHub. It's really nice that we have these notes that we can keep along the way.

[17:12] In JavaScript, this is going to be a little bit more difficult if we're not using, for example, TypeScript. We're going to get here and we have our state for the editor. It's just like useReducer in React, where I have a list of all the actions that my component could possibly do. This is everything that an editor could do, is editor lessons, like lessons like PRs.

[17:37] I have some helper functions. It's a relatively large component. Let's see. This may be all we can actually switch over today, but we'll see if we can get to it. To start with, we actually want to take a couple of these functions here.

[17:59] I'm going to do this [inaudible] buffer, I'm going to paste this in. In JavaScript, you have prop destructuring where you can allocate an object. If I were to call make, I would make an object with a name and add that in.

[18:16] You allocate this object at run time and this is how you get named arguments for a function versus just positional arguments. R2, R3. There are a couple of things that are a little bit dangerous about this. One is you're allocating an object on every functional call, which is a little bit wasteful but probably not the end of the world.

[18:40] The really big problem is it might actually be firstName and you don't realize it. It's very easy as this gets up to...This is very often something like options.

[18:51] When you do your options.firstName, it's very easy to have this part become out of sync with any of the callers. In Reason, you have this first-class concept of labeled arguments, which are with this tilde here. For example, if I have a function like this, whenever I call it...You can call this with any order.

[19:30] I can say, my client is NewClient and jwtMe. We also have punning, which is nice. I'll go into that later. The idea is if I ever get this wrong here, it will tell me, "Hey, I don't know what jwtMe is." It has to be actually that. It always keeps it in sync. It also compiles up to the most efficient possible representation, so you don't allocate an object. You get the best of both worlds there.

[20:02] Let's go ahead and undo all of this. I see that these are the options that it's passing right now, excuse me, the arguments that it's passed in. I'm just going to write a little Emacs macro to find the argument, fill it. Do that a few times. I'm going to copy this over here.

[20:28] Now we're destructuring all the stuff that we expect to use. Now we can say that this is the actual signature for our make function. If you're going to call this JavaScript function, JS editor, you need to pass in these arguments. What did I do?

[20:54] When you have to give it the types...What I'm going to do to get the types real quick is go to the existing editor make and ask, what is the type of this function here? You can see down in the lower left it's going to give me the type. I'm going to go copy that out and let's see if this will work. We'll paste that in.

[21:32] There we go, cool. I was able to say, I know that the JavaScript editor needs to have the same structure as my Reason editor in order for everything to keep working. Let me just go ask what the type of [inaudible] is and I'll make the type right here. John, I don't know if you want to go over and maybe explain the ideas around why we're switching from Reason to JavaScript for anyone who came late?

John: [21:58] Yeah, Desmond, good question. Simply because Sean wrote a project for us that he wrote in Reason because he excels at it and is very productive with it, but our dev team at Egghead are not Reason developers.

[22:17] So he's offered to convert it from Reason to JavaScript more as an educational thing that we could share with everyone listening in and for our developers if we want to make any changes in the future. It's not like we said, "This will be better if it's in JavaScript," it's just that Reason is not right for our team. We're not trained up on it. Maybe we will be if everyone watches this, though.

Sean: [22:50] OK, I think we're making good progress. React is [inaudible] used and it doesn't like...ESLint is another one that is a little bit tough for me because a lot of that is built into the Reason compiler. You get all this stuff in the editor. You're always aware of it, so it doesn't have to block the rendering of the thing.

[23:18] Let's go ahead and get this here and that. Now we should have all of the stuff that we actually care about. Let's go ahead and console log a few of these things and make sure that the data's coming through as we'd expect it. [inaudible] . Log a course as well.

[23:53] I have lots of other noisy logs in here that a good developer wouldn't put in. Here we go. We can see that the JavaScript object is getting our JWT token, which we would expect, and that we have a course object as well. You can see we have the description of the course. We have all of the lessons over here.

[24:22] This looks like we're able to pass stuff into the JS editor pretty nicely. Now what we're going to do is now that we have it calling and passing the data in, we're going to go look at the guts of the editor and try to port that over bit by bits as well.

[24:42] Maybe the first thing we can do is start with the resulting HTML JSX. Let's see. I think it's probably fastest if I just take this and I try to chop it up inside of Emacs into the JavaScript-compatible JSX with a couple of Emacs macros. Man, this is a huge, huge component.

[25:17] I'm just going to attempt buffer. I'm going to paste this in. All of these style up make, let's see how many of these we have. In Reason, everything has to be typed. There are escape patches, but it's really hard to do something like in INI, like in TypeScript.

[25:44] Even your styles ultimately have to go through this function called ReactDom style make, which has all these. If we ask it, for example, "Hey, what's the type of make? What are the arguments that it takes?" you can see that it has all of these...every CSS property is actually listed inside of here as an optional thing.

[26:04] This is actually how you make styles at the lowest level. This makes sure that everything is ultimately typed. Obviously, in JavaScript, we don't do that. What I'm going to do is write a little Emacs macro here, click for ReactDom re.

[26:24] Then I'm going to search for a make. I'm going to kill that. I'm going to go to the inside and then jump back right here. I think that that will be probably the most the Emacs macro can do for us. Now I'm going to wrap this in that.

[26:52] Enough, I jump to the next one. Cool. It worked. Same idea. If I were doing this on a bigger project, I would automate this in a better way. For the time being, this will work just fine. You can see that it's Emacs macros doing the rework.

[27:15] Part of why it's so nice that Reason and JavaScript share so much in its syntax, because these translations become mechanical, which means it's much easier to automate them.

John: [27:28] I have no experience with Reason, but it's still pretty easy to navigate visually for me.

Sean: [27:34] It comes from OCaml a long time ago originally. People thought it was a relatively silly idea to change the syntax to look like JavaScript. After doing some workshops in it, I was completely blown away how much more approachable it is for people.

[27:50] Having a different syntax doesn't gain you a whole lot. It can really scare people away. It looks different for no discernable advantage.

[28:02] The other thing is I'm going to search for the js.log. I'm going to replace that with a console.log. We actually have...I guess I only have one of those. The switches are going to be a bigger deal. So many things in Reason come down to pattern matching, which is where the switch comes in. Imagine, for example, you have a function or a component that...Go ahead.

John: [28:33] I was just going to say it's a gaping hole in JavaScript is the lack of pattern matching, it feels like.

Sean: [28:39] The challenge with the switch in JavaScript is that it's a statement, so it can't really return anything. It makes it very difficult. Imagine if we had an action. There are three things. We could log in, we could log out, or we could greet. If we were to greet, we would want to greet with a string.

[29:04] If I come down here now, I can say lets name is...I'm going to switch [inaudible] if I can call a getName. It's going to take an action, and based off of the action, if it is a grett, we'll get the name out of here and we'll return that. If it's a log in, we'll say no name. [inaudible] .

[29:42] There's something wrong. Let's see if I can fix this. [inaudible] . I just want the switch here. I'm not sure what I'm doing wrong. [inaudible] chat is probably screaming at me. Oh, yes, switch action. [laughs] I need to switch over the thing, obviously.

[30:14] The next here is it's going to tell me that hey you're missing one of the actions, which is one of the first issues. It knows that these are the three possible actions, and it knows that I forgot it. I can say while I'm logged out there's no name.

[30:30] The cool thing is I can say, for example, I can assign this a value to a variable. Switch is an expression versus a statement, which means a lot of the code where you're doing an if else this and you have a let beforehand, and the if/else will change the value of that up there gets really shrunk down into this much easier to read form here.

[30:59] Translating the switches where we're switching over a lesson which is knowable. We might not have a lesson. It's going to be a little bit more challenging. I might see about how to do that. Get rid of my comment.

[31:14] Let's see. I guess we'll just something like let lesson. Then if there is no lesson, then we'll say that lesson is going to be equal to the lesson selected. If there...We're going to do it the other way around. If there is a lesson, then we'll assign it...I'm not sure about the truthy values. Let's do, if there is, then we'll say, "Lesson is [inaudible] selected."

[31:56] Let's go ahead and copy this part over to start with. We'll close this. We also need to return this. We don't have a lesson right now. We'll put this here, we'll say, "This is a lesson." I'm not sure where did we get the lesson from.

[32:46] Let's go ahead and look at the...I can jump this, ask where is this defined. It looks like, in our component states, we have the lesson ID that we're looking at. Then we get inside of our hashmap and say...We need to build a hashmap of lessons from our courses. To start with, maybe we can dump the structure of the course, so to be a little bit more clear.

[33:20] I'm going to say, null. Here, we'll do a pre tag, I'll do a JSON.stringify of the course. Did I get that wrong? Yes, I need to do that, and React must be in scope. That's fair. We have no lessons selected, which makes sense. Let's go ahead and look at the component states up here. I'm going to copy this over into...Here, we'll make our first light default state, based off of this.

[34:16] We have a list of PRs, where this is a map of lesson ID to a PR. This is Boolean. This is a map of lesson ID to a lesson edit, [inaudible] do the lesson edits. This is, likewise, pretty important to have. Reason? Watch my back, because in a month, I've forgotten what a lesson edit is. I can come in here and I see, "Oh! A lesson edit is this."

John: [35:00] I agree.

Sean: [35:00] It's going to be our lesson edit. This is our current lesson that we're looking at, which is potentially none. We might not have selected a lesson. This is the current PR that we're looking at, which also might be none. Inside of here, this is going to be one of these lessons right here. I don't think we need to worry about that too much. Then, the edit payload is here.

[35:35] Finally, at the bottom, we have our transcript, which is the original transcript we edited, and the sha. This is at the bottom.

[35:45] Now we want to look at let lesson. What this is doing is just taking the current lessonID, which is in our state, and looking it up inside of the map. Let's do defaultState. Our prs are going to be an empty object. ChatOpen will default to false. Lessons will be an empty object, lessonID will be null, and the prID will be null.

[36:29] We're going to start porting over the reducer so it can capture all the actions that our editor does so far. Bring that in.

[36:38] Now we have our action. We'll have to look this up though. I don't know in JavaScript React how to do a useReducer. I assume it's basically the same as Reason. useReducer this. We need to have this action.type. Actually, this is like a Redux style. Redux has this pattern, right, where there's a type discriminator?

John: [37:23] Yeah.

Sean: [37:28] Let's see. I think one of the actions that we allowed was select lesson. We can just start with that. We'll say it's select lesson. In that case, we want to return our previous state, but with the lesson ID set to the action.lessonID. Otherwise, I guess we'll throw an error.

[38:05] Let's make a button. I'm going to cheat to start with and just look at the lesson ID. We'll say, "3845." Let's also do the same thing here, where we'll actually take a look at our state as we're debugging it. Do it here, where our initial state...We call it default state. We'll just keep their conventions. We're using reducer.

[38:52] We're starting to port our state from Reason over into JavaScript now. Now we want to have a button that's just going to cheat and select a lesson. We'll have to do a button. We dispatch. We need to do something like the action is selectLesson.

[39:30] Does anyone know if there's a convention for actions? Are they capitalized like this or snake case or are all uppercase? What's the normal convention in JavaScript land? Screaming case.

John: [39:45] [laughs]

Sean: [39:52] We'll selectLesson. We're going to set the lesson ID to be 3845. This is where it's going to get a little bit scary for me. Now I need to remember that selectLesson has a field called lessonID on it. It's possible I may think it's ID.

[40:14] My mind constantly makes up good arguments why it should be a different name in the middle of a programming session, and I forget what I actually called it originally. I always think it'll be so logical. I'll always remember it.

[40:31] Now we have this set up. Hopefully, if I...That's not quite what I was hoping for. Let's see, selectLesson. What did I do wrong? Oh, I need to pass in the state first. I see. It's state and then...Let me see how this one works. We dispatch. We don't need to do that. Maybe useReducer's supposed to already pass in the state for us. What did I do wrong? These match up. These match up.

[41:29] [crosstalk]

Sean: [41:31] I see. This needs to be nested in another thing. Thank you. If you don't have the Reason type system to back you, then you probably want to have the Egghead crowd watching over your shoulder.

John: [41:49] No, still wrong. Dispatch action type.

Sean: [41:58] I see, OK.

John: [41:59] The payload's probably another object.

Sean: [42:07] Cool. [inaudible] . [laughs] Small gains, small ones.

John: [42:20] Since we're 45 minutes in, I know I would love to see more about the authentication, the flow. Just how it all works and hits the endpoints.

Sean: [42:35] Sure. Maybe we can...

[42:38] [crosstalk]

John: [42:38] GraphQL and authentication and stuff on that...

[42:42] [crosstalk]

Sean: [42:42] All right. See if this will come in. What we do is just show what it looks like to...We haven't logged in with Twitch at all. We can log in with Egghead and GitHub. We can still see what it might look like if we also want to bring in some Twitch information. Someone could post it here with the Twitch info. The way this works, I have this one over in [inaudible] bindings.

[43:40] What I'm going to do is actually just look at the compile outputs for this. I think it should be copy pasteable for us. Look for auth for log in [inaudible] . This is the compiled JavaScript output, which is a bit messy now because I can't run Prettier on it for whatever reason. I'm just going to look for this auth. Let's see where it's auth-defined.

[45:04] [inaudible] . Or just go to our docs. We can just copy this over, which is how we're going to do auth. I just need to get the app ID. There we go. Then we'll do a string-streaming case. Cool. Now we have one graph off setup. To log in a user, we can just do this. We'll copy this.

[46:29] What we're going to do is make this button, so that's on click, it's going to log you into Twitch. We say button and click. Throw that in there. Then just do Twitch. Let's see if that works. Going to need to do a login. We're writing it there. Let's see if this works now.

[47:15] This is going to go through the flow. I was already logged into Twitch, so it already sent me back here. Now I should be logged into Twitch. If I wanted to, for example, let's make a quick API call to see my information about me in Twitch. Let me go into Explorer.

[47:43] We'll go find out about me. If I'm logged in to Twitch, I want to know my display name, my email, my name, and my ID. We'll go ahead and run this. I'm going to call this find me on Twitch. I'll log in. This is what I should expect to see for my user whenever I'm logged in inside of the app.

[48:16] I'm going to export this as fetch. I'm just going to copy this in as our login function. What this is doing, this is graphical. We wrote some extra plugins, for example, that lets you explore GraphQL on the left here. Then once you are ready and you like the data, we actually built a little thing that will export to JavaScript.

[48:41] In this case, I'm exporting as fetch rather than a React component. I'm just going to copy these two functions over. Now it should have find me on Twitch. If we are logged in, I'm going to call wait, find me on fetch. We'll just console.log.start.

John: [49:16] You'll have to make the function async.

Sean: [49:19] Oh, thank you. Hopefully, I can just do that right there?

John: [49:25] Inside of the [inaudible] .

Sean: [49:28] Inside of here as well? Probably not here. We'll open this up and log in. I logged in. I need to add, I guess...We have maybe a CORS origin issue. Let me see what happened. You can see I'm logged into Twitch here, but then this didn't allow it for some reason. Let me see if there was some issue on my side.

[50:11] Copy this as Chrome. I'm going to paste this in. I find CORS errors are really hard to debug. What I tend to do is just copy them into a batch script here and save them. Now I can just run chmod +x.

John: [50:39] Do you want to make an Egghead course on debugging CORS errors?

Sean: [50:44] [laughs]

John: [50:44] People would watch it.

Sean: [50:48] Looks like I used the wrong auth or app ID. That was my bad. Just do this. Right here, I was using the wrong app ID. I logged it into an app that's not going to allow this. Let's go ahead and paste that in and clear this out one more time.

[51:18] There we go. Now I have all the information about me from Twitch. We added login with Twitch. We have all their information that we need from them for this app right. That's what it looks like to add login with a service. We could similarly change that to Egghead or Salesforce or Spotify or whatever. Was there other parts you want to see?

John: [51:50] We also mentioned some [inaudible] point out the GitHub API parts and how that...

Sean: [51:55] Yeah, sure.

John: [51:56] Is that running through OneGraph at all, the calls or is it accessing...

Sean: [52:01] The GitHub API is really well-designed, but it's still split between their REST and their GraphQL. Most of the functionality is on GraphQL, but not all of it. We pull in their GitHub GraphQL API, but we also extend it with the functionality that's available inside of the REST API.

[52:25] For example, if I wanted to come in here and if I wanted to create for fork a repo, we can come in here. We can look for...

John: [52:35] Just real quick. This OneGraph graphical, once you sign up and create an app, this is just available...

[52:43] [crosstalk]

Sean: [52:44] Exactly, yeah.

[52:45] [crosstalk]

John: [52:47] Sorry. You could explain it better than I could. I signed up for an account. All this stuff was there. There's no fancy thing of getting to this. It's just create an account and create an app, which is clicking two buttons.

Sean: [53:03] You can do some pretty cool things. I'll just make a quick Egghead [inaudible] . I just created a new app. Now I'm inside of the full OneGraph one. I'm going to add a mutation. For those of you who don't know, GraphQL has three concepts.

[53:26] One is query, which is where you're reading the data. The other is mutation, as where you would write such as GitHub posts in an API, and then subscriptions, which are kind of a live updating data. Mutation is going to do something. It's not just going to read data. It's going to do something.

[53:42] I can come here in GitHub and see here are all the actions that are available to me. For example, I want to maybe create a repository. I'm coming here and say egghead live and I'm making this public for everyone. Having created it, I want to get the issues, the ID and maybe the URL. We'll call this one create github repo. When I run this, I'm not logged into GitHub, so it'll ask me to log in.

[54:22] We'll run and now I have a GitHub repository that I was able to create. It's empty, obviously, but if I wanted to, for example, then upload a file, I could add another mutation here.

[54:38] Let's do create or update file content. This is the commit message. Then, we'll do it at readme.md. The repo name is egghead demo live and I'm the owner. We'll do the plain content, which is [inaudible] .

[55:14] This is actually going to make a git commit, so we'll get all this information out. I'll run that. I'll have to come over here. Hey, we have the hello from GraphQL. I think that this creator update file content, it doesn't exist in the GitHub GraphQL API, but people still want to be able to do that from the browser, right?

[55:40] For example, in the Egghead example, we're actually creating new files and modifying them directly from in the browser and we don't want to have a server to actually do that stuff for us. What we do on OneGraph is we pull in that functionality, and we append it with OneGraph.

[55:58] The idea here is, this way, you're always guaranteed that even if they introduce an action called creator update file content, we'll guarantee that this one will always work, and will actually map this one to the new one, and you'll never lose functionality. You can commit to this one API version, and then you're good to go.

[56:20] If you want to get this into, for example, this is hard-coded, but we can actually do that export where instead of exporting to fetch, I'm actually going to create a React Apollo application. You can see here that it's analyzed all of the operations over here.

[56:39] We do best practices. You can see here, a lot of people don't know you can name graph QL operations. We say, "Hey, we noticed that you haven't given us a name. It's probably a good idea to. We won't stop you, but probably you should think about it."

[56:53] Then [inaudible] has this full Reacts Apollo application will create a CodeSandbox that actually has it running right now. If I click this, let's do a live demo two and create another CodeSandbox. I feel a little bit bad for CodeSandbox, it would just throw a bunch of stuff at them. If I run this...

[57:18] [crosstalk]

Sean: [57:20] You can see that login is already built in. It said, "Hey, you weren't logged in." This generated app already does all for you. There we go. Now whenever I go here, I should have demo live two. This is a full React app that I can just copy and paste that will actually interact with GitHub and create repositories, or upload files, or whatever.

John: [57:43] It's such a great starting point. HelloWorld is now, it requires [inaudible] or almost every app. It's just the way the world works.

Sean: [57:55] Yeah. Whenever you're getting started, you're just desperate to get anything to work. You traverse the wilderness where nothing's working for a very, very long period of time. What you want is just like, give me an example that works, and I'll start tweaking it. I'll nudge it closer to what I want.

[58:16] That way, it's always successful. If anything breaks, you just go back to the thing you were doing before which works, and you can keep going. I'm pretty excited about the future of the graphical tooling that we're going to be able to build out.

[58:36] Basically, the idea for converting the Reason over to JavaScript is just going to be a lot of that where it's just Emacs macros, copying and pasting, and then being very careful as things transform into JavaScript, and you rely more and more on your own ability and your own discipline to keep things in shape. The GraphQL part is pretty easy.

John: [59:06] Have you done it the other way where you've converted a JavaScript project into Reason? Is that pretty seamless?

Sean: [59:11] Yeah, I find that one to be actually significantly easier because what happens is you start with...The process whether you're using Reason or not is going to be the same. You come to some code base, you're trying to think what are the data structures that are passing through here?

[59:29] This function takes some arguments and returns something, and I have to keep that in my head. You work on it but every function that it calls, you also have to keep in your head. When something breaks, you have to dive all the way down.

[59:44] I think of Reason as this notepad. I keep the notes over here while I'm saying it takes these types and it returns these types. Then I port one module over the Reason and I make sure that everything is right. If I get anything wrong, then it will tell me, "Hey, these things actually are wrong. Fix it up."

[60:01] If you do something like use genType, where it will actually take the...This is a story from messenger.com, which is now I think almost 100 percent on the front-end Reason. They actually had this problem because they were using Flow.

[60:15] As they switched over to Reason, which has a much stronger and sounder type system, they had less and less type coverage. Because Reason would output this JavaScript, but Flow didn't have any type support. Anything that was left in Flow was basically just calling into this big blob of untype JavaScript.

[60:34] That's why the built genType was to say we want to be able to incrementally migrate pieces over. We can take the most troublesome parts of our app where we're going to get the most leverage, we'll convert that over but it still has to interact with the rest of the JavaScript that we have.

[60:50] They wrote genType which actually generates those really, really nice flow types and typescripts. It generates them as though you were really disciplined. Then you can just consume it. The migration is much more seamless the other way, I think, going from JavaScript over to Reason.

John: [61:07] Very cool. All right. If the chat doesn't have any questions, I think we'll wrap up so Sean can get back to his day job.

Sean: [61:15] [laughs] Thank you very much for having me. This was a lot of fun. I hope it was at least somewhat interesting.

John: [61:25] The other thing I would note, we do have a course on Reason on Egghead by Nik Graf. Check that out. Just get on Egghead and search for...I guess I can paste the link.

Sean: [61:35] Nik Graf is great. He also has a course on GraphQL schema design, which is phenomenal. He's a machine.

John: [61:45] I'll just drop that link in here real quick. Any one Graph plugs you want to make?

Sean: [61:51] No. If anyone wants to try anything, we have a bunch of interesting examples. Just basically ping me on Twitter, and I'm happy to talk about any app ideas for implementation or whatnot. Maybe a fun one I could...There's a super long talk I gave that is just full of a bunch of GraphQL [inaudible] that we're working on that's almost all open source. That's a plug I'll give.

John: [62:24] I pasted your Twitter handle.

Sean: [62:27] Thank you.

John: [62:30] All right. Thanks, everyone.

Sean: [62:32] Thank you.

John: [62:32] Later.

Daniel Mantei
Daniel Mantei
~ 4 years ago

Not having watched the full video, please forgive me if this is a stupid question, but... why would you want to switch from Reason to JavaScript (our Typescript)?

Yours truly, A person who is learning Reason to get away from JS/TS (for code safety and improved language ergonomics)

Sean Grove
Sean Groveinstructor
~ 4 years ago

Good question! We mention it in the video but:

We built a proof-of-concept of the Egghead transcript editor (e.g. https://eggy.netlify.com/courses/shareable-custom-hooks-in-react) in Reason because that's by far the fastest way for us to prototype and build.

But the initial plan was to hand it off to the Egghead folks to maintain, and it's not fair for us to force Reason on them if they didn't ask for it. So we agreed ahead of time that we'd convert it to JavaScript if they decided to use it, so that their team could hit the ground running maintaining it.

It's also an interesting experience (I've only ever gone the other way, converting JavaScript to Reason) to mechanically translate the code in such a way where you don't break assumptions. Reason helps a ton with even that!

Markdown supported.
Become a member to join the discussionEnroll Today