How I Like to Write JavaScript

Rate this content

I love writing JavaScript. It feels lightweight, free-form, and flexible--all qualities that boost creativity and invite me to practice new and interesting techniques. Over time, I've developed lots of patterns and principles that help me day to day. In this talk, I'll show you a handful of them and then we'll look at how I apply them inside the AlpineJS codebase itself. It's gonna be a good time!

26 min
05 Jun, 2023

AI Generated Video Summary

Caleb Porzio introduces Alpine JS, a JavaScript framework, and demonstrates the process of creating a scrappy version of AlpineJS and refactoring it. The Talk covers topics such as creating a Dom Walker, evaluating expressions, using mutation observers, and refactoring the code. It also discusses techniques like inverting conditionals, using callbacks, and parameter currying. The Talk emphasizes the importance of abstraction, handler extraction, and a declarative approach in software development.

1. Introduction to Alpine JS

Short description:

Hey, my name is Caleb Porzio. I made a JavaScript framework called Alpine JS. We're going to create a scrappy version of AlpineJS, make a mess, then refactor it using techniques from Alpine.

Hey, my name is Caleb Porzio. I made a JavaScript framework called Alpine JS. And when I first started AlpineJS, I was by no means a killer JavaScript developer, but it's been a few years. I've rewritten the code base a few times, and now I have a bunch of opinions that I think help me make more maintainable code bases that I actually want to work in.

So we're going to create this tiny scrappy version of AlpineJS today, and we're going to basically make a mess doing it, then we'll walk it back and refactor it using some of the techniques that I've used inside Alpine. So let's do it.

2. Creating the Dom Walker and Handling Flame Click

Short description:

Here is a button on a page with a script tag with nothing in it. We're going to create a little playground. Instead of using Alpine's exon click, we'll use flame click and write JavaScript inside it. Let's create a Dom Walker script to look for flame click attributes and initialize them. We'll check if an element has the flame click attribute and get its contents.

Here is a button on a page with a script tag with nothing in it. This is going to be our little playground. And the framework we're going to write is, I don't know if you've seen Alpine, but with Alpine, you can add things like click listeners directly to buttons by adding attributes directly in the HTML, like exon click. Well, instead of that, we're going to do flame click, and then we can write any JavaScript in here. So let's write something like so hot.

Okay. And now if we load this in the browser, nothing is going to happen. We have this button with click alert. So hot, we click it and nothing happens because we haven't written any JavaScript for it. So let's do that. So the first thing I would do is create a little Dom Walker, a little script that'll walk through every element on the page and give us an opportunity to look for things like flame click and actually initialize them. So let's write a Dom Walker. And with the magic of snippets, you don't have to sit here and watch me write a little Tom Walker. So here's the Walker script. And this is the point where we have this little variable called L. Which every iteration in this while loop is just going to walk the next node. So let's just console log out L and refresh the page and make sure that it works. If we look at the console, here it is. We have button, click me. Now we have three buttons on the page. Let's refresh, make those three. And it's going to, it's going to walk through all those three. If we had a button nested inside of a div, it would walk that div as well. And then the button inside of it. Okay, great. So we have our little Dom Walker. Now in this part, we can do stuff with every element. And in our case, we want to check for the existence of this flame click attributes, we'll say if L dot has attribute flame, click, then let expression equal L dot get attribute flame click. So this is going to get the contents of that attribute. Okay.

3. Evaluating Expressions and Mutation Observers

Short description:

And this expression, let's just log out this expression, so we can see that it worked. We want to actually listen for a click event and then evaluate it. Now we're almost there. We're just going to add one more piece of real world complexity to this mess. That's going to be a mutation observer. In Alpine, you can actually change or remove these attributes without reloading the page and Alpine will pick up those changes. So let's write some mutation observer code that allows us to hook in to actually removing that attribute. What do we want to do when the attribute has been removed? Well, we want to remove the event listener that we just added above. So let's do that. Now we have add event listener.

And this expression, let's just log out this expression, so we can see that it worked. Here we have alert so hot. And now if we want to evaluate this, there's this little dirty function. You're not really supposed to use, but we're using it for this talk called where it'll actually evaluate a string as JavaScript code.

