Video Summary and Transcription
This Talk discusses optimizing developer experience with Nuxt 3. It highlights improvements in documentation, auto importing libraries, server developer experience, and deployment. Nuxt 3 introduces a unified solution for schema, documentation, and defaults, as well as auto imports for easy component access. It also introduces a faster server framework called H3 and allows for efficient network requests with isomorphic fetch. Deployment is simplified with a single entry point and support for various platforms. The goal is to make Nuxt 3 amazing and backport features to Nuxt 2 apps.
1. Introduction to Developer Experience with Nuxt 3
Hi, I'm Daniel Rowe, and I'm going to be talking about optimizing developer experience with Nuxt 3. Developer experience is a topic close to my heart. The more we make opportunities for creativity and reduce constraint, the better developer experience we see. NUXT is a view framework, a JavaScript framework, suitable for someone with no knowledge of it.
Hi, I'm Daniel Rowe, and I'm going to be talking about optimizing developer experience with Nuxt 3. Developer experience is a topic close to my heart and I think that's probably true for most of us here today. It matters a huge deal, doesn't it? The tools we use have the capacity to make our life painful or make it magical.
At the moment I'm speaking in my role as a member of the framework team for Nuxt itself which means I get to maintain and work on the framework alongside a huge community of people who contribute and make Nuxt possible. In my previous role though I was CTO for a tech startup. Our main product was built on Nuxt and so I've really encountered Nuxt from both angles both as a user being frustrated by issues trying to solve them and in fact contributing and fixing issues was my first way of contributing to the Nuxt community, but I also of course have now got the perspective of working on the the Nuxt team too and really I'm going to be thinking about developer experience from both perspectives today.
This is where I'm based. I'm in the northeast of the UK, it's already cold and crisp, it's definitely autumn and this is where I sit most days. I'll look across my desk and see my cat, one of my cats, I have three but that's Lily in the picture and I'll have a cup of coffee if it's in the morning or a cup of tea if it's the afternoon and this is where I like to be. I like to sit and code or chat, figure out problems and try and make things better. This is where I feel most in the zone.
So I have a question for you, when have you felt most productive, most in the zone, most in that flow state that we sometimes talk about as developers? Just take a moment call it a mind, see if you can freeze that moment in your head. It might have been that you were confronting a problem. You had some great idea that you were implementing. You'd been on a bug hunt for it seems like ages and you've found it at last. Maybe you've published a library and you're seeing the GitHub stars come in, or you've just seen your first PR merged. Whatever the reason, it feels like you are on top of the world.
So the more I've thought about my own moments of being in the zone or talk to others who have had the same experience. I think there are a lot of things that go into them and it's a hugely complex topic. Obviously we want to replicate it. It's addictive. It's a wonderful moment in time and it depends on lots of things going on. Everything from your own personal well-being, to how much sleep you've had, how much caffeine you've ingested, to whether people are treating you well or fairly, whether they are giving you the value that you deserve, how you feel about yourself.
But there are some common factors I think when it comes to thinking about the tooling that we use which is particularly of course the topic that I'm thinking about today ways in which the tooling we use can promote that in the zone moment, can promote our developer experience and I think it's particularly around these two axes. So on the one hand constraint things that are holding us back and on the other creativity the things that we're trying to do that sense of vision or energy or impetus that we have. And now when I'm talking about constraint I'm not talking about the constraints that you work with when you're trying to find a solution to a problem like a business problem I'm talking about the constraint that's more like red tape that just holds you back that prevents you from implementing the idea that you might have. Obviously that might be hugely oversimplifying it but I think you see great developer experience when you have that creativity when you're going with the flow you have some amazing idea and there's very little if anything to prevent you from realizing it.
So the more we we make opportunities for creativity and the more we reduce constraint I think we see better developer experience and that is really where NUXT has always sought to position itself. Don't worry if you don't know what what NUXT is, NUXT is a view framework, a JavaScript framework. It's a it's a progressive framework which means that it's suitable for someone with no knowledge of it.
2. Improvements in NUXT 3
NUXT is a progressive framework that takes away a lot of boilerplate and allows you to focus on your ideas. With NUXT 3, we've made improvements in documentation, auto importing libraries, server developer experience, and deployment.
You can pick up NUXT, install a NUXT project and you should be able to start developing straight away. It doesn't require extra configuration, it works out-of-the-box but if you need to take ownership of it and take full control you can do that. As you start building with NUXT you can configure pretty much anything. In fact with the modules ecosystem and the whole modules container you can configure everything about NUXT and make it work almost in a completely different way from how it did when you first picked it up.
It's a progressive framework but it really is meant to take away a lot of the boilerplate. That zero configuration side of things is hugely important, it's in the NUXT DNA. So when you pick up your NUXT project you might see there's a pages folder, just drop any Vue component in there and it will become a root into your app it will be bundle split, it will be set up with Vue router, it will have a name. All the things that you might have to do previously as part of the boilerplate of a Vue project gets done for you automatically by NUXT. More recently you might have wanted to have a static website. NUXT makes server-side rendering possible. In fact it was one of the few solutions that did early on in the days of Vue applications, it was quite a complicated thing to set up and NUXT made that possible and more recently with static site generation, NUXT makes that possible too. Lots of other things from VueX store integrations to automatic registration of middleware. I think probably the main thing that I'd highlight is this concept of modules. The idea if you need to implement a progressive web app or you need to implement authentication you don't have to do it yourself. You have a CMS you want to integrate or some other service you just pull in the module for it and NUXT makes it possible for you to get on with your idea without actually needing to step back and figure out the boiler plate you would require to properly set up that service or re-implement that that concept. So no need to reinvent the wheel. The concept of NUXT is really to free you from constraint and free you to focus on that idea you have your vision.
NUXT 3 really takes the same path again. So with NUXT 3 there are lots of things to talk about, lots of ways in which we've tried to improve developer experience, but I want to focus on four today in particular. I want to focus on how we've sought to improve the documentation, because and that might sound minor, but I think it's quite a profound way in which we've sought to change the documentation, make NUXT easier for devs to use. I want to focus on how we're auto importing libraries, helper functions, and components. I want to think about our server developer experience. This is really possibly a completely different way of approaching server side functionality, and I want to think about the deployment, and how we've sought to make the developer experience of taking an app, and actually deploying it effortless and amazing. So first to dive into documentation. And when I'm talking about documentation, let me use the example of the Nuxt configuration schema. So the Nuxt configuration schema is an example of something that we need huge documentation for. If you go to the current Nuxt2 docs, you'll see there are pages and pages and pages of information about how to configure Nuxt, not that you have to do this, but when it comes to taking full control of your Nuxt application, there are lots of ways we provide to do that. And that's part of what it is to have a progressive framework. We have to give options because there's so much the framework does, so much heavy lifting it does for users. But the moment you have something that has a lot of configuration, it means that it's possible for the application itself and the documentation to diverge.
3. Schema, Documentation, and Auto Imports
With Nuxt 3, we have a unified solution for schema, documentation, and defaults. We include the documentation directly in the schema itself, ensuring that any changes to the code are reflected in the documentation. The configuration schema file provides comprehensive information, including JSDoc types and resolvers. The untyped project, released under an open license, can be used in any framework. Additionally, Nuxt 3 introduces auto imports, allowing easy access to components in the components directory.
So you can provide a new feature, but if you don't document it, it's no use to anyone. Or if the type or the option changes for that new feature and you don't document that properly, it makes a huge difference too. So with Nuxt 3, we have the opportunity to rethink this, and so we've come up with a single unified solution for schema, documentation, and defaults.
So here's an example. This is a possible schema for a configuration item. This is the the view config itself that will be used in a Nuxt app. And these are just two particular properties that I've pulled out. Whether or not the app is in silent mode, which is typically what you want in production, and whether it has performance tracing involved, which is typically something you only want in development. So we have special resolvers that let us set what the default state for each of those is if there's no explicit configuration provided. And it depends on another entry in the config file, namely whether or not dev mode is enabled. But the thing that will really hopefully jump out at you is the fact that we have the docs there. So this is the documentation for our current Naxt website, but we've put it directly in the schema itself. So what this means is when we're editing code or making a change, we'll have to change this file, and if we change this file, we have to change the documentation. That becomes part of making the PR to the core. Then when we actually compile the library up, we will have documentation and configuration that is unique that is specific to that version of Naxt. It produces something that looks a little bit like this in terms of a configuration schema file, all the information, but filled out a little bit more, pulling out everything from the JSDoc types to the actual resolvers and even producing a separate defaults file just to give you a something you can interact with programmatically. And we have the utilities as well that enable you to consume a file like this. And the whole thing is released under a project called untyped, which we are making public and can be used in any framework.
So then when it comes to you actually interacting with your Nuxtats, so you're trying to configure it, it means that we're able to pull in the entire documentation from your node modules folder where it lives into your editor. So as you're editing that config and you want to set one of the options, you can see all the docs that we have got. It's not huge in this particular instance, there would be some options that would have a lot more information, including code samples, links to other websites, and all sorts of other info. But it should give you an idea of the kind of functionality and the power of this ability. The fact that we're actually able to take the documentation and put it right there as you type means hopefully your experience as a dev is going to be dramatically improved. You're not going to need to search the online docs. You're not going to need to figure out even what the question is. Hopefully, the benefit of both the fact that everything is fully typed and fully documented as you go will make a huge difference. It's the kind of thing that would make all the difference for me.
Second, we have this auto imports functionality. You'll be familiar with this if you've used the Nuxt components module, which can be enabled simply by setting components true in a Nuxt 2 project, but this is now built in in Nuxt 3. So all the components that you put in your components directory become available for you to auto-import on usage.
4. Benefits of Using Nuxt
When using Nuxt, you can easily use components, helper functions, and libraries. Nuxt automatically generates the required imports based on your usage, enabling proper tree shaking at build time. This allows for efficient code organization and eliminates unnecessary imports.
So if you are using that component in another file, in a page for example, it gets bundled then to that page. Or you can say it's a lazy import and then it will be generated as a separate chunk, maybe if you conditionally show it something like that.
Well, you've taken it a step further. It's not just about components now, it's also about helper functions and libraries. We're really leaning into the benefits of having a framework here. So some of these kinds of things would be impossible if you weren't thinking of a framework, something that has control over both the bundler and the code transformer, but it is possible with Nuxt.
This means that anywhere in your codebase you can actually use common functions like ref, watch, computed, or use router, or even Nuxt-specific composables like use meta. You just use them. Nuxt will notice that you've used them in that chunk. It will automatically generate the imports that are required and that means of course that we're able to do proper tree shaking at build time as well. So when you use it you have the import and when you don't use it you don't need to import anything at all.
So this is what that might look like, for example. So if you're working in a component you should be able to type. Now define pops I should say is just a compiler macro, but you should be able to use things like use meta which enables you to have access to the metadata of a page, or ref which is a view util and with full typing. So it's not specific to your memory or something like that. And that obviously flows through to the template as well.
5. NUXT 3 Server Framework and Isomorphic Fetch
NUXT 3 introduces a new server framework called H3, which is ultra minimal and faster than other frameworks. It provides utilities for handling requests and is cross-platform. The isomorphic fetch utility allows for efficient network requests. The NUX 3 server is generated as a single file, independent of NUXed, and handles code loading and response rendering efficiently.
Third, we allow you some huge developer improvements on the server side of things. So the new NUXT 3 server framework, and this is true as well for NUXT 2 if you're using bridge. In fact, a number of these features are common to NUXT 2 if you're using bridge.
We built a new HTTP framework called H3. It's ultra minimal, so it's absolutely tiny. It's faster than a lot of the other frameworks out there. In fact, I'm not aware of a faster one. It's got lots of little utilities like use cookie or use body, use query that allows you to do things you might want to do for requests, but which are tree shakeable so they're not injected by default. It's cross-platform, so it runs in a browser as well as a Service Worker or a Node environment and means that your NUX app doesn't have to be compiled to one particular target. It's not just expecting to run in a Node environment and it lets you do things like you can just return the JavaScript object from a request handler. You don't have to JSON string fire up and set the content type header, or you can just throw an arrow and you don't have to worry about properly returning a response to that particular request. It's all handled for you.
In addition, we have something called an isomorphic fetch. So an isomorphic fetch is basically a utility that lets you perform a local function call if it's being run on the server, but a proper network request if it's being run on the client. So your new NUX 3 server, which is, by the way, generated just as a single file rather than a directory of lots of files, it doesn't have a runtime dependency on NUXed. It's purely itself. It's all you need to run your app and run that server, but it doesn't have any runtime dependency on any of the NUXed goodness that makes this possible.
And this is a little bit of what it looks like. So the first thing that any request will encounter is this H3 powered orchestrator that will decide what bits of code are needed to render a response to that particular request. So if it's just one of the API endpoints, we won't load the whole view bundle, we won't load the view renderer or anything like that. We just load the code that is needed. If it is a page, for example, in your view app that might be loaded up, and that page might have a dependency and might want to make a request to one of the APIs that it's sharing space with in that server, where it doesn't make sense to float that request up to the HTTP layer and make it as a proper HTTP request. Not least, that's terribly inefficient in something like a serverless function. You really don't want to be hitting the endpoint again. The code is all there. It just needs to be loaded into memory. And so this fetch, this $fetch function, isomorphic fetch that we're talking about, tells H3, load this code up and give us the response. So it's an incredibly efficient way of getting a response from a serverless endpoint. And it just works. Not only does it just work, it's also fully typed.
6. Serverless Endpoint and Deployment in Nuxt 3
You can create a serverless endpoint that returns a number. TypeScript knows the type of the isomorphic fetch return. You can access the default request and response objects in node. This allows for easy interaction with params and direct JSON returns. Nuxt 3 server dramatically improves user experience. Deployment in Nuxt 3 is simplified with a single entry point and fast build times.
So you can create a serverless endpoint, say time, it'll give us the timestamp of a particular request. And that's just going to return a number. We don't have to handle that number in any way. It's going to be properly passed by the isomorphic fetch. And we can actually just wait fetching that number.
But the amazing thing is TypeScript actually knows the type of what that isomorphic fetch is actually going to return for us. That is pretty magical, if I do say so myself. And we might obviously have something a little bit more complex where we're not just returning a number, but we might need to access the default request and response objects in node.
Those are just typed by the way exactly the same as your normal request response in node, even though H3 H3 might not be running in a node environment, it will be mocked out to have the same the same shape. So you would be able to access something like request URL or you can call res end if you really want to, although a lot of the power of H3 is if you don't need to do that and you actually just directly return your JSON or just directly interact with params. So that would be totally possible. You could throw an error and have it automatically handled or you could access the requests and response objects and that should work perfectly.
All of that means that it should be possible to dramatically improve your user experience with the Nuxt 3 server. And I think there are lots more enhancements that we are going to be able to offer in the coming weeks and months. So watch the space and certainly let me know if you have any ideas.
Finally, deployment. And this is something that I think matters a huge amount because running a Node server is one thing. It has got lots of particular requirements that might be different from, say, running a PHP based script or something like that. So for Nuxt 3, we've sought to make this as simple as possible. So first, as I mentioned, there's just a single entry point that you need for your Nuxt 3 app. So that could just be Node run node.output server server.mjs. So this is what that might look like. For example, just build your app. It's incredibly fast. New CLI. I've enabled timings on this particular one. So you'll see how long it takes to start. Three milliseconds cold start. And I've just performed my request in another window. There you go.
7. Deployment and Feedback
NUXT3 allows for deployment to a wide range of targets, including Cloudflare, browser service workers, and Deno. The new NUXT server, Nitro, can be deployed to almost any place. NUXT3 has zero configure support for platforms like Netlify and Vercel. It also supports Cloudflare, Azure functions, Azure Static Web Apps, and Firebase with minimal configuration. We want to make Nuxt 3 as amazing as possible and backport features to Nuxt 2 apps. Check out the docs on nuxtest.org and follow us on Twitter. Contact me directly for any assistance.
So you see how long it takes to actually load each bit of the request handler. Just milliseconds. So because we're able to generate just a single runtime, it means we're able to deploy to a vast number more targets than we ever would have been able to do before. The entire app can be bundled in 100 kilobytes, rather than something like 5 meg or 10 meg, as you might previously have been dealing with if you were trying to deploy to a lambda function.
But on top of that, a lot of the improvements that we've been able to bring to something like Nux Nitro have meant that we're now multi platform. So we don't actually require a node environment anymore, as long as the dependencies of your app don't require that. So you can deploy directly to a Cloudflare or to a browser service worker or to Deno, more coming. The output of Nitro, the new NUXT server is capable of being deployed to almost any place you can imagine. And again, that's about removing constraint. You don't have to figure out how to make the NUXT server that you get at the end of the build command fit into the deployment setup you have. It should just work.
As of release date, NUXT3 has zero configure support for a number of platforms, particularly notable Netlify and Vercel, where it is absolutely no configure required. But that is true to an extent also with Cloudflare, with Azure functions, Azure Static Web Apps. It's true with Firebase with very minimal configuration and more coming. Nitro enables incredible developer experience from the point of view of deployment. And really, we're looking forward to any feedback we've got on that. We want to make that as good as possibly can be. If any of what I've been saying strikes a chord to you, please do let me know. We'd like to make Nuxt 3 as amazing as possible, and backport as many of these features as possible to your Nuxt 2 apps, so you can actually benefit from all of this today, even before you migrate or build a new app with Nuxt 3. Check out the docs on nuxtest.org. Note that some of them are auto-generated, as I promised. Follow us on Twitter, and do join our Discord server if you'd like to toss any ideas around. And then, of course, please do contact me directly, because I would really value that hugely. It's been a real pleasure. And if there's anything I can do to help, don't hesitate to let me know.
Comments