VueConf US 2023

Talks

1. State of the Vuenion

Evan You

2. Monitoring Your Production Vue Apps

Abhijeet Prasad

3. Proven Pinia Patterns

Adam Jahr

4. Building Data-Intensive Visualization Applications with Vue

Alex Harding

5. What to love about Vue in 2023

Alex Kyriakidis

6. Build & Deploy Mobile Apps with Nuxt Ionic

Cecelia Martinez

7. Patterns for Large Scale Vue.js Applications

Daniel Kelly

8. Speed up your development flow with Vite

Felipe Flor

9. Freak'n Keyboard Traps

Homer Gaines

10. The Next Vuetify

John Leider

11. Conquering Forms in Vue

Justin Schroeder

12. Appetite for Components

Lee Martin

13. Testing Vue Components with Cypress

Mark Noonan

14. Render when? Render where? Render why? Render what?

Phil Hawksworth

15. 10 things about Postman everyone should know

Pooja Mistry

16. Vue to the Edge

Sébastien Chopin

17. Demystifying the Dreaded A/B Test

Chris Demars

18. Introducing unjs

Daniel Roe

19. Nuxt SSG: Strategies & Pitfalls

David Nahodyl

20. Building Your First Open Source Project

Erik Hanchett

21. Two Keys to AI's Future

Gant Laborde

22. Building Desktop Apps with Vue

J.D. Hillen

23. DevOps before there was "devops"

Jeremy Meiss

24. Session Replay

Ryan Albrecht

25. Vue.js: Building Secure Applications

Tyler Clark

Vue to the Edge

Vue to the Edge

Sébastien Chopin

Hello everyone, bonjour. I do have a small accent though. So, I’m very glad to be here for the second time. And today I’m going to talk about Vue, Nuxt and the Edge. I am Atinux, also known as Sebastian Chopin and I am the CEO at NuxtLabs.com, we basically do stuff around Next.js such as consulting workshop, also building product around it. We recently open source our UI kit library.

And today, I’m going to talk about Vue and Nuxt. Who here has used or is using Nuxt? So I will say 50%, hopefully after the talk it’d be more. So Nuxt is a web framework for creating Vue applications, and it’s more than this, Nuxt 3 also allow you to create full stack Vue application and I can run absolutely everywhere.

But first, a small recap, small summary of the features we have. We have server side rendering since day one, client side rendering, if you don’t like server side rendering or you don’t need it for your single page application, you can disable it. We have static site generation, if you have a blog, it’s perfect. Edge side rendering that I’m going to cover right after. We have a hook system, so you can absolutely change many things from the nuxt core to the application part. The five system router that you may know for a long time. We have auto imports as lazy, we don’t like to have imports, but we can auto import for you when you use a component or composable and keep having the tree shaking. We have the data fetching composable very useful when you do server side rendering and you don’t want to have this fetch call happening on client side, so that’s for hydration. We have a middleware system if you want to guard some routes. Plugins, if you use plugin that’s the way to go. Layouts, transitions, we also support the Vue transition API by Google Chrome, several routes and server API, TypeScript out of the box, out of the box with zero config. State Management using use states as a basic one, but you can of course just pin up of UX. We’ve the server components also called island components, pushing less and less JavaScript to the client even if I’m not a big fan of this personally. Layers. So, that is a feature that I haven’t seen elsewhere. It’s basically a way to extend a nuxt application so you can push your next application to NPM and extend it, so, it’s very useful, so, for some or a few application that you can reuse, thinking of composable component, even pages and much more. We have pre-processors if you like stylus or post processor called processes. We have this module ecosystem, think of nuxt plugin where you can push more features to your nuxt application. We have SEO helpers, obviously, if you do server side monitoring, you want to make sure your SEO is top-notch. Testing utils and more upcoming processes and many more features that I won’t call all right now.