So if we refresh it evaluates alert, so hot, but we don't want that. We want to actually listen for a click event and then evaluate it. So let's do that. L dot add event listener click. And now we can put a little function in here. Let's do that. All right, refresh. And now it's not going to alert until I click great. That worked now we're almost there.

We're just going to add one more piece of real world complexity to this mess. And that's going to be a mutation observer. So in JavaScript in your browser, there's an API called mutation observer that you can use to observe mutations to the HTML. So in Alpine, you can actually change or remove these attributes without reloading the page and Alpine will pick up those changes. If you removed a click listener in Alpine, it'll actually remove the click listener from the button where I just removed the click listener in DevTools and now I click it and it didn't actually remove it. So let's write some mutation observer code that allows us to hook in to actually removing that attribute. So let's do that. All right. So again, I'm not going to make you watch me right at all, but we knew up a mutation observer and we specify a few things like an attributes filter and that we're only observing attributes, mutations, and then I'll just alert removed right from here, just to show you that, okay, we click that works. And now if I go ahead and I actually remove this attribute, we've hooked into that point in time, and we can actually run code when the attribute has been removed. So what do we want to do when the attribute has been removed? Well, we want to remove the event listener that we just added above. So let's do that. I'll remove event listener. And when you're removing event listeners, you get the element, you specified the event name, and then you need a reference to the actual handler function that was the event listener in the first place. So we need to pull this up. Let's say let handler equals eval expression. All right, now we have add event listener.

4. Refactoring and Designing the Code

Short description:

And now we can remove that event listener when the attribute has been removed. This is everything we need to make our little MVP, a little JavaScript framework. So let's start refactoring and talk about my values as a programmer. The first thing I usually do when I go to refactor a code base is start at the beginning. There's a lot of visual noise about Dom tree walking that isn't necessary for understanding everything. Let's write the code we want to exist: walk pass in an element, like document up body, and a callback where we get the current element as we're doing that Dom walking. And this is all we need to read the code.

And now we can remove that event listener when the attribute has been removed. All right. Click so hot. Now, if we go in here and we remove this attribute, we click, and now we're unable to see that, that alert because the event listener has been removed.

So this is great. This is everything we need to make our little MVP, a little JavaScript framework. We'll call it hot JS. And yeah, so this is a mess. This is all the codes you would write if you were just getting the job done. So the rest of this talk is going to be us refactoring this code back to something that is more sensible and more maintainable. Because right now, if we wanted to add more directives, like flame, click, we were like flame text or something. We would have to duplicate everything. And there, you know, it just would be a complete nasty mess.

So let's start refactoring and talk about my values as a programmer. These are a lot of my opinions. This is like the Caleb Horzio style guide to writing JavaScript, a lot of my opinions and how I approach refactoring. So the first thing that I usually do when I go to refactor a code base is start at the beginning. Cause a lot of times it's intimidating. Like where do you start? Everything's a mess. And usually it's like, I just walk through the code until I find the first imperfect thing or the first thing that I don't love and then just start there. So if we do that, well, it's not hard. Like right away, I'm like, okay, there's a lot of kind of visual noise about like Dom tree walking. That isn't necessary for understanding everything. Like we can easily extract that away. And I also don't love that there's, uh, this current variable up here and then this temporary element, and then there's more tree Walker code down here. So there's kind of an obvious extraction here that I, that I want to make, and let's design by wishful thinking. That's a little Adam Wathen quote, where when you're going to refactor, you basically write the code that you want to exist and then make it happen. So let's write the code we want to exist. It'd be great to just say walk pass in an element, like document up body, the body tag of this page, and then a callback where we get the current element as we're doing that Dom walking. And this is all we need to read the code.

5. Extracting Code into a Function

Short description:

Like if we're writing this code for consumption, this is all we need. So I have a utils.js file where we're going to store all these functions. Let's create a function called walk that accepts the root element and a callback. We can extract the code surrounding the callback into the walk function. This is a basic extraction where you extract the code into a function and accept a callback. We have walk L and everything else should work fine. Let's run this and make sure it worked. Cannot read properties of undefined has attribute because we're not passing in the element into the callback. Everything works great. Let's continue until we find something that's not perfect. This is perfect. This is perfect. Here's a big if statement, if L dot has attribute.

Like if we're writing this code for consumption, this is all we need. All this stuff is implementation details.

