 So, the name of this talk is Using Elixir Script, and what I hope to do with this talk is get people to either try out Elixir Script or get involved with the project and help out and get it closer to the finish line. My name is Brian Joseph. I work at Rubbery, which is a consultancy company in New Orleans and where I get to do some Elixir projects. I am from New Orleans and I'm still there. And you can find me on GitHub, Twitter, and Hex, same username, BrianJOS. So what is Elixir Script? It is an Elixir JavaScript compiler. Has anybody ever tried to get or looked at it? That's one. Couple more. Well, cool. So the project was started late January 2015. It has about 800 stars, a little bit less. Had 11 contributors, but most of it has been me. And my proudest stat is that it's written mostly in Elixir, and I hope to make that to like 100% one day. That would be nice. The project goals are to use Elixir in JavaScript environments. So I hear people say that JavaScript can run, is the only language that runs everywhere. I kind of disagree with that. But even so, I would prefer to write Elixir and use Elixir in other environments. So in particular, the browser using Elixir in those situations. And also easy interoperability with JavaScript. I want to make it easy to use JavaScript modules and use JavaScript functions and use the JavaScript data types, without any kind of ceremony. And for the most part, that's still true. So there's been a couple of projects that were created strictly to facilitate Elixir Script. One of those is the ES Tree project. So ES Tree is actually a JavaScript spec. It was based off the SpiderMonkey AST, and it is the one that most of the JavaScript tools around the JavaScript AST are based off of. So for instance, Esprima adheres to it. Babel, I think it has like a kind of derivative of it, but it kind of uses it. So that's up to date as of ES 2017. So the latest changes in ES 2017 were async and await. So you can use that. And what this ES Tree module does in Elixir Script, I'm sorry, in Elixir, it defines a JavaScript, excuse me, it defines structs for each of the JavaScript AST nodes and also defines tools for you to build up a JavaScript AST and also take the AST and turn it into JavaScript code. There are also three JavaScript modules that were created for Elixir Script. The first one is tailored, which is the pattern matching library. The next one is the Erlang types library, which has Erlang primitives. So Elixir Script will use the JavaScript equivalents when it can, but for things like references and PIDs and tuples and bit strings, this library creates JavaScript implementations for those. And the third one is processes, which is the Erlang process model. This one is the one that isn't really used in Elixir Script just yet. It works for as far as I can tell in JavaScript, but it's kind of hard to shoe hoard it into what's already there, so that's kind of been the issue. So how does it work? So it takes in Elixir files, like Elixir code files or code strings as input. It passes those to the Elixir compiler, and what this does is whatever you have an error in the codes you pass in, you get Elixir's nice error messages, so the same error messages you are familiar with. The second value you get from that is that it loads in the modules that it compiled so that we can use those to expand macros whenever we get to them. It then converts those code strings basically to the Elixir AST, and it does some pre-processing, like one of those is turning the variables into, like, you know when you do like A equals one, A equals two, and it turns into, like, different variables in the background with Elixir. It kind of does things like that. And then it goes and transforms the Elixir AST to JavaScript AST, and then from there it turns JavaScript to JavaScript AST to JavaScript code. So this is kind of an image of how things work. You got input your Elixir code files and output JavaScript code files, and in the middle is a pipeline of different steps that it takes. And in code, it's almost like a literal pipeline where each of these steps handles a different case in the completion process. And I got the idea from a friend of mine who showed me a video by Andy Keepe, I think it was a closure conference, and he was showing off Nanopass compilers, and this isn't, each of these aren't like necessarily like a Nanopass compiler, but it gave me the idea to break up the steps of the compilation into these, into these passes, and it made it easier to maintain and easier to remove things or move things around if I needed to, so it slows down the completion process, but I think it's still worth it. So here is a mapping of how Elixir script handles the primitives. So a list turns into a JavaScript array, a map turns into an object, an atom turns into a symbol, a binary into a string, and the integer and a float into a number. And for bit string, tuple, pids, and references, that's where the Erlang Types library comes in, and it has implementations for those. So what can I do so far? So most of the special forms, modules, functions, pattern matching, public macros, protocols, structs, sigils, bit strings, I'm probably missing some things in this list. I kind of went through the Elixir Lang guide and just started writing things down just to get like a proper list. For the standard library, it can do, well you see in the complete column there's a lot of things that are in a complete agent. Well, I'll get to that later. So those are the things that are complete as far as like it has all the functions and macros there. Incomplete, kernel, it doesn't implement everything just yet. And enum, it doesn't implement everything. And it is also the only thing that is, all of these are actually implemented within the Elixir script. So we're actually in Elixir. Enum is the only one that isn't for a couple of reasons. I won't go into it right now. So limitations, no OTP, so don't even try. Buggy processes, so I'm going to do this a little bit, these no OTP and the buggy processes. So I showed you all the Erlang processes, the JavaScript packet module that I created. And that works just fine. The problem has just always been integrating that within the compilation process that I have right now. And so I've tried a couple of times to add it into Elixir script, but every now and then, well, when I try, I will come across a different issue like before. The first time I was like, I have to go back in all the JavaScript code that I wrote for this. I have to go back and turn it into generators because for a processes library, it works off of generators. Everything has to be a generator for it to work. So I stopped at that point, and then I came back months later. I was like, I'm really going to do this now. This is going to happen. And I got pretty far, but then I realized how important OTP is when I was like, how do I start all this? Oh, that's right. There's an application start thing. And I don't have that yet. And then it just kept piling on, and I'm like, OK, I want to stop now. So that's kind of the story around that. Not all special forms are implemented. So super is actually the only one that isn't implemented at all. I think location is the only option that isn't supported, but everything else is there. No private macros because of the way that I showed earlier of how we're getting the modules and using that to load the macros. That's not really a way to do that with private macros, as far as I can tell. So it doesn't support private macros as yet. An incomplete standard library, which I showed before, doesn't recognize dependencies. So it actually was going to, but I wanted to ask for some feedback on how I did things, which is basically going into the depths folder and getting everything and compiling that. When I asked, someone said that that's probably not the best way to do things. And then I asked, how else should I do it? And I didn't get an answer. So I just backed it up because I trusted that they probably knew they were talking about. So still looking for a solution for that. And also, you still need Babel or some kind of tool to convert the output to something that is usable. And the main reason is ES modules. So back when I started this, it was January 30, 2015, either the ES 2015 spec was completed or was about to be. Anyway, 2015 had ES modules in it. And so I was like, we're just going to go in that direction. Fast forward to, what is this, February 2017. And we still can't use ES modules natively within browsers or within node. And it's around the ES loader spec, which if you start thinking about how to load in ES modules, it's not an easy thing. So that's why. And I think if I went back, if I had to go back, I would probably use common JS modules instead. And I even have code in the Lyxa script to use common JS. But I haven't pulled the trigger because it always seems like ES modules are so close to being just a thing. But they aren't yet. So installation. So how would you install it? The first way would be using, if you want to use the CLI, you can either compile it and install it from source. You can, for each release, there's a pre-compiled version which you can use. Or if you're on macOS, you can use brew install Lyxa script. And somebody's been really helpful in keeping the homebrew version up to date. I don't know who it is, but I thank you. And I think there's actually one for ArtsLinux, I think. What is it, AUR? That's what it's called. I think there's a way you can get it from there. And one of the things I also did was I created a boilerplate project, which I don't even like boilerplate projects, but it doesn't make it easier for people to use Lyxa script within a front-end project. And the only thing it really requires is that you have the Lyxa script CLI installed. So if you want to get up and running pretty quickly, you can do that. The second way is as a mixed dependency. So you can add it to your list of mixed dependencies. What you get with that is a mixed task which acts just like the CLI. But the really cool thing you get with that is that you can add it to your list of mixed compilers and add some options in there for figuring out where the input and output is. And whenever you do mixed compile, it will actually go through the input and output folders and compile code. So you only have to use mixed compile to actually make that happen. So how do you interact with JavaScript? The first one we're going to show is using the JS module. So the JS module contains functions and macros that map to JavaScript keywords or just helper functions that while I've been testing, I kind of have a need for. So the two I've used the most, and you'll probably use the most are import and new, which is also type of instance of global throw yield and def gen and def gen p are how you would create generators. And to use these, since it is an Elixir module, you would use either requireJS or importJS, but you can't import import, so just keep it in mind. So the first one we'll talk about is importing a ES module. So you would use JS import, and it takes the first argument is the name of the module that you want to call the module within your Elixir code. So the example here is React. We want to call it React. And then the second is the path to it, which in this case is just React. And you can see at the top of that what kind of import statement it creates in JavaScript. So the default is to make a default import. But if you want to use a non-default import, you can add the default specifier, the default option, and make it false, and then you would get an import star as import. The second one that you probably use the most because JavaScript is creating a new object. So with that, JS.new will create a new object. You give it the name of the object and then a list of arguments. One note is ElixirScript can't create classes, but you can instantiate them. So there's no depth class or anything like that. And there probably won't be because I don't like classes. But you can still create them when you need to. So how would you call Web APIs within your code? The Erlang module syntax, basically. So if you want to call document.getElement by ID, it's just colon document.getElement by ID. Same thing with console and window. Window, as you know, is like in browsers, it's the global thing. So you could just call alert. But you can't do that in ElixirScript because that alert wouldn't be defined within the scope. Anyway, what I'm getting at is if you find yourself in a situation where you don't have window, or you just don't know what the global object is called, you can use JS.global instead. So for instance, in a browser, it's window. In a web worker, the global is self, I think. And no, I think it's called global. So and there's, I don't know what the state of it is, but there is actually a spec for JavaScript to create an actual global function so that you can make it, you can have more elastic code. But so below that, I have examples of creating a new date, which is, that date is actually a JavaScript date. And then you can see you can do date.now, which you can use that syntax there because date is uppercase. And you can just call it. And I didn't realize this got pushed off. But I have an example down here. Let's see. Oh, yeah, we can't do that. Of calling fetch. So using the fetch API. And you can see you're using that then on it. And we have the anonymous functions, which you're using to handle what's returned. So some rules. So what you can do is use the Erlang module syntax to call functions. What you can't do is call functions that start with uppercase because you can't do it in Elixir. And you can't call functions that are not in the scope. So you can't just call alert. And it's not going to know what to do. So code sharing. You actually can share some code between Elixir and Elixir script as long as they support the same APIs. So obviously, Elixir script is going to be the least common denominator with that. Once again, you can't use dependencies yet in Elixir script. So you couldn't use dependencies with that. The bonus is that you can actually share code between Elixir and Javascript, which I've done before, where I had implemented the baked64 vlq module in Elixir. And I was able to use that with an Elixir. And also, I was able to call it from node in Javascript. So now I can show some examples. Let's see. The first one I'm going to show is using Web APIs. And I'll just actually start this. Is that easy to see, or should I zoom it up some more? OK. So this is actually a project which is based off of Elixir script boilerplate that I showed before. And I'm just going to go through the lines to show something. So we have our module here called app. We're requiring JS because we want to use, down here, we're using JS for a JS.new. One thing I didn't talk about is the Elixir script compiler will look for a couple of module attributes for a certain thing. So one of those is onJS load. And what that will do is, when it compiles this function, it will actually call that main first. So you can't really do something like this as far as I know in Elixir. But this is what it actually will do within the compiled ES module. And you see here I have a private function that's called log. And I am matching on the ID of that. So one of them is myDiv, one of them is mySpan. And they kind of do the same things. But it's just an example of using pattern matching. And before I was piping things to the Elixir compiler, you actually could use the actual name like HTML div element. But you can't do it anymore. So don't try. I have been thinking about maybe making something that will list out the web APIs and just build out modules for them, like a macro. But I haven't done that. And below we have our main, which we're getting the elements, so myDiv and mySpan. It's creating a list. And then it's taking that list and piping it through map. And it's calling log on both of those. And then for each of these, it's going through and creating a click handler. And then finally, all it's doing here is creating a date and then displaying it. And so now we will go, where is it? There we go. So it's just, come on, there we go. There's nothing really much to it. So it's showing the console output that is here and also here. And if I click here, you can see it's calling the log function again. And if I click there, it's showing, oh, the event. I'm sorry. So I happen to be showing the event on click. So that is, I think that's it for this example. The next one I want to show is, oh, using it will react. So what I've done here is create another project based on the Elixir script boilerplate where I have, I'm using macros that define react elements. And I'm doing that within this piece of code here, this module here. And here's another module attribute that Elixir script looks for, which is load only. So this is useful when there is something you want to do like at compile time, but Elixir script can't necessarily support some of the things. Like, for instance, an external reference, an external resource, and then creating the tags here. And basically, it can't support these things just yet. So it's a way of loading it in to use the macros, but it doesn't actually compile it to JavaScript. You can see we have a using statement here where we're actually importing and react and react dom, and then we're importing in the macros that are created here. Now, some of this code might actually look somewhat familiar if anybody's read the metaprogramming Elixir book by Chris McCallard. That's kind of where I got the example from. And so here, we're calling this using here. So we're using react.rui. And I'll just get to this point real quick. So here is our view. And you can see we have a div, which is actually creating the div element within react. We have our do block. And in here, we can call with my form, which is a function that creates a form with inputs. So we can actually create view functions. And here, we have a field, which is also a function that creates a div. And what I try to do here is kind of model the model view update that Elmas is known for. So we have our initial state of a name and email, which are blank. The view, which I just showed before, is just a div with I can actually show it. Yeah. It's just a div with some inputs. And I can type in this. And it'll just copy what's been written into here. And so the view takes in the model. And the model has, I mean, the view has event handlers, which we're calling here, we're calling update, which takes in the event, which is the first argument. And then, basically, the message or the attribute you want to change. And with an update, we're using an agent to, let's go back to the beginning, but we're using an agent here. And we're getting that, and then we're updating the state of the agent based on the message. And to get back to the beginning, here, we're using agent to start and giving it the initial state. And we're using the name, I guess, the model for it. And then we're calling render right away. And then we're going through, and for each render, it gets the model from the agent. It pipes that to the view, which then pipes that to react.render so that the view is updated. And that's pretty much it for that example. The next one I'll show is using it within a Phoenix project. So let's see, too much MPO. So I'll go to the mix file first. As you can see here, we have ElixirScript as our dependency. We have added it to our compilers. We have our ElixirScript configuration right here. So we're looking in WebStatic EXJS, and then LibShared, and then it's outputting to WebStatic JS build. So we're kind of hijacking the Bruntz pipeline a little bit so that whenever we update our ElixirScript code, it goes into a place where Bruntz can see it so that it can finish off the rest of it. But we do have a, and I didn't talk about this, but we do have a ElixirScript.hobot command. So we're adding this here to our watchers. So it's this mixElixirScript.watch. Our main ElixirScript code is in here. We're using that React UI thing I showed before again. This is our main, which is using that React UI to build up the Todo app. So this is the Todo MVC. There it is. Application that you might have seen before. We have our data module here. We don't know what to do with that data, which we'll go and call the Phoenix API using window.fetch and doing certain things. And most of what's happening, actually, the updating is handled by list, which we'll get the list of to-dos from Phoenix, and then add those, and then call main update, which actually goes and updates the view. Yeah. So Todo.model.todo is actually here in libshared, which is just a struct with a title completed in ID. And we don't have, we're not using Ecto here or any database. We're using an agent, basically, to store the state. And you can see we're also using Todo.model.todo here. And this is on the server side. So it's using the same struct on both sides. And I can show off the Todo controller, but it's not really much here. And so we have our Todo MVC app. So I don't know. Speak at lomestar, elixir, go of demos, roadmap, oops. What do I always misspell that? And oh, questions. And so this talk is pretty much almost over. So we can cross that out. And it's just getting the state back from the agent on the side, so you can refresh it. And as long as you don't restart it, it'll just stay there. That was the last demo, so we can cross that off. And we can go back to the slides. I don't know how to. So in the roadmap, get production ready. I think a lot of people, some people have asked me, is a production ready? My answer is always, if somebody's using it in production right now, I'm going to have a heart attack. More documentation and better usability, which are definitely important to me. Dependency resolution, I think just those three right there, more documentation, better usability, and dependency resolution will take things to a higher level. And add it more at the standard library, obviously. Source maps, those are hard. So yeah, those are hard. Private macros, stable processes. And the rest of them have question marks, because I don't know. So single file output, I do like the way they elm just creates like just a single file. And I've been back and forth on that. And there are a couple of other tasks that would need to be taken care of before that would be something that we could do. But it's still on the table. Reader conditional, so I don't know if anybody, is anybody here familiar with Closure and Closure Script? All right. So one of the features that landed in Closure maybe a couple of years ago was our reader conditioners, I think it's called, where depending on, depending on what environment you're in, you can run different code. That'd be kind of cool if you can do that with Elixir and Elixir Script. WebAssembly, so this project, WebAssembly might be out of the scope of this project, but it'd be cool if somebody like basically made it so that Erlang and OTP can compile to WebAssembly so that this project is obsolete. That'd be nice. OTP, we'll see what happens with that, and compile from Beam. So another project a week ago, just as an experiment, to get the Erlang abstract format from Beam and then compile it to JavaScript. And that might be, it's still an experiment, but it might be a better way to handle things because basically things like private macros and OTP, as far as I can, as far as I know, those kind of issues would just go away. And then everybody in the Beam community could convert their code to JavaScript. Questions?