So, talking about the edge, who knows what is the edge of this workers? I would say about 4%, so, hopefully everyone will be able to raise their hand after my talk, otherwise I will just change my job. So, the edge is a limited JavaScript environment running on CDN nodes. When you deploy, your code will be replicated to all the nodes. So here it’s the CloudFlare network, but there are others edge platform. So, that mean whenever your customer is, it will render to the closest node. Think of like you have a load of nodes server and you have this load balancer automatically for you. And it renders very fast, so, we talk about millisecond from end users, if I take for example a clutcher network, it’s about 50 milliseconds whenever you are in the world, it’s actually zero milliseconds cold starts compared to serverless hosting such as AWS Lambda, no servers to maintain, it scale automatically and it’s quite affordable right now, we’re talking about 15 cents per million requests. And there are many edge computing providers coming every month. CloudFare pages and workers. Deno deploy for those who use Deno. Lagon.app which is open source, so, you can self-host on your own Edge network. Vercel Edge Functions powered by CloudFlare, and Netlify Edge Functions powered by Dino if I’m not mistaken, you can correct me right after. There is also Edgeio, but after testing it, it’s just a proxy on top of it, so, we’ll have to remove it. StackPath and more are coming.

But the Edge runtime has limitations, of course, otherwise everyone will be using it. It’s different than nodes and browser. It actually run V8 isolates, so, it’s purely JavaScript, you don’t have access to window, you don’t have access to the file system on the node side. It’s like six years ago when you heard about Next or server side rendering, and you try to use plugin by use window, you get a window, it’s not defined, it’s the same here, if you try to access node API or browsers API. You can’t upload your website if it’s more than 5 megabytes, some providers are expanding this limit so expected to grow over time. But, we worked on nuxt 3 and also Nitro the engine behind nuxt to cover, to fix those limitations. So, we actually mock and polyfill most of the node and browser environment to work on the edge because most of the time some of the API you won’t use it in production, but it’s quite useful in development. And we produce and optimize output on nuxt build. Starting with nuxt 3 you can install nuxt dependency as a dev dependency, not a dependency anymore. So, all your dependency of your project goes to the dev dependency and once we build your project you’ll get to dealt output, so that’s why you cannot run the next start command in production because this output has no, you don’t need to in pair install, we trace all the dependencies and packets inside a dot output which is less than one megabyte by default.

Database are also coming to the edge. So, it’s mostly based on replicas and using HTTP proxy. SQLite with CloudFlare D1 which is still in Alpha, Turso.tech which has been released a few months ago still in beta but growing pretty fast. Postgres using Neon or Supabase. MySQL with PlanetScale. I may forgot some of them so if you know don’t hesitate to tell me after my talk. Some hybrids of MySQL and no SQL with HarperDB and KV such as Upstash based on Redis or CloudFlare KV.

And I’m going to do a demo that I will deploy on the edge, and hopefully you’ll be able to interact with this. Do I need to, can everyone see at the back? Or you just pretend and it’d be fine. So, I start nuxt, latest version, can Daniel confirm it’s the latest version? Yes. We have the dev tailwindcss for the style. And I installed nuxt-space-layer that I created especially for this demo. Nuxt-space-layer is an NPM package that is adding some utilities for my nuxt app. I will later convert it as a module so please don’t use it in the meantime, and it will add vue composable such as vueusersessions, we are working right now on outcome module for nuxt, but so far, you can use it by creating cookies. You can make authentication by creating cookies or using the community modules right now. So, I created a composable that is called usersession, and I have several utilities where I can set user session that’s as simple as this. I have a database helper, so it will use escalating development and D1 in production. I have auto imported of tables that I’m going to show you while coding. I can define my tables in tables.ts, and I have a GitHub oauth handler to handle the authentication with GitHub.

So, let’s try to correct alt tab, so I look like a pro. I will extend this application and basically this is how it look like on the code, it is a nuxt app with the nust.config and the directory, and nuxt will extend this, and I have all data import in my app. So, let’s start development server. What if we create, if we create a drizzle config, I’m using drizzle ORM for my database, and it is creating the migration and the tables from which is, which are empty right now. So, let’s start our application.