Okay. So I have a utils.js file where we're going to store all these functions. Let's create a function. We're going to call it, walk, and we accept the root element and then the actual Walker, which we'll just call callback. And then we can extract all this code here. The top half pop here, run that callback, which is going to be all of this code that will pass in. So let's pull this up right here. Okay. And then this bottom chunk, we'll pull that out in here. Okay. So again, this is a pretty basic extraction where you just extract the code surrounding something into a function and accept a callback for the inside of what that code was wrapping. So we have walk L and everything else should work pretty much fine. Uh, this is the only bit we need to change here. And we'll also need to import this into our file here. And let's run this and make sure that it worked. It did not work. Cannot read properties of undefined has attribute. Because we're not passing in the element into the callback here. Say both files refresh. And there we go. Everything works great. All right. Let's start from the top again until we find something that's not perfect. This is perfect. This is perfect. Okay. Here's a big, if statement, if L dot has attribute.

6. Inverting Conditionals and Using Guard Clauses

Short description:

When encountering a big conditional, I like to invert the conditional and return early using guard clauses. This makes the code more readable and avoids excessive nesting.

And when I come across something that doesn't work, I'm going to If L dot has attribute. And when I come across an if statement like this, there's a few things that go on in my head. In general, conditionals, add to the complexity you need to store in your head when you're reading your own programs, because it's like all of this code only works when there is. An attribute on the element called flame click. So I need to keep that knowledge in my head that all this code, we need to be inside of that conditional, um, which, you know, as you read, it's just like adds to that load. So one little thing that I like to, that I like a little technique that I like, um, when I have a, you know, a big conditional is invert the conditional and return early. So in this case, we can say if not L has attribute, then return. And now we can basically run the rest of the code with knowing that we have that attribute, but without that extra level of indentation. And in this scenario, it's not the best refactoring, but I just want to note that I use these, they're called guard clauses. I use them all the time. It's like, get the exceptional cases out up at the top so that you can write the code at the happy path. And if you have like four levels of nesting and you turn those into four guard clauses, that is so much more readable than various, you know, levels of nesting throughout the function. All right. So that's one little technique.

7. Using Callbacks and Avoiding Null Values

Short description:

Instead of using an if statement, use a callback to receive a value. Create a function called getAttribute to extract the expression. Avoid potential null values by using a receiver callback. This ensures that the expression exists and avoids errors. Continue with the code implementation.

Another one that I like is instead of using an if statement use a callback to receive a value. So let's just, let's extract this, this L dot get attribute into a little function called get attribute. Where we pass in the element. And the name of the attribute that we want to get, which is flame click. Okay. And let's just write that function and then we'll talk as we go. Get attribute element and name. Okay. And something like this, we'll pull this into here and we'll call this name. And now the first thing you might think to do is just return this expression. And so you have something like let expression equals kind of thing, but then you're back to where you started. You have to say, if not expression, and that's a null value, that's a potentially null value. And when you're working with code, as you know, like. Values that can potentially be null are death to your programs because it's so hard to figure out that the very few cases or many cases where they are null and then you get all those errors, like trying to, you know, treat null as a function or call property on null or whatever. So what I would rather do in this scenario is create a receiver callback. So instead of setting a variable called expression, what if we create this little receiver callback where we get expression as the first parameter? Now, everything inside here has access to expression, but we're always guaranteed that expression exists. If it doesn't, this callback just won't run. So let's turn that function into a receiver function. So if not, has the name we're looking for return early, otherwise, let's add this little parameter here, this receive, otherwise, instead of returning it, let's receive that value. All right. Make sure this works. It's not going to work because we didn't import this. Now refresh and everything works. Great. Alright. Let's keep going.

8. Abstraction and Handler Extraction

Short description:

We create a function called when attribute is removed to handle the abstraction of the mutation observer. We add the attribute to the page and ensure it works. The code is now more readable and tidier. We extract the handler variable into a separate function called on.

So we have our walk function. We have our receiver get attribute. That's pretty good. We have this add event listener, and we're going to extract this in a minute. But the next really imperfect thing that I see is just that there's an easy abstraction here. This mutation observer, there's code above and there's code below. So it makes it a really quick function abstraction. So let's do that. We're going to create a function called when attribute is removed. And then we'll pass in the element, the name of the attribute, and then a callback to run when that attribute is removed. So we can basically just take the code like this, run the callback and then the rest of the code below it, we can put below that.

