Introduction to Nuxt Middleware
Hey developers, my name is Eric. In this video, we're going to talk about Nuxt.js. We're gonna talk about the differences between server middleware and normal middleware, and also we're gonna take a quick look at asyncData as well.
So if you guys don't know, my name is Eric. I am the author of the Vue.js in Action book. I also have several years of software development experience. So make sure you stay all the way to the end, that really helps me out. And also, I have some amazing courses. Udemy has these ten, eleven dollar sales. If you use my links below, it actually helps the channel out and you'll get those discounts. So just click any of those links below. I have some of my favorite courses. Click on it, if you buy it, I get a few bucks. That really helps me out. And those are all in the description.
So here I went ahead and just created a real simple app for you. I just created the starter app and changed the name to 'test123'. I have one route, you can see here... you can see under the pages folder I have one named 'eric' and I had added a link, so it says "Hello World Eric". And that's all it does, just a really simple app.
Understanding Universal Applications & SSR
So I wanted to show you a little bit about server-side rendering. So in the documentation, if you look up nuxtjs, you can look here at nuxtjs.org, it talks a little bit in the guide about... you can see here this little thing here, that there is views, routes, and there's asyncData and there's middleware. So let's take a look at asyncData.
So the idea is that since Nuxt is what they call it is a universal application. You can see on the front page, it's called a Universal Vue.js applications. And what that means is that it has all that neat server-side rendering stuff built into it. And what it's really doing is that there's a Node.js server that helps render the pages on the initial page load, so it's quicker. So instead of a a normal single-page application where all the JavaScript has to load first, and then you have the first page up here, this one actually uses this Node server to load the page quicker because it just sends down the HTML/CSS first, and then later the whole app and JavaScript gets loaded.
Exploring asyncData
But it also has some nice features where you can run code on the server side and the client side. So the first way to do that is something called asyncData. So I'm gonna look in my Eric view here and I'm gonna add a script tag and close the script. And if I add something called asyncData, I can actually add in code here. You actually have something called the context, and this gives you the ability to have access to a bunch of different things on the app.
So if I go here and I search for context, I can get some information about it. You can look at the API essentials and basically you get access to the app, isClient, you can see if it's a server, route, store, you have all these variables. And what happens is this asyncData actually loads before the component loads itself, and it loads on the server side and the client side. So you can see here if I run console.log('hi') here and I look at this test run... and I actually have the server running. And I got an error because I need to do this. I need to export default... and then I'll put this code in there. I'll refresh it. And you can see I don't see anything here at the bottom. Let's see if you can see that, yep, you can see it right here. It says app is up to date. I don't see anything in the console, but if I click on this link, this is inside the Eric, and I save it, you can see here it shows 'hi' down here. So it's actually loading this console log on the client side. But if I look at here, and here's my server running, and I refresh it, you can see here now it's running on the server side. So you can see it's actually... it runs on the initial page load, it runs on the server side, but when you actually change routes, you see here I go back, it runs on the client side.
Server-Only Logic with asyncData
So this isn't going to help us if we want something to only run on the server side, like if we have some secret information, but you can see that's how it works. And you can actually... there is a way to make it only run on the server side, but it doesn't run every time. But if you do something like process.server here and you put this console log inside here and you refresh it... you see here I'm refreshing it and it's not... still loading here. There we go. Oh, process is not defined. I think I have a typo, too many C's. I'll reload it again. You see here, it's not running on this side, but if we bring over our server side, you see every time we reload it, it runs on the server side, but it never runs on the client side again. You see here in the console at the bottom, it's not loading. So that's one way to do server-side rendering, but it's not really perfect.
Using Route Middleware
The other way to do it in middleware is... and also by the way, one thing nice about asyncData is I can return a value from asyncData, an object, like let's say I have blah and I can put a value in here, hi, and actually I can use that object inside here. So if I hit 'Press Me', you see here's 'hi'. So I can return stuff from my asyncData. I do have access to this context, like I showed before, which has access to your query params, your query, your request object. So you can see requests from the Node.js server. If Nuxt is used in middleware, the request object might be different. So you have access to a lot of these things that... this is not in plain vanilla Vue.js, but you're not really running stuff on the server.
Now, middleware is something you can do. So I can actually do something like this. So I'm gonna delete this async... well I'll just comment this out so we don't get confused. And I'm going to add something called middleware, and we could also define this in a few other places inside the nuxt.config file. But let's say I wanted to create a middleware called, I don't know, I'll call it eric. It doesn't matter. So inside this middleware here, I'm going to create a new file, I'm gonna call it eric.js. And then inside eric.js I can export... let's see here. I can do something similar. I'm going to copy and paste this from another screen just to save time. So I can do this export default function. You still have access to the context, and we can do things like this. Where I could have done this in asyncData, I'm going to do destructuring to get the app out. I also could just do something like this. That'll work the same way. But just to keep it simple, I have app here. I can also do process.server here too. And then I can console.log the app. So I'm going to delete this. I'm just gonna leave console.log(app) and if we load it... and I get an error, so blah is not set. Oh, let me go back to here and let me delete that. Reload it. And now if you look back here in the server, you can see here, now we have this huge glob of data. So this is coming from the server because it's on the initial page load. But if I go back and click it, now it's showing up in the console here and not on the server. So here's the same information in the console on the client side. So once again, just like middleware, just like asyncData, it only runs on the server side on the initial page load and then after that it runs on the client side.
What Is Server Middleware?
So you're probably thinking that, well, why bother with this? Why try to even do anything in the server side with this because it's... I mean, you can use this if process.server, but it's not perfect. So the third option and the true way you want to do server-side rendering or run server-side functions using Nuxt.js... I mean, like I said, by convention, by default, it'll do all the server-side rendering for you. But what happens if you truly want to write some server-side functions in here and create your own routes that are outside this Nuxt app? Well, that's where server middleware comes in.
So Nuxt, like it says here, Nuxt internally creates a Connect instance, so we can register our middleware to its stack and have changes to provide for more routes like API without the need to an external server. So this is the nice part. And this is what's in bold: without the need of an external server. So instead of having to create an additional Node.js server somewhere, why not just use the one inside Nuxt.js? It's there. And it says obviously, don't get it confused with middleware. And you can configure it in the nuxt.config.js file. And you have this next. So you can do it two ways. You can actually create your all your routes, you can create like external API routes inside the server middleware and then just have it rendered. Or if you want to kind of give control back, you can run next, and that invokes the next middleware. So don't forget call next at the end of the middleware if it's not an endpoint. So if you're creating endpoints, then you wouldn't want to use next. If you are creating... if you don't create endpoints, you just want something else to happen, then you might want to use this next. So it's pretty easy to use.
Implementing a Basic Server Middleware
So I can show you here. So what you do is you go to your nuxt.config file, and you add in the serverMiddleware with a colon. And then you have this array here. And then you have each object that you want to put in here. So you can do things like serve certain static files, you can do additional things like, let's say we already have the eric route, so I can do path /eric and then I can add in a handler. And we'll just call it... API... we'll call it index.js, just kind of like it is in here. And then we'll have to make sure we make this an object like this. And now we can go and we need to create a new folder. So we'll create a new folder called api. And let's make sure we're whoops... we'll create a new folder, we'll call it api. And inside the API folder, we'll create a new file called index.js. And then inside of it, we can... we can create just kind of like what's doing here.
So I went in and stopped the server and restarted the server after I made this change to this index.js file and I added the console.log(req) in there, that's for our request. And you can see here, here's the server. If I go to 'Press Me' here, and when we start it here, the server, and I refresh this page... 'Press Me', and refresh it, you can see here I have the full object coming through here. So it's run on the server side and not never on the client side. So it's useful but it's not perfect.
Creating an API with Express
So one thing we could do, which makes this even better, is let's say we want to use an Express server to set up an API endpoint. So I'm going to go back to my nuxt.config file and instead of having the server middleware like this, I'm going to just do everything inside one file. So I'm gonna just put it as api, and we're gonna have that index.js file. We can just put index. We need to put the js in there. And make sure we have a comma at the end. And then inside here, I'm going to delete this.
Okay, let's go and delete everything in the index.js file like I just did. I'm going to go ahead and copy and paste just a basically a "Hello World" Express server. So I have our express = require('express'), app = express(). Then I have this app.get which has a request and a response object. I'm just going to send "Hello World", and then I'm going to export the module with api here. So I'm gonna save it and then let's stop and restart my server in the other window here. So this actually should give us a new endpoint outside the Vue.js app. So if I go /api here, I actually got this "Hello World". But right now we're not inside the Vue.js app at all, this is a separate endpoint. I can also use something like Postman, you see right here, and if I hit send here, localhost:3000/api, I'm getting "Hello World". So I'm not even inside the Vue.js app at all right now. I've actually created this endpoint and it just works, which is really cool.
So you could see I could do a whole bunch of things here. I could do authentication, I can do all my authentication in here. Or if I have some secret keys that I can't have exposed to the inside the client app, I can put them all inside here and then do calls out from the components into this API. So it's pretty powerful and now I don't need a whole Node.js server.
Conclusion & Key Takeaways
Now of course if you're doing a lot of complicated things, you probably want to go ahead and just get an actual server, either Rails, Node, Java, something. But if you have a really compact app, I could see you doing everything inside Nuxt and just write all your server-side code inside this middleware here and have it all just run. So this is... so I hope you guys like this video.
Just some quick tips on differences between asyncData, middleware, and server middleware. I think Nuxt.js is really powerful for creating Vue.js apps because you have things like this built-in, it's really neat, and you also get the power of server-side rendering on your initial page loads.
So if you guys like this video, please click that like button and subscribe. And below, tell me how you guys do server-side rendering, what servers do you guys use? Do you guys use Node, Rails? What do you prefer? Let me know. Thanks.