1. Introduction to Full Stack Components
I'm excited about RemixConf EU and speaking about full stack components. I'm working on Epicweb.dev, my full-time thing now. This talk is a demo of components that include UI and server-side code. We'll be talking about Remix, our favorite full stack framework.
What is up Remix Friends? I'm so excited about RemixConf EU and I'm really excited to be speaking with you all about full stack components, so let's go talk about taking colocation to the next level.
So one thing that I wanted to talk about really quickly is I'm working on Epicweb.dev, if you haven't seen that yet definitely give it a look. It's my full-time thing now, it's awesome. And all my slides and everything for this talk are on my GitHub so you can take a look at that there.
So this talk is going to be a demo of components that include both the UI code as well as a server side code and we're going to be doing a lot of coding and so yeah, buckle up. We're going to be talking about Remix, of course our favorite UI framework. Well full stack framework, not just UI and that's part of what this talk is all about.
2. Exploring Remix Features
Remix allows us to marry the backend and the UI in the same file. We can build UIs that aren't URL-centric, like the Twitter like button. We're going to demonstrate a combo box that does a search. We have an app running with a route for fetching customers. We can export a component that consumes the loader. We're using the Downshift library for the combo box experience.
So Remix allowed us to marry the backend and the UI in a way that has never been done before with the loader and action and our UI all in the same file. And this is a pretty simple demonstration of how that works from a route perspective. So we have our projects route and here we have our loader to load those projects and we've got our form to add new projects and the backend piece for that mutation.
But sometimes we have UIs that aren't like so URL centric, for example the Twitter like button, whenever I click on that like button that's not going to take me somewhere else, I don't only render that on a special page that has a specific route, I render the like button for every single one of the tweets that are on the page and so that doesn't really work very well as something that you'd like stick in a loader or an action for a particular route necessarily and here's another example of a combo box that's doing a search and this is the thing we're actually going to be demonstrating today.
So, I've got an implementation of this app right here, we're not rendering the combo box yet because we are going to build it together and connect it to the backend and it's going to be sweet. So, that's it. It's demo time. So, the first thing is we've got this app up and running right here, we're in the 01.b4 version of the app and we're in the app directory under routes and under this resources directory is where we'll find the customers. So, we're going to have this route for slash resources slash customers and that's going to be the API route that we're going to be using to go get a bunch of customers.
Now, one really cool thing about Remix is that if you don't have a default export of your module, the Remix will treat your module like a resource. And so, what we mean by that specifically is I can say export an async function, whoops, a function, come on, there, called loader and here I'm going to return JSON and that JSON actually is going to come from Remix run node and we'll say hello world. And if I save that and come over here, I can go to resources, customers and I'm going to get hello world. Now, there's nothing special about the resources directory other than the fact that my editor seems to like giving that a special icon, but there's nothing special about this. We can call this whatever we want and it just so happens that the way I like my URL for this to work is to have a slash resources and that's it. So wherever we want that URL to be, that's where the file is going to be. So by having a loader export but no default export, this is just a regular request for like an API request. So with that in place, now we can build some UI that interacts directly with this loader that makes fetch requests. But what's really cool about Remix is that we can actually add a bunch of other exports to this as well. We can export const koala equals Kodi, like it doesn't matter. We can do anything we want to in here and Remix will just ignore it in its builds. So what that means is we can actually export a component in here that consumes this loader and that's exactly what we're going to do. And because I know you probably don't care to watch me write a bunch of JSX, I've actually written all the JSX stuff there. So here's our loader, it's just what we had before, but then we got a bunch of other JSX stuff in here that you, like I said, you probably don't care to watch me do all of that. So skipping over the JSX bit, the most important and interesting bit here is we're using this use combo box, which is a Downshift hook. Downshift is a library I built years ago when I was at PayPal, and it's for making this combo box experience for us. And all we need to do is provide it with the items and we can respond to input value changes as the user is typing. So that's perfect. That's exactly the two things that we need. And with that we're exporting this combo box, but we're still just a resource route. There's nothing special going on here.
3. Implementing Endpoint and Querying Customers
This is just hitting an endpoint and getting the response. We'll flesh out the loader and require authentication. We'll get the URL and query from the request. Search for customers using Prisma and SQLite. Send the matching customers in the response.
This is literally just hitting an endpoint and getting whatever the response that we sent back was. So let's do a couple of things with this endpoint, though. So we'll flesh out this loader.
So for one, I personally don't really want people to be able to hit this endpoint who are not authenticated. So we're going to say, Require User. And we'll pass the request. Now we get that request in our loader, of course, so we'll pass that request. We'll use LoaderArgs. There we go.
And with that, now, I can still make a request to this, but if I go incognito, I'm going to get redirected to the login. So that's nice. Remember, all of your loaders are basically API endpoints anyway. Anybody could curl that URL and get access to everything that you have at that URL. So you do need to protect your loader data, and this is how we're going to do this here.
So, the next thing is, I'm going to get the URL from the request.URL. Turn this into a URL object so I can get the query from URL search-params.get. And we'll just do full word query here. And we want the query to be either, in this case it's either a string or null. We'll go ahead and default that to a string. So it's always going to be a string. So now I can do search customers.
And this is implemented using Prisma and SQLite is how this is set up. But this search customers could be an implementation that makes a fetch request to another downstream service or like a Rails or PHP backend, or whatever. That part is not important. Just the fact that we have some mechanism for sending this query along to where we're going to actually query for the customers. So we'll pass this query along and we'll get our customers. These are the matching customers back. And then with that, we'll send that in our response. So now if I hit that, I'm not going to get anything. If I say, query S, then I'm still not going to get anything because I messed something up.
4. Implementing Search Customer Fetcher
This is the correct query. We're going to use URL search params. We forgot to await, but now we can get the customers and query for specific ones. The special sauce is our useFetcher, which connects us to the UI. We implement the Search Customer Fetcher with type safety.
So no, that is the correct query and query right here and query right there. Oh, this is not good. So we're going to URL search params. Oh, shoot. I'm going to have to start over. Oh, I know what it is. I'm not going to start over. I forgot to await. Silly me.
So now we're going to get the customers. There we go. Okay. So we've got all of our customers there, then we can query for specific ones. And we can just get an array of all the customers that match. So that's exactly what we're looking for for the API route.
Now here's the special sauce. This is what's going to actually connect us to the UI piece of this, is our useFetcher. So Cody the Koala, hello. Here's Cody. Cody is going to tell us we need to implement Fetcher here. So we're going to say Fetcher, or we'll call this Search Customer Fetcher. You can call it whatever you like. It really doesn't matter. And we'll say useFetcher right here. And then to get the data that this Fetcher is going to be interacting with to be fully typed, I'm going to say typeof loader. So there's my loader right there. I get type safety for my Search Customer Fetcher. And that Search Customer Fetcher is going to have a dataproperty on it. And if that dataproperty exists, it may not. Because on the initial render, we're not calling this loader right from the start.
5. Handling Undefined Data in TypeScript
We're calling it when the user is searching, right. If there is no data, then that's undefined. If there is, we'll have customers. So our customers will be an array. Now TypeScript is happy, and our selected customer has the correct type.
We're calling it when the user is searching, right. And so if there is no data, then that's going to be undefined. But if there is, then we're going to have customers. So we'll have data Elvis Operator Customers. And if that doesn't exist, then we'll have that, those customers be an empty array. And with just that change, now a TypeScript is a lot happier. Because this type definition right there, our customers is going to be an array of customers. And now this type is correct. And so our selected customer is going to have a correct type. And the type we passed along to use combo box.
6. Making the Fetch Request
We need to make a fetch request whenever the input value changes. Downshift provides an API for detecting these changes. The Search Customer Fetcher has options for making the request. We'll use the submit option, which makes it easier to serialize query params. We'll handle the case when the query is undefined by assigning an empty string.
So that's really cool to be able to have full type safety across the network for a component that's going to be used all over the application. Who knows where it's used? So the last piece of this is actually making the request. And for us to actually make this fetch request, we just want to make a request whenever the input value changes and downshift provides this API for us to know when the input value changes. And so what it will say is the Search Customer Fetcher. And there are a couple of options on here. We have .form, which we could use if this was an explicit submission that the user is clicking on a submit button. That's not the case for us. This is an imperative mutation or an imperative query that we need to make as a result of some other user interactions. So we can't use form. There's also load, which we can use to make a GET request with query params, but we have to serialize those ourselves. So I don't want to do load, I'm going to do submit just because this makes it a lot easier to serialize those query params. And actually, GitHub Copilot is pretty close here. This is complaining right here because the query can only be a string, it can't be assigned undefined, an input value on the changes that were given is optional. It may not be there. So we'll just add a, I forget what that syntax is called, coercion or something, something there. If int value is null or undefined, then we'll end up with an empty string.
7. Adding the Get Method and Rendering the Component
We implemented the method as a get, but it could be an action. The action URL is for the loader inside resources/customers.tsx. We can use this component anywhere in our application and it will stay connected to the loader. We'll use it in the sales invoices new route to choose a customer for a new invoice. Importing from the routes directory is usually not recommended, but this is an exception. The functionality currently works, and we can fix the spinner.
Now the last piece we need to add to this is we need a method of get, or lowercase get here. And that is the case because we have implemented this as a loader. Now we could actually implement this as an action and have our method be really anything but get, like a post or a put or something, but I'm happy with this being a get. And then, um, and like for query endpoints, that's typically it makes most sense to be a get, but yeah, you do you, however you want to.
The cool thing is that you don't have to jump into 30 different files or multiple repos to make this change, you can just one day decide, you know what, I want to do this as an action instead and just switch it right here in the same file, which I think is rad.
Okay. And then the last thing is the action. Now this action is the URL that is going to be hit with this query. And the URL is the URL for this loader, which we've already established is inside of resources, customers, TSX. And so we're going to say slash resources, slash customers. Okay. And that's it, we have finished this feature. And it totally works. But we need to actually render this component. And this is this is the pretty cool part. So like, so far, this kind of feels a little bit just like your typical remix route and everything because you've got your loader, you've got your type of loader, like everything feels very similar to what you're used to in building a remix route. But the cool part is that we can actually use this component in anywhere in our application and it will stay connected to this back in loader. So in particular, the part of the application we want to use it in is inside of our sales invoices new when we're creating a new invoice so we can choose which customer we want. And so if we come down here, we've already got Cody helping us out with the props that we need to pass and everything. So we've got our customer combo box, which we are going to be importing from routes, resources, customers. So typically, I don't recommend doing any imports from the routes directory. In general, I just think that is not a really safe way to do things. But this is one exception that I think is totally legit and it is totally awesome. So that's all that we're going to do in the customer combo box piece here on the new route. And with that in place, if I come back here and go create new invoice, then I've got my customer combo box. Now, we currently have this set to true, and we can fix that here in a second. But the cool thing is that this functionality currently totally works as I make changes and I can select customer and all of that stuff. So that's pretty rad. We've got a component that is connected to its backend and all in a single file. So the last thing I want to do is fix the spinner because that is bothering me.
8. Implementing Spinner and Backend Connection
The pending state is determined by the SearchCustomerFetcher.state. If the state is not idle, the spinner is shown. To avoid a flash of loading state, a delay is added using the useSpinDelay package. This ensures a smooth transition and provides a nice pending state for users. The component can be rendered throughout the app, connected to the backend. It can also be packaged as an npm package for easy integration with other projects.
And so if we come down here, we've got our show spinner, and our pending state is going to come from our fetcher. So we'll have our SearchCustomerFetcher.state. And the state can be idle, loading, or submitting. Pretty much if it's loading or submitting, we know that we're in a pending state. Normally, I just determine whether we're in a pending state by saying, is the state not idle? If it's not idle, then we're pending.
There is a subtle difference between submitting and loading, where loading is going to get some data, submitting is when the user is submitting data. But in our case, I think it's reasonable just to say if the state is not idle, then we can show the spinner.
So with that in place now, we can see that there's no loading state. But if you watch carefully, you might actually see a flash of loading state, and that is not awesome. So there are a couple options here. You can add a like a transition delay or something. But the problem is if the request takes like within 50 milliseconds of whatever transition delay you put in there, you're going to get a flash of loading state. It's really basically impossible to avoid without a little bit of extra help.
So basically what we need is to say don't show the loading state unless you know… well let's put a delay in because that does make sense. If it's within 100 milliseconds don't show any loading state at all. But if I do show any loading state, then we should keep the spinner hanging around even if it's finished. So keep the spinner hanging around for another like 300 milliseconds or something like that just so that we don't have a flash, because it's way better to show it for longer than you need it than to just show a flash of loading state. And there's a package built specifically to solve this problem. It's actually built for my website by Stefan Meyer who helped with implementing my website. And it's called useSpinDelay. And we'll pass that along there. It has some good defaults we'll just keep those. And with useSpinDelay from the spin delay module, now we're going to avoid that flash of loading state. And if we do have a slow 3G network, then we are going to get a nice pending state, which is exactly what our users would expect. So with that in place, we're solid. This is really, really great. You could render this component all over the app and be certain that it is connected to its backend. On top of this, you could actually also package this up in an npm package and then expose just a couple of things for people to go into the Remix config, add their routes option here, and they call into your things so that you can hook up the route for the API route. And then they can just start using your component and it's all magically connected to the backend, which that's pretty interesting. And I'd love to see somebody try to do that.
9. Wrapping Up and Resource Routes
Remix allows us to create resource routes by simply having a route with no default export. We can export anything we like as long as it's not a default export. This co-location of code makes it easier for us to maintain the software in the long term.
So with all of that said, let me wrap up with a last couple of thoughts. So in review, Remix allows us to create resource routes by simply having a route with no default export. That's what makes a resource route. We can export anything we like as long as it's not a default export. So other components and utilities that integrate with the resource route directly. And so it's not just components. You could do hooks, you could do really anything like a button that links to a PDF generator and the loader is like generates the PDF, whatever. Anything that ties specifically to this resource. And just keep that co-location and that code co-location makes it easier for us to maintain the software in the long term. It's really, really cool and exciting. I love this.
Speaker's Gratitude and Favorite Remix Feature
The speaker expresses gratitude towards the audience and thanks them. The speaker mentions being excited to be at RemixConf EU and part of the community. They discuss their favorite Remix feature, Mutations, and how it simplifies application state management. The speaker refers to a poll where one of the favorite features was Kent. The speaker then transitions to the first question about whether full stack components break separation.
So the last thing that I want to say to you all is you're inspiring. Thank you very much. See ya.
Hello, thank you so much for having me. I'm super excited to be here. RemixConf EU rocks! That's sad. Super just happy to be a part of this community.
Yeah, it's awesome to have you here and that presentation was excellent. So the first question before we start is actually for you. And I wanted to ask, what is your favorite Remix feature? My favorite Remix feature? I chose Mutations. I think that application state management is the hardest part of building a web app these days. And Remix makes that a non-issue, completely. So that's my favorite feature for sure. That's awesome. When we did the poll on Slido, one of the favorite features was Kent. So I thought that was quite appropriate. It was pretty awesome. So we'll start with the questions. We'll start with the first one. Does full stack components break separation? Oh, yeah. Oh my gosh. I asked you your question. I completely forgot that we asked that. We asked the question beforehand that you provided. See how excited I am to talk to you, Kent? I better remember that there's other people that also want to ask questions. But before we do that, you asked the question, which was which one of these is not an accepted Remix export? And you had a couple of different options. And it looks that majority of people chose should revalidate. It was like 78%. Some people thought it was handles. Some people thought it was headers.
Full Stack Components and Separation of Concerns
Should revalidate in Remix is called as an unstable API, and it's called should reload. The Remix team is currently moving the React router APIs back into Remix. And so eventually, it will be should revalidate. But right now, it's unstable should reload. Full stack components break the traditional separation of concerns. JSX started breaking the idea of not mixing logic with markup. UIs require logic and design, so the concern is the combination of all these technologies. CSS and JS, Tailwind, and the backend are all part of the concern.
And a few people thought it was links. So what is the correct answer Kent? Yeah. Most people got it correct. This is a bit of a trick question because should revalidate in Remix is called as an unstable API, and it's called should reload. Unstable should reload. But in react router version 6.4, it's called should revalidate. And they're, the Remix team, is currently moving the React router APIs back into Remix. And so eventually, it will be should revalidate. But right now, it's unstable should reload.
That's awesome. And again, remember to go to Slido to participate in these questions that we're going to ask throughout the show. And that was a reminder for myself, by the way. And let's get back to questions with Kent. And let's go to the first one. Doesn't full stack components break separation of concern? Yeah, yeah. That's a good question. So, we've been breaking the people's idea of what separation of concerns means for years. Starting primarily, or at least in the modern age, started with JSX. And people saw JSX and they said, I shouldn't mix my logic with my markup. It just doesn't make any sense. Well, the fact is that we're working in UIs, and the logic is a very important part of what you're trying to accomplish. So, to me, that is the concern. The concern is the Twitter like button, or whatever it is that you're building. Twitter like button is a good example though, because it's not just the logic behind whether or not it's toggled on and off and what to do when the button's clicked, but it's also like what the thing looks like. So, then we've got CSS. That's a part of that too. So, now the concern includes all three of those technologies. So, that was my argument for CSS and JS, and now I'm into Tailwind, which is kind of a different take on that. But just the co-location of what concerns that use case. But then even that isn't the complete use case covered, right? There's also the back-end portion of that.
Fullstack Components and Island Architecture
Fullstack components embrace the fact that things that change together should stay together, redefining separation concerns. The idea emerged during the Remix advanced workshop for Remix Conf. Ryan initially liked the idea, and it has gained popularity. Full stack components are not the same as island architecture, as they focus on code organization and maintainability rather than performance optimization. They provide a cohesive environment for colocating code that should live together.
So, Fullstack components just takes that idea further, and really, my optimal code organization strategy is the things that change together should stay together. And so, if you're changing the back-end code anytime you change the front-end code, and vice versa, well, maybe you can put those things together. And if you're changing two things together frequently, then maybe they are the same concern. And so, yeah, it doesn't break separation concerns. It embraces the fact and maybe redefines what separation concerns means in your mind.
Yes. So, where it came from for me was I was working on the Remix advanced workshop for Remix Conf in the U.S. and I was building a combo box showing how to use use Fetcher and everything. In fact, like the the one that we did today, the exact same example. And I had them in several... So I had a resource rounded over here and then I had my component over there and I was like, I wonder if I could just... and then like, sure, I guess why not? And I showed it to Ryan because he was going to co-present that workshop with me. He's like, I don't hate it. And let me think about that for a little while. And then eventually he decided he really liked it. I love it. And so, yeah, just it's definitely not something that the Remix team had ever really thought about. But I am seeing this and I love it. Now, that's awesome. That's awesome.
Another question we have, KB says, I've been hearing the term island architecture recently from other JS frameworks. Are these full stack components like Remix's version of that? Not exactly. Island architecture is a lot more about what gets hydrated and where. And in Remix apps, it's all still the entire thing is hydrated. And so it is a little different. You might be able to implement a sort of islands architecture possibly this way. Yeah, people do wild things with resource routes. But yeah, this is more it's less about a thinking like a performance optimization, and more about a maintainability optimization and colocating the code that should live together. It definitely feels like you're in an island though, because I mean, your component can accept props and everything.
Full Stack Components and NPM Publishing
Full stack components allow for a great way to develop components that can accept props, reference context, and combine backend and frontend code. They can be published to NPM by either creating a route file and calling functions in an NPM module or by publishing a function to be called in the REMIX config. Hydrating specific routes in REMIX can create islands, but it may not align completely with the concept of island architecture.
It definitely feels like you're in an island though, because I mean, your component can accept props and everything. It can reference context and stuff. But it really does feel like it's on its own little island. And it has its back end and front end and everything all just together. It's just a really great way to develop those types of components.
Nice, nice. And another question. Can full stack components be published to NPM? That's a great question too. So yes, they can. So the challenge is, you've got a single file. And with REMIX, there is a file convention. And so how do you, like if I wanted to make a Twitter like button that people can use on all of their different websites, how would I do that as a single file component? Because we need to have a file in the routes directory for a resource route. Well, that's not completely true because you can actually imperatively at build time create routes in REMIX config. There's a routes option there. And so you've got two options. You could make a route file and then just call into functions in an NPM module that handles everything for you and you just tell it what's the resource route URL. Or you could publish a little function that people are supposed to call in their REMIX config. And so in the REMIX config, we say like, set up my Twitter like button route thing. And so then that way, the Twitter NPM module would be able to know what the URL for the resource route is, because it's responsible for creating that resource route. And then it can talk to itself that way. So I haven't seen anybody do this, but I think that'd be cool if somebody did.
No, awesome. Awesome. To follow up on the island architecture question, couldn't you only hydrate specific routes and REMIX to make it islands? So, yeah, I wouldn't. Yeah, I'm sure that is possible. It's not something that I've tried. But, I wouldn't call that– Islands to me is like many things on a single page. We do have the idea of nested routes, and so maybe you can have a nested route that this is the only part that's hydrated. I'm not gonna say that island architecture isn't in line with what REMIX is trying to do. I'm not completely convinced that the– Though like it is technically, from a theoretically technical standpoint, it is better to run less code.
Island Architecture and REMIX's Suitability
I'm not convinced that the island architecture is always the right thing. I use REMIX for everything. There are very few projects that REMIX isn't well-suited for. REMIX doesn't have HMR yet, but the team is working on it. Starting with REMIX allows you to adapt to changing requirements better than anything else. REMIX being part of Shopify is thrilling, as it provides stability and funding for the framework.
But in practical terms, I'm not convinced that the island architecture is always the right thing. And even necessary for most apps. And so that's why I haven't really spent a whole lot of time thinking about or working through that myself. But I am convinced that you could implement an islands architecture with REMIX but yeah, I haven't bothered to try.
Yeah, no thank you for that. This is a question I wanna ask because I know there's a lot of people that haven't tried REMIX yet. So are there any projects that you wouldn't use REMIX for or what is your thought on that?
Yeah, no projects that I wouldn't use REMIX for. I use REMIX for everything. So there are very few projects that REMIX isn't well-suited for. I have talked to some teams that are like, well, we just can't do life without HMR. It's like, well, I mean, okay. REMIX doesn't have HMR yet. Eventually, we'll get that, but it doesn't. Things are a little bit unique because REMIX is so server-centric, like how do you do HMR with the server and stuff, but I'm convinced that the team is eventually going to figure out something for that. But like just about anything else I can think of, like you think, okay, well, what if I have a single page? It's a game, it's using local storage for everything. Why would I use REMIX for that? I mean, yeah, you're not going to take advantage of nested routing, that sort of thing. You're not taking advantage of loaders necessarily. But what else are you going to use that's going to be any better? Like, will Veep serve you better? Not really. Like, it's like we're all kind of on the same playing field. And what's cool about starting with REMIX is that eventually when you decide, oh, man, this game is wordle and I'm about to sell to like this big company or whatever, and we need data persistence and you know... Well, you just upgrade to that because you built it with REMIX from the start. And so I struggle to see situations where REMIX isn't a great starting point because it allows you to adapt to changing requirements better than anything else I've seen.
Nice. Cool. And here's another great question. How do you think REMIX being part of Shopify will affect the framework? Oh, my gosh. I'm so, so thrilled about this Shopify thing. Like just imagine for a moment that REMIX had not sold to Shopify, REMIX is doing, is still doing fine. Like we would have continued to work just fine for like another year and a half or so on the funding that we'd received originally with the number of employees we had. So like it would have been fine but the problem is eventually the REMIX team would have to figure out a way to make money.
Shopify's Acquisition and the Future of REMIX
Shopify's acquisition of REMIX allows the developers to focus solely on the framework's development without distractions. This partnership ensures that REMIX version two will be released sooner, benefiting the community. Shopify's unique requirements make them an ideal acquisition company, providing a solid foundation for a framework. Their collaboration promises exciting use cases and a positive future for REMIX.
And what all that means is that these amazing developers who are developing this framework for us would be distracted by other things that are not related to what the framework is. And so Shopify coming in just says, hey, you keep on working on what you're doing, you're doing a great job with that and we'll take care of the money thing. And so I'm thrilled that Ryan and Michael in particular don't have to worry about the making money stuff and they just continue churning on this framework for us. I think I'm convinced that we're gonna get REMIX version two much sooner than we would have if they had to start thinking about making money. So I'm thrilled and of all of the companies to acquire REMIX, I think Shopify is just so good as an acquisition company because they have some of the most interesting requirements that I don't think are generally applicable to everybody but definitely it's a really good baseline or a common denominator for what people need out of a framework. So really excited about the use cases that Shopify will bring to bear on REMIX. And I think, and they've just been really awesome as a company too. So I think that they're gonna be really great stewards of the web and a really great place for REMIX to hangout.
Speaker's Love for REMIX and Shopify's Support
I fell in love with REMIX instantly. Shopify's support increases confidence and adoption. REMIX is my go-to for personal projects, enabling faster development.
Yeah, no, that's really, really awesome. The soon as I tried REMIX, I fell in love with it instantly. And a lot of times when I show REMIX to others, they're like, wow, this is a really cool way of doing it. And I think having a company like Shopify stand behind REMIX is huge because it gives more confidence for someone to be like, hey, this is backed by Shopify, let me check out this and it'll increase the adaptation rate. But for me, like I said, for all my personal projects, REMIX has been my go to way of doing things. And I find myself developing things faster, which is pretty awesome.
Influences of Hydrogen on REMIX
The REMIX team discussed the influences of hydrogen towards REMIX with Shopify. They compared server components to Remix's current capabilities and found Remix to be a better approach. Shopify decided to bring the Remix team on board. Hydrogen's role will likely involve more full-stack components, such as a configurable shopping cart. The end game is still unclear, but there may be a hydrogen stack or a special CLI. Hydrogen concepts are not expected to be integrated into Remix, as Remix already has similar functionality. However, Shopify engineers will contribute to Remix's development.
And I guess like another question I have, do you think there's going to be influences from hydrogen towards REMIX? Yeah, actually, so the REMIX team, we talked to Shopify months ago, like even before REMIXconf. They came out to Salt Lake, we were talking about, you know, potentially doing what they're doing now earlier before they released hydrogen with the server components. And we're just trying to say, hey, listen, like server components aren't really released yet. Like it's not a stable API or anything. Like you're going to release on top of something that's not finished. But look at what we have now. So like compare what server components gives you maybe in the future to what Remix gives you today. Now, absolutely. And we just think that this is a better approach. And so eventually Shopify took that to heart and decided that they really wanted the Remix team and brought us over or I'm not there anymore. Just let them to be clear. I'm full-time on Epic web, but decided to bring the Remix team over. And I think that hydrogen's role will be more full-stack components. Type of situations, they'll have like a shopping cart that you bring in and maybe configure. It could be like, they had the blog post where you still are using hydrogen, but you're importing things from Remix. So there's kind of like a mix there. I'm not sure what the end game for that is. Like, do you install Remix? And then, or maybe there's a hydrogen stack sort of thing. I think that probably makes a lot of sense to have a hydrogen stack. I expect that's probably something that will come out of that, whether it's technically a stack or maybe some special CLI that the hydrogen team comes up with. But as far as like hydrogen concepts coming into Remix, I don't see anything like that. There doesn't seem to be anything that hydrogen specifically had that Remix didn't already have outside of things that are Shopify specific, like shopping cart and stuff, which of course wouldn't be well placed inside of a generic framework like Remix. But certainly, there are a lot of really smart engineers at Shopify who will absolutely be helping Remix in lots of ways. So I'm looking forward to that collaboration too.
Full Stack Components and State Management