Okay, perfect. So now we have one attribute is removed and we can add that to the page here. One attribute is removed L and then this flame click. Okay. And then our callback here. Okay. So that looks pretty good. Let's make sure that it works. Okay. That works. And now if we remove this attribute, the click has been removed. All right. So this is much more readable already. If we're just like even just squinting at it, giving the squint test, you can see that everything is much tidier. We have a lot of these basic functions extracted the last one, the last imperfect thing while we're walking down is that we have to set this handler variable so that we can both add it as an event listener and then remove it as an event listener later on. And this isn't so bad, but pretend that there's like a hundred lines of code between here and here. And that just doesn't feel great to have this temporary variable being referenced in such different parts of the code base and to extract it. Like, like if we're going to make a little function, so let's do that. Let's make a little function called on where you pass in the element, the event name that you want, and then the handler, and then let's do that.

9. Refactoring the Event Listener

Short description:

So let's say on L click and then handler, you know, that's fine. But this remove event listener, how can we make this bit part of this abstraction? A technique I like to use is to return the removal of the event listener as a function from the on handler. This allows for cleaner code and avoids the need for a separate temporary variable. Let's import on and continue with the refactoring process.

So let's say on L click and then handler, you know, that's fine. Okay. But this remove event listener, how can we make this bit part of this abstraction, this on event listener and technique that I like to use when you're trying to extract something from two different layers of nesting. So before so far, we've just extracted things on a single level of conditionals or functions or whatever. Just a single level of indentation. This is something we want to extract both here and here. So it gets a little dicey or we can't just copy and paste stuff into here. So a technique that I like to use for functions that do something like this on, it actually adds an event listener. Often there's like a tear down or some sort of cleanup procedure for that procedure. Like every action has an opposite reaction. Like this action, this add event listener. There also is the removal of that event listener that's related to adding it. And to keep that in this function, we can return it as a function. So check this out. If we take this, I'll remove event listener and let's actually duplicate this and say, remove event listener like this, now we can return it from this on handler, and then we don't need to have this handler as a separate temporary variable we can see let off on L click of L expression, and then down here we can just run off. So this is something that I love, and there's so many times where this is useful, um, often, you know, when you're registering event listeners or pushing on to some kind of stack, you might want to return some method or function to remove from that stack or bus to cache or it's just like a really handy pattern that I really like return a cleanup procedure from a function that that has a cleanup procedure. So, okay, so great. So I'm really happy with this. Let's import on and make sure everything works. Okay. So this is like step one in the refactoring. I think we've got to a point where this looks pretty good, but it's really just a more readable version of what we started with, it's the same structure. We're walking the Dom. We're getting an attribute. We're listening for a click. And then when the attribute is removed, we're pulling that click off. There's so many structural changes we can still make. So let's keep walking through those.

10. Using Context and Parameter Currying

Short description:

The get attribute and when attribute is removed functions have similar parameters. To reduce duplication and improve readability, we can modify get attribute to return a function called on remove. This new function will accept a callback and internally call when attribute is removed. By utilizing the context from get attribute, we can create a function that only requires the callback. This technique, known as parameter currying, simplifies the code and makes use of context. Alternatively, we can use the bind function to achieve the same result.

Okay. So the first one we're going to do, we have get attribute and when attribute is removed, they have basically the same parameters that you send them. And at this level of code, like this very outside in part, where we're just walking the Dom getting attribute. I feel like we don't need to have all this knowledge. I feel like we don't need to have, to use, get attribute. And when attribute is removed, it feels like a lot of duplication. What if instead this get attribute returned us a function called on remove past it in the parameter of our little receiver function here that we could just use instead. And we wouldn't have to pass all of these parameters in, I think it would clean this up a lot.

