The Problem Nuxt Layers Solve
When we build our applications, things can get quite complicated, especially then when it goes from one project to another and you have certain things that you always do, right? And of course, then you can say, hey, let's encapsulate these things, these maybe functions, helpers, utils in some kind of npm package. And it works. And then you might start saying, oh yeah, we have a component library as well, that's also in a package. But what to do with all Nuxt stuff? Yeah, of course you have modules, that also makes sense, obviously.
But it wouldn't be nice if we have for example, multiple applications of products, if they could just all depend on the same base? You would update the base, then you also know that you might have to touch on these product applications, of course. And this is something that works already, also as written here with like a component library with composables that you can just extract in a package and with modules. That's fine. But also with npm packages, yeah, of course, you need to set up a private registry; it's a bit of effort. So commonly, you can also put them in a monorepo, it might make things easier, or use git submodules if you want to. Nevertheless, this is more or less a solved issue.
But what if you think further? Let's say you have these products and they are for a client each, right? But now you say, okay, two clients want the same product app here, this one, but they want different features or they want a different style. So what do you do?
Well, I know solutions with branches, I know solutions with repositories, and once again, submodules, and it all feels painful. But with Nuxt, it's a bit easier thanks to layers.
Two Core Use Cases for Layers
So what you can do is you can extend the tree to this. And now we actually talk about layers as a proper application. So let's say you have a base layer, which is more or less a part of a Nuxt application. It contains the Nuxt config and then whatever you need in here. And then you can say, okay, we have another application that actually extends this base layer down here. So we can have multiple applications extending that base layer here, like the product applications. And then say we have another layer on top. So think of it as like an inverted tree that once again depend on this product app and does also on the base layer. So we have like a white label application here and there, you know the drill.
And that works pretty well. The best part is, we'll see that in a bit, with layers you can override parts of the lower layers, but otherwise you have everything ready at your disposal with full Intellisense, with your TypeScript support, and with all the Nuxt app features without hassle.
But while this is a common thing I see around, there's also another benefit that's not talked often enough about. So you can slice your application like that, especially if you have some kind of white labeling need. But you could also say, let's take just one single application and group it, for example, by feature. You could say, hey, we have one application that's on the top and then we say we have a cart layer, search layer, an authentication layer. They all cover these parts. Or you could even say, hey, the auth layer, well, we need it for other parts, and then you could write layers that depend on the auth layer, then used by the application eventually. So all in all, you can spin up your Nuxt application with smaller sub-apps. And with layers, you can then encapsulate the code in a nice and meaningful way. And if you wonder, okay, this is a little bit abstract, how do you actually do that? Well, don't worry, this is our job now. Let's jump into the demo app.
Setting Up the Monorepo and Layers
All right, our demo application is... wait, not really existent, right? I mean, there's a package.json, it's fine. And we have a pnpm-workspace.yaml that I set up because we use a little monorepo architecture for our application which we'll initialize right away. But also, we will initialize the layers. So what's in the application? That's no secret, you've seen it multiple times. It will just be a plain new Nuxt application, right? Pretty simple. But we can also use Nuxi in it to actually initialize our base layer.
So what we can do is we can use pnpx nuxi init -t layer and then say base. So that's the name of the folder, of course. So what we can do is we can create, let's say, a partial Nuxt application based on that layer template. And we will do the same for the other layer called Layer Two that we described here. And after that, I will quickly prune some dependencies and remove a few unnecessary things to make things a little bit less complicated. After the video, you will easily be able to work with the layer template, but for now we don't need everything there straight away. And then we'll look into what the template gave us.
Alright, if we open the base folder now, we will see lots of things that are familiar, like a package.json, that makes sense. We're in a monorepo structure, right? Didn't do much with that. And Nuxt config. Wow. So as mentioned before, every layer is a partial Nuxt application. But there's a component in here, HelloWorld. We'll have a look at that in a second. The problem is we don't really see... like we don't see any app.vue or pages, but nevertheless, we can start the application and then see what's happening in the browser. And here it already says okay, a full server is booted up. That's nice. So let's see what the browser gives us.
How Layers Work: The Playground Directory
All right, all right. The browser shows Hello world from base layer. That's kind of expected because we used a HelloWorld component. But it also says it here, but the question is, where exactly is this rendered? Because we don't have any app, we don't have any pages. So let's just jump back in the code and see what's going on there.
Exactly. Being back in the base folder, yeah, we don't see any app.vue, any pages. But let's have a deep dive in package.json and see what's happening here in dev. Because on dev, we don't run the dev server based on that Nuxt config here, we run nuxi dev playground. And the playground folder is part of the layer structure to technically test these partial Nuxt layers/Nuxt applications. Because obviously, you want to maybe do some tests, be it E2E tests, or just show developers, hey, here are the things, like let's have a look if things still work, you want to try out some stuff.
So let's take a look at the playground folder here. And here we see an app.vue which renders our HelloWorld component. So there is where the things get rendered for the dev server. And also a nuxt.config which uses the extends keyword. And the extends keyword is exactly on how to use a layer. So we basically have a mini playground application here in the playground folder that's a Nuxt application extending on the base layer only. So this is already how you would use extends, but this basically says extend the whole folder above, so the whole base folder here.
And now we briefly know how Nuxt layers work. So they're Nuxt applications, they can have any kind of components, pages, utils, composables and so on, and we can use them to build stuff. But what we didn't do so far is we didn't use the base layer and we didn't like extend that. Like we didn't say to our application, hey, let's extend that layer. This is what we'll do next. And after that, we have to see how we want to incorporate our second layer that we didn't use at all at the moment. But one step after each other. Let's start with adding the base layer to our application.
Extending a Base Layer in an Application
To add our base layer, we don't have to do much except what is in that Nuxt config for the playground here. So we go into our app folder and I will quickly also start the dev server there, get it up and running. And now we are in the Nuxt config of the application. And in here we can say extends and then point to ../base. Perfect. now we say, please this application here, this app, should extend the base layer like we did in the first example. Yeah, similar ideas, similar vibes. Okay.
But how to make sure that it actually works? Well, we can go to our app.vue here, remove the NuxtWelcome component as we should anyway. Now, why not adding the HelloWorld component from the base layer? So let's do HelloWorld here, save this, and see what we see. Maybe below write base layer component to make sure it's also the correct view. And let's see what happens in the browser now.
Exactly what we would expect. We have this Hello world from the base layer and with the Nuxt dev tools we see it's coming from base/components/HelloWorld. So it's resolved correctly. You can jump in there straight away. And of course the base layer component with the caret comes from app.vue. So we successfully used the base layer here. But well, the message isn't correct, right? Hello world from base layer. Yeah, true. What if we would want to change that? What if we want to adapt that and override that component?
Overriding Components from a Lower Layer
Overriding a component from lower layers is not that complicated. We can just take the component, take the same name—very important—and put it in the higher layer or the higher application. So in here, we just have now components/HelloWorld, and now we do Hello world from application. So if we check the browser now, we will see exactly that: Hello world from application. And if we track it down, it's now our own HelloWorld component. That's because, well, based on how Nuxt resolves component imports, the import from the more specific layers, so the more higher ones—in this case our application, which is the highest layer if you would say so—are preferred compared to those of the layers below. So they have priority and are overridden.
Great. So now we can even override certain components. Of course, not all, because now our layer is a bit useless.
Use Cases for Overriding and Feature Layers
of layers. And this is perfectly fine if you have presentational components in a white label application where you might say, 'Oh yeah, that's tricky, maybe let's not show that as a table but like as a grid.' And you're like, 'Okay, then we have to override the component in that case.' So there are lots of like valid cases where you want to do that. Sometimes also just to say, 'Hey, there's a function and I want to change what it's doing for some specific layer.' That's fine.
So the first case is kind of covered. Let's jump to the second case that I've shown you with the auth layer, search layer, shopping cart layer, how we would realize that. Well, we do that with our Layer Two that we haven't used so far and use the base layer and the layer two in between, where the app on top of here extends both.
Combining Multiple Layers in One App
So let's jump into it and more or less use a component from the Layer Two layer and from the base layer. To do that, let's rename our base layer component here to not HelloWorld but maybe SomeComponent and just write Some component from base layer to make sure that we can distinguish. And now let's close these folders for less confusion and open the Layer Two folder here. And it also has a component called HelloWorld. So let's change this and say Layer2Component, for example. And once again, this can have many subcomponents, that's all fine too.
And the next and last step, well, we want to add the component, but that means we would have to extend not only by base, but also by Layer Two. And now in our app.vue in app, add the latest component and also rename that HelloWorld one because, well, that was—we changed that, right? And we don't want to use the HelloWorld from here. So we call it SomeComponent. So let's use SomeComponent here. And the Layer Two one was Layer2Component. And you see already this works with auto completion; they are recognized already. We can move this here and I didn't have to do anything, no reload, nothing. So we're good to go, I would say.
And now in the browser, we should see the components from both layers. And this is exactly what happens. Perfect. So here we see the base component, some component that we renamed. That's perfect, that works as expected. And down here in Layer Two, the Layer Two component. And that's a very, very simple example on how you can use two layers side-by-side. Of course, they can once again have other layers as well so if you'd want to, you can even say I have a layer depending on the layer and so on and so on.
Advanced Usage and Important Caveats
And here we are. Authoring layers should be a breeze with that. As usual, the code is linked in the description below, as are all the other references. So don't forget to check that out and might use it as a starting base or just see, okay, this is connected, let's code along, however you want to.
Very important, there are a few caveats to mention when using layers. So first, it's really nice that you can extend folders locally, and that's not it, that's actually more a feature than a caveat because you can extend repositories like GitHub, Bitbucket, GitLab and so on. And you might have to do a little bit more to actually access them with an access token when they're private. When they're public, it's a bit easier. And you can also extend npm packages. Yeah. So you can also share your layers as packages.
But when you extend layers and they use an alias in a path, so let's say you do import whatever from '@/ or ~/ and so on, that might not work in your end application. And why? Well, because these aliases, they always point to the source directory of the running Nuxt application. And if you run your app, then the @ from a layer below, they will point to the app, which is not the desired way, right? Not at all.
Thing is, there is a consideration to create named layers that also then have their named aliases. There is an issue tracker tracking the progress on that and it might come in the future, but that would solve the issue. So then you can say @base/ and so on, so on which also make it easier to access files from layers below, even though you might want to override them or use them and then do something else with them.
Nevertheless, this is all a little bit in the future, but right now the layers are still pretty powerful. I've seen them in action in quite some projects and generally people are happy after they figured out how to use them, especially because you can use all the Nuxt goodies like the auto imports we've seen, the modules and so on and so on.
Final Thoughts & Call to Action
So now it's your time. Make your projects modular, layerable, however you want to call it. And compose nice things out of them, reuse stuff and get going.
If you have any questions, of course, regarding to layers, if there's anything maybe we should build together with layers, please drop them down below as usual. I read all of them and come back to you. I know layers is a topic that lots of you want to see covered, so here we are.
And other than that, of course, stay tuned for the next videos and please have a look at the newly released podcast with Michael Thiessen and me called Déjà Vue, if you haven't noticed or heard yet. A link to the episode is here and also in the description. Or maybe here, mirrors, weird. Anyway, that's it for real now. Check out Déjà Vue, check out the other videos on the channel, and latest, see you next week. Stay safe and happy hacking.