So, I want you to choose between coffee or tea 'cause I don’t know what you guys prefer. So, for this I’m going to create two button, so one for coffee and one for tea. Now, manage. I will copy and paste, border p-4, so that’s some tailwindcss, do you know tailwindcss, so I don’t waste our, yes. So, for those who doesn’t know, please explain to your neighbor what it does. It’s a collaborative session.

So, let’s see how it looks like, let say it’s fine. And having, here you go. So, when I click on it I will vote for coffee and when I click on tea, I will vote for, thank you guys, tea. So, I will have a function vote, here I’m using script set up, so I can use the composition API right away, I will have my choice and I will console.log my choice. It’s easier to code when I’m sitting down usually, but that’s not an excuse. So, what I’m going to do is in order to void edit, I need to be able to authenticate it. So, let’s authenticate my user. So, for this I have const loggedIn and user from that user, user session and I can see that it’s a button. So, right here, I will say if I’m logged in, I will say hello user. Userlogin, and a button to logout. Logout, It’s, and I would have it underline. So, if I’m logged in that’s correct, I have a clear to remove my session. Otherwise, I will log in with GitHub to vote please. And, I will add some time.

Okay, so, this button will go to /api/auth, so, if I click on it, it doesn’t exist. So, let’s create this API route. So, to create an API route in nuxt, it’s like the pages five system. We have the same for the server. So, I will create api/auth.ts. And I created the helper to authenticate build GitHub. So, I’m exporting this GitHuboauth eventhandler, and I can have onSuccess, I get my events and my users, my user, and I can return my user to see. Obviously, in order to this function to work I need to fill my environment variable with a session password, so that’s what I detailed in the readme of the layer, the client ID and a secret that goes back to the URL.

So here, look at us 3000. So if I refresh, I can see that because I already authenticated this application, I’m connected. But in order to know and create the cookie for the client side, I’m going to use, set user session. It needs the event, so the event is this, edge 3, we use, we created edge 3 which is our HTTP server similar to express.js and we have, you have access to their current travel, some paras and more goodies. And here I’m setting my user this way, and I’m going to redirect, to send, redirect to my homepage. So, if I, okay, onSuccess, it’s an asynchronous, thank you for spotting this, yeah. So what I have? I’m logging in, sending back to the landing page and if I take my cookies, if I take a look at my cookie, I have nuxt session and the value of it is actually encoded in the next session, password. We are going to have a auth core module that will do the same but will be more secure by giving you the ability to only set what will be public in order to only give the user ID for instance.

But, let’s not waste time here and if I log out, I am logged out, that’s simple. So this, I can see that has to be rounded. Better. What? You saw it too? So, so, if I’m not logged in, thank you, co-pilot was nearly correct. I will throw an error to say you need to be logged in, in order to vote.

So now, what we want to have is the ability to vote, so for this I’m going to create a table, so for this, I will create the votes table. So, I have sqlitetable, sqlitetable, let’s name it votes. And here I can give an object with the ID which is an integer, this is the column name, so it will be the same, and I said it’s a primary key. Then I want to store the user ID, which is also an integer, let’s name it user_id, and I don’t want it to be null, same for the username, but username is a text and the choice which is text, not null as well. What I want to add also is unique index because I want the user to vote only once. So, I want to make sure to have it only once in the database. So, it is a second argument for user ORM, but it’s hard to say. User ORM, so I want to have user id index, user id index which is a unique index, we can name it a user id. Oh, no. Table.userid. So I’m saving. Cool, saved. So, if I take a look at, I would have to restart I think. So, I do have migration which has been created here. The module, we do this automatically, right now I didn’t have the time to do it automatically. And if I take a look at my SQLite database created in data, I can see my vote table.

So now, what I want to have is to return the list of votes. So, for this, if you use this nuxt extension on VS code, you can right click create a new API and let’s name it vote.get, the .get suffix only force the get HTTP method, and it automatically create the defined event handler for us.