So let's do that inside, get attribute, instead of just receiving the expression, let's receive a function called on remove and we'll just accept a callback like this. And then inside here, we can actually call this when attribute is removed just like this. So it'll accept a callback. And we'll just forward that to when attribute is removed and we already have element and we already have name. Does that make sense? Like we already have this context from this get attribute call. So we can just create a little function that only needs the callback and calls the one attributes removed. So now that we have on remove, we can just do this. On remove. And that's much nicer. And we can clean it up even more and just return that function just like that. So I think that's a lot cleaner. Um, this is a technique that I use a lot where it's like, if you have context, use it, so in this case we have the context we can use it and what we're actually doing here, this is called, uh, parameter currying or whatever. I don't know. I don't know like the technical terms, but basically when you take a function and you pre fill out a few parameters and then pass that new function around that only needs a single parameter or, you know, whatever, it doesn't need all the parameters. It's called currying. And there's a few different ways to do it in JavaScript. This is the most literal, but we could have done something like this. Let on remove equals when attribute is removed dot bind. So you can use this JavaScript function called bind where you pass into this context, and then you prefill in parameters. So in our case, L and name, and then it'll return to you a function that already has these parameters filled in. And then you could just do something like on remove. Okay.

11. Refactoring to a Declarative Approach

Short description:

This code is very imperative. Let's structurally change it to a more declarative approach by registering directives and using a boot method. We'll create a new file called directives.js to store all the functions related to directives. This follows the single file principle. Instead of classes, we use modules in JavaScript.

So I think that's an improvement and we could go as far as, you know, directly pasting this in line, cause it's going to return it's off function. But I feel like that's a little too much. I feel like that's just one step beyond what we need to do. All right. And for our big final refactor move, again, this is all just kind of a nicer way of writing what we had written before let's structurally change it right now, this code is very imperative. Um, meaning it's just step-by-step it's like walk the DOM tree for every iteration, check for an attribute, get that attribute, register a listener. You know, we're maintain ability-wise that's not always the most maintainable. So if you think about what's the code that I want to maintain, if this is my little framework, what's the code that if I needed to add a new attribute, like flame text, I would have to copy all this, maybe this would get huge. And it's all inside this walker. It's like, what if I just went to fantasy land and wrote what I want? Well, let's, instead of calling it attributes, let's call it directive. So what if I said directive? And then I could just say something like flame click, and then let's just take this whole callback right here. Okay. And, and these even, like these are all individual parameters being passed. I would rather turn this into an object of things being passed in so that I could just pick and choose which things I want to like, oh, I only want the element. Or I only want the on remove, or I only want the expression. So yeah, this is designed by wishful thinking. To me, this is like. A much better way to do it. So register the directive, sort of declare the directives. This is a more declarative approach to clear the directives up front, and now inside of this walker have some method like boot or something like boot element. And then this directive function registers a directive in a pile of directives, and then boot goes through all those directives and actually boots them. So let's write that we're going to break out of our utils right now. And we're going to create a new file called directives dot JS. This is another thing I like to do. Is it's called, I call it the single file principle is when you're writing functions that belong together, you put them in a single file. So like anything having to do with directives goes in a single file. That way you always know where to find it. Um, if you're used to object oriented programming, like PHP or Python or Python or Java or something, you're used to writing classes like this. Well, I don't really use classes in JavaScript. I more use these modules, these files, where instead of methods, I have functions.

12. Exporting and Booting Directives

Short description:

And if I export the function, it's a public function. If I don't, it's just a private function used within the file. We can add properties by writing variables at the top. Let's export the function call directive, where we pass in the name of the directive and a callback for initialization. We need to store the directives in an array called 'directives' and push an object with the name and initialize function. The 'boot' function will iterate through the directives and execute the code for each directive, passing the attribute, element, and initialize function.

And if I export the function, it's a public function. If I don't, it's just a private function used within the file. And I can add what's the equivalent of properties by just writing variables up at the top. And you'll see what I mean. So let's export this function call directive, where we pass in the name of the directive and then a callback that handles the initialization. We could call this maybe initialize so that it is more readable or something.

Okay. And now here we're not, we don't have the current elements, so we have to kind of change the structure. We need to store all these directives so that we can boot them later. So let's create a little property called let directives equals. And it's just an array. And then here we'll say directives push, and let's push on a little object with the name and then this initialize function. Okay. So when the code runs, when this directive runs, it's just going to basically hold these over for us in this variable, this property called directives until we use them down in boot. So let's create that boot function. All right. And boot accepts an element.

And now boot is going to go through those directives. So directives.for each, and this will be a directive, an individual one. And now this individual directive, we can take this code that we had before. And now we would actually run it like for this directive, we'll get the attribute. We already have the element. We'll say directive, dot name. And in this case, we could just pass in directive dot initialize, and maybe we'll do that just for now to make sure that it all works, but actually we're not going to do that. Instead of passing it, initialize, we're going to pass in our own callback here. And then call this initialize function. And remember, initialize is what we pass in to the directive and initialize expects this object of parameters. So let's just paste that in here. Okay. So we have element, we need expression.

13. Inverting Flow and Writing Readable Code

Short description:

Remember, we've inverted the flow by hoisting up the declarations and using a boot function for the loop. There are many more optimizations and refactors that can be done, but for now, let's keep it at this level. This structure is how Alpine is written, making it more readable. I hope you've learned something about refactoring JavaScript into well-named functions.

Remember, get attribute returns, expression, and it returns on remove. Okay. So let's import those from our new directives.js and import boot. And now this, we need to import get attribute from utils. And let's see if this works. Initialize is not defined. Okay. So we have initialize, but it's actually a property of our directive, this directive that we pass in. So directive dot initialize. And there we go. Everything still works. And to me, we've kind of inverted the flow here. Instead of directly looping through something and doing something or doing a handful of things on every loop, we've hoisted up those things that we're doing into declarations at the top. And now we're, when we do the actual loop, it's just this little boot function that goes through those things that we declared. So hopefully this makes sense to you. I know that, you know, having to kind of look at this, it doesn't like pass the squint test very easily. But I know looking at this can be a little bit overwhelming. But I think you get the idea. But I think you get the idea. So there are so many more optimizations we could make this on method. We could actually provide directly here and fill in some of this context, like we did before with that currying. There's just so much more we could do. There's so many more refactors I'd like to make, but we're just going to keep it at this level for now. And hopefully this gave you a little bit of perspective on how I like to write things and how I like to structure code and just so you know, this is very much how Alpine is actually written. There is a file in Alpine's core called directives that has a function called directive that stores all the handlers in this object and then you can initialize them later. Everything I've shown you is basically how the core of Alpine is written itself that I think makes it a lot more readable and yeah. So hopefully you picked up a nugget or two about refactoring JavaScript into nicely named functions. Yeah. Thanks.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Summit Remote Edition 2021React Summit Remote Edition 2021
33 min
Building Better Websites with Remix
Remix is a new web framework from the creators of React Router that helps you build better, faster websites through a solid understanding of web fundamentals. Remix takes care of the heavy lifting like server rendering, code splitting, prefetching, and navigation and leaves you with the fun part: building something awesome!
Remix Conf Europe 2022Remix Conf Europe 2022
23 min
Scaling Up with Remix and Micro Frontends
Do you have a large product built by many teams? Are you struggling to release often? Did your frontend turn into a massive unmaintainable monolith? If, like me, you’ve answered yes to any of those questions, this talk is for you! I’ll show you exactly how you can build a micro frontend architecture with Remix to solve those challenges.
React Summit 2023React Summit 2023
32 min
Speeding Up Your React App With Less JavaScript
Too much JavaScript is getting you down? New frameworks promising no JavaScript look interesting, but you have an existing React application to maintain. What if Qwik React is your answer for faster applications startup and better user experience? Qwik React allows you to easily turn your React application into a collection of islands, which can be SSRed and delayed hydrated, and in some instances, hydration skipped altogether. And all of this in an incremental way without a rewrite.
JSNation 2022JSNation 2022
28 min
Full Stack Documentation
Interactive web-based tutorials have become a staple of front end frameworks, and it's easy to see why — developers love being able to try out new tools without the hassle of installing packages or cloning repos.But in the age of full stack meta-frameworks like Next, Remix and SvelteKit, these tutorials only go so far. In this talk, we'll look at how we on the Svelte team are using cutting edge web technology to rethink how we teach each other the tools of our trade.
Remix Conf Europe 2022Remix Conf Europe 2022
37 min
Full Stack Components
Remix is a web framework that gives you the simple mental model of a Multi-Page App (MPA) but the power and capabilities of a Single-Page App (SPA). One of the big challenges of SPAs is network management resulting in a great deal of indirection and buggy code. This is especially noticeable in application state which Remix completely eliminates, but it's also an issue in individual components that communicate with a single-purpose backend endpoint (like a combobox search for example).
In this talk, Kent will demonstrate how Remix enables you to build complex UI components that are connected to a backend in the simplest and most powerful way you've ever seen. Leaving you time to chill with your family or whatever else you do for fun.