So now, I want to use my database. Come on. Where is my auto complete? UseDB. .select I will return, so I want to select everything from my tables.vote, then I want to order them by desc, which is the, how do you say in English? Exactly, thank you. Tables.vote and I give the ID, and I return all, I don’t have the auto import of desc right now so I need to import it this way.

And if I want to test, I don’t know if you have seen this little button, it’s the nuxt Devtools. You can see many things in here such as our components we have, the pages and we have a tab for the server routes. I can get the session, this API has been injected by our layer, but what I want to see is my list of votes, it returns an array so, I expect it to be correct.

So the next thing I want to do is to create the post route to post my choice. So, create a new API, vote.post, and here I’m going to be async function, i will get the body. So here, I can read the body, this is an helper from edge 3. We don’t pause automatically the JSON request for performances reason. So you only read them when you need to. If I don’t have anybody, I will make sure this is an empty object so I can just iterate to get my choice. And here I’m returning, my choice. So, I do have my post requests, so, if I send, I can see that I have nothing here. And it return my body properly. So, what I… Thank you. I know it’s you Alex, waiting for your talk.

So, I will verify my choice and if it’s not, I will throw create error. This is also auto imported to send back the status code 400, bad choice, please choose, really? I will write a sentence right now, between coffee, tea. So, if I send nothing, I have this 400 error with the message. So now, I know that I have the correct choice but I want to make sure the user is authenticated in order to vote. So I can get the session with using require user session, and by having this require user session, it will throw before one, if I’m not authenticated when I do this API request it will automatically forward my cookie as headers and then we can read from it, and see if you can authorize or not. So now, I am authenticated. I can see that. And I will quote again. It works.

So what I need to do now in order to finish the API part is to save it in my database. So, I’m going to also cause useDB.insert. I need the table here. So, tables.vote, values, so that’s the entry I need the user ID which is inside my session, .user.id, I can verify here. User.id, username which is says your user name and the choice obviously. So, drizzle ORM had this type safety for you, so that’s why we had this ugly part here. And what I want is to return and get value and I will return my votes.

You may have seen that the whole nuxt server doesn’t restart is because we are in nuxt 3 right now, and in nuxt 3 we have nitro which creates a worker for you every time. So we, we found a way to separate your client bundle, your app bundle, client and server, and the server part. So, when you change only the server, we restart only the server API part. So that’s why it feels like ordinary replacement on the server.

So, let’s vote again. I have my votes. And if I try to vote again I have this error based on the unique index we created. So, what we can do is on conflict we can update. So, the conflict is based on the table.vote user id. And what I want to do is change my choice. So, I can save, it’s the same id. It’s working.

Okay, now let’s go back to your index page, otherwise, you won’t be able to vote except if you can with your mobile phone to API requests, but, let’s simplify this.

What I want to do here is make an API call to thank you next and type script for auto completing my API route. This is partially through co-pilot, I don’t need to choose string identify, next, we do it for me with the rock hedge. And what I want to do when I post it is to actually refresh, so, what I’m going to list is the activity. So, for that I’m going to list all the votes. Do you know what method I’m going to? Okay, co-pilots. He knows, she knows, I don’t know. Probably she. And I will await next use spent developer to await and only this once we are done doing the data fetching, and I will display the vote, this. So, I’m done with the devtools, thank you.

So now when I’m changing because I can refresh automatically, I don’t need to refresh the page, it will automatically make the API call update votes and thanks to viewer activity, update the template that use this variable.

What would be nice though is to know what is my current vote. So, user choice, computed. And I will note vote.value. Find. So I have my votes, let’s try this if the vote.userid equal user.value, if I’m authenticated.id and I get the choice. Let’s display it here, your choice, coffee or tea? Thank you.

So, let’s make a dynamic class. So, it looks a bit pretty. I think you may have noticed that we don’t have background on hover and I think it looked nicer this way, and it’s important when I had the exclamation mark, but don’t have to do this. I will say board-black if usage, this is quite ugly and you can refactor this later and open the per request. I know you will. And this is tea. Okay, I can do some view and style. Here also think we need to round. Nicer.