Workshops on related topic

JSNation 2023JSNation 2023
170 min
Building WebApps That Light Up the Internet with QwikCity
Featured WorkshopFree
Building instant-on web applications at scale have been elusive. Real-world sites need tracking, analytics, and complex user interfaces and interactions. We always start with the best intentions but end up with a less-than-ideal site.
QwikCity is a new meta-framework that allows you to build large-scale applications with constant startup-up performance. We will look at how to build a QwikCity application and what makes it unique. The workshop will show you how to set up a QwikCitp project. How routing works with layout. The demo application will fetch data and present it to the user in an editable form. And finally, how one can use authentication. All of the basic parts for any large-scale applications.
Along the way, we will also look at what makes Qwik unique, and how resumability enables constant startup performance no matter the application complexity.
React Summit 2023React Summit 2023
106 min
Back to the Roots With Remix
Featured Workshop
The modern web would be different without rich client-side applications supported by powerful frameworks: React, Angular, Vue, Lit, and many others. These frameworks rely on client-side JavaScript, which is their core. However, there are other approaches to rendering. One of them (quite old, by the way) is server-side rendering entirely without JavaScript. Let's find out if this is a good idea and how Remix can help us with it?
Prerequisites- Good understanding of JavaScript or TypeScript- It would help to have experience with React, Redux, Node.js and writing FrontEnd and BackEnd applications- Preinstall Node.js, npm- We prefer to use VSCode, but also cloud IDEs such as codesandbox (other IDEs are also ok)
React Day Berlin 2022React Day Berlin 2022
86 min
Using CodeMirror to Build a JavaScript Editor with Linting and AutoComplete
Using a library might seem easy at first glance, but how do you choose the right library? How do you upgrade an existing one? And how do you wade through the documentation to find what you want?
In this workshop, we’ll discuss all these finer points while going through a general example of building a code editor using CodeMirror in React. All while sharing some of the nuances our team learned about using this library and some problems we encountered.
TestJS Summit - January, 2021TestJS Summit - January, 2021
173 min
Testing Web Applications Using Cypress
This workshop will teach you the basics of writing useful end-to-end tests using Cypress Test Runner.
We will cover writing tests, covering every application feature, structuring tests, intercepting network requests, and setting up the backend data.
Anyone who knows JavaScript programming language and has NPM installed would be able to follow along.
Node Congress 2023Node Congress 2023
63 min
0 to Auth in an Hour Using NodeJS SDK
Passwordless authentication may seem complex, but it is simple to add it to any app using the right tool.
We will enhance a full-stack JS application (Node.JS backend + React frontend) to authenticate users with OAuth (social login) and One Time Passwords (email), including:- User authentication - Managing user interactions, returning session / refresh JWTs- Session management and validation - Storing the session for subsequent client requests, validating / refreshing sessions
At the end of the workshop, we will also touch on another approach to code authentication using frontend Descope Flows (drag-and-drop workflows), while keeping only session validation in the backend. With this, we will also show how easy it is to enable biometrics and other passwordless authentication methods.
Table of contents- A quick intro to core authentication concepts- Coding- Why passwordless matters
Prerequisites- IDE for your choice- Node 18 or higher
React Summit US 2023React Summit US 2023
96 min
Build a powerful DataGrid in few hours with Ag Grid
Does your React app need to efficiently display lots (and lots) of data in a grid? Do your users want to be able to search, sort, filter, and edit data? AG Grid is the best JavaScript grid in the world and is packed with features, highly performant, and extensible. In this workshop, you’ll learn how to get started with AG Grid, how we can enable sorting and filtering of data in the grid, cell rendering, and more. You will walk away from this free 3-hour workshop equipped with the knowledge for implementing AG Grid into your React application.
We all know that rolling our own grid solution is not easy, and let's be honest, is not something that we should be working on. We are focused on building a product and driving forward innovation. In this workshop, you'll see just how easy it is to get started with AG Grid.
Prerequisites: Basic React and JavaScript
Workshop level: Beginner