So what we have now is we can vote, I have my list of votes, I will simply do a loop here so it’ll be bit nicer vote of votes, and I guess co-pilot will help me. Thank you. Vote.username, voted for user choice. Font, medium. And let’s make it nicer for, this, coffee. Yes.

Last thing I want to do is to pretend it’s real time, so for this, oh, two things, I want to have the total of coffee to know who is the winner, which one is the winner, .value filter v.choice, sounds good. I only turn co-pilot for this demo, usually I don’t use it at Madsan. Thank you. Lee Martin. Total coffee and, I know I’m wasting a lot of time just making, is it total the end to that?

And lastly, pretending it’s real time. So, on mount. Okay, so what I want to do is only on mount I will create a center table, I don’t want to do this on server side even though I’m using the edge rendering, so, it would shut down the, the server side rendering call, but if you use no js, you don’t want to create interval when you do server side rendering for memory leaks and before, on before unmount. Okay, okay, thanks. Apparently, I’m missing this.

So, if we look at the network tab, not that nice and that for the purpose of this demo, we stay like this and if I log out I can see the vote but I cannot vote. So, I created a GitHub repository name coffee or tea and I will say demo should be working. So, I’m going to my CloudFlare account, I created pages project, I linked it to my GitHub repository, in the settings, I added my environment variables to connect with GitHub and may have to change this client secret after the talk. Okay, I know you guys already remember. And I specify, so smart placement is just for me to test. I created a D1 database.

So right now, I didn’t find a way to automate the migration, but what you can do is go to console, open this, those migration in here, copy paste in the console, and if we create the same database as you had in development except the entries, of course. What I have left is connecting this database and name it D1_DB. The layer will automatically connect it in production. And I’m using, I think for the build, the latest version they released last week, the beta 2 that support node 18 npm.

So just running npm run build, we will automatically know that you’re using CloudFlare worker. So we will bundle it as a worker, preset worker, yes. So you can go to coffee or tea that page is .dev or you can normally scan this QR code, I would gives you a minute. I will wait for everyone to vote in order to finish my talk anyway. And hopefully, if this works I will try to vote myself. Go, and now we just broke the Wi-Fi? Okay so, I can vote, okay, it’s working. So definitely coffee is winning. How dare you?

So, what we have now is if I go to my D1 database, I can see that I do have the votes coming in. And the advantage of this is it’s replicated everywhere in the world. So, by just, wow, thanks you guys, by just reading it’s very fast, so what I’m going to show you is another demo, demo I created where same here you can logged in. So this is done not the parade, it also have server side rendering and it actually renders with server side rendering normally in less than a 100, in less than 200 milliseconds, while querying my database.

I also, so this demo here, I played with multiple providers. So, I deployed it to CloudFlare pages and D1, but there resource at Turso, which is same SQLite running on the edge. So, on CloudFlare pages, Lagon, Vercel edge and Netlify edge. So, you can take a look at there source code is the same source code, just environment variable that changes and it works with zero configuration on most of those providers. The advantage of this is I made this API call that is querying my database to list, so, making sure this call is actually calling my database. And you can see in many location around the world it renders in less than 300 milliseconds, no server to maintain, no database to maintain. It just works, so you can focus on building your app.

So, this is working, now, you can see the code is open source under the mighty license on Atinux/coffee-or-tea. The other demo, I also played, oh sorry, this one I think I’ll be done. It’s called Atinux.pages.dev. It’s using CloudFlare KV instead of database. You can double click here and say hello you cof us. I’m using modern here, you cof us. So, it will automatically save the page, have edge side rendering. And here, I can say, woo, it works, baby, and save. If I refresh, my page is here, and I also added this OG image generation working also on the edge.

That’s it, and I think I’m late now. All the code is open source on my GitHub account. Thank you very much.