Evan You chats with us about Vite. How is Vite so fast? What about tree shaking? How do you convert various formats into ESM and what does Evan recommend? What is the future of Babel? And what the first 2 minutes of a Vite project are like?
Time Jump Links
- 01:36 Vite
- 05:59 What's the core part of Vite?
- 09:25 Why is it a different story for production?
- 13:49 Sponsor: WooCommerce
- 16:16 How is Vite fast?
- 18:18 What about tree shaking?
- 22:48 Converting various formats into ESM
- 26:47 What do you recommend for ESM?
- 32:14 What is the future of Babel?
- 37:53 Source maps
- 43:00 Sponsor: Deque's axe DevTools
- 44:49 Writing your config files
- 50:24 First 2 Minutes with Vite
- 54:14 Does it pick up by file extension?
- 58:03 Vite Press
MANTRA: Just Build Websites!
Dave Rupert: Hey there, Shop-o-maniacs. You're listening to another episode of the ShopTalk Show. I'm Dave VF Rupert and with me is Chris VL Coyier.
Dave: How are you today, Chris?
Chris Coyier: Dang it! I was just looking up Vue API stuff because I knew you were going to do it.
Chris: I was going to be like "un-component loaded Coyier" or whatever, but that's not one.
Dave: At click. We've got all kinds of directives, but hey, directive me to the person we're talking to today, Chris.
Chris: [Laughter] Well, we have the creator of Vue himself, Evan You, on. Hey, Evan. How are you doing?
Evan You: Great! How are you?
Certainly, the "bundler market" is a part of that. I say quote-unquote because it's kind of like some of these new tools are not really bundlers or purposefully avoid the concept of bundling. Bundling is what it says on the box, right? Taking files and combining them together.
A tool that on purpose kind of doesn't do that, at least in development, is Vite. It's got lots of press and people excited about it. Dave, you're using it on a project, right?
Dave: I'm using it. I probably poorly explained it here a half a dozen times, so I'm glad you're here, Evan, to explain it better.
Chris: I'd love to just start with that because it's called Vite. The tagline is "next-generation front-end tooling."
Chris: Rather than us explain it, can you do it? I know you've done this before in talks and stuff, but let's do it on the show.
Evan: Sure. Actually, every time people ask me what it exactly is, I find a hard time to find an existent equivalent because it's a little bit different in everything it does to something we're familiar with.
Evan: I think the closest resemblance to an existing tool is Parcel.
Chris: Oh, really?
Evan: Yeah. Parcel is this -- if we look at all the whole bundler scene from the beginning, it's Browserify to -- you know Gulp really isn't a bundler, right? It's just a build tool. But then we have--
Chris: You have to tell it to bundle.
Evan: Right, but then we have Browserify, Webpack, Rollup, Parcel. These bundlers, they kind of all have a little bit of different abstraction levels. Parcel is one of the most -- I would say the scope is the widest. It covers the most features out of the box.
Evan: It also tries to encourage you to use the HTML as your applications entry point, which is a concept that Vite aligns with as well. The biggest difference, obviously, is in that Vite really is not a bundler, in a sense.
If we think about a build tool, so I use a very generic term (build tool) because we work on a mod and front-end project. There's always some sort of compiling going on. Sometimes, we need to compile templates or we need to compile JSX or TypeScript, right? There's always some compiling going on. This is unavoidable.
Evan: But, you know, one thing we've realized is, with native ES modules, the browser has come to have the capability of just serving ES modules as is, and it's pretty fast, pretty performant. For local development, you can serve several hundred modules well within a second.
At the same time, if you have several hundred modules and the bundler has to put them together, sometimes it takes even longer. We've all been through it with Webpack, some of those Webpack days. Everyone probably has worked at least on one project that takes two minutes to startup. It's kind of been a common experience and, in the Vue ecosystem, we've heard a lot about that as well because Vue CR is based on Webpack.
I don't want to knock on Webpack because it's been a great advancement in front-end tooling. It's a great achievement. But the experience we've had is, we have a lot of users who have huge projects, and they were like, "Oh, my project takes two minutes to startup and every hot module replacement takes three seconds."
Evan: Right? This whole feedback loop is just getting brutal. If you're trying to make a simple change and you have to wait several seconds for something to update on every change--
Chris: No good. Is that the core thing? Is the core thing, let's stop bundling in development? Is that the biggest part of all of this?
Evan: The core thing is, is there a way to do less during development and get closer--? To leverage more some of the capabilities that we expect in the pure bundler era is that the browser is kind of dumb. It can only handle simple script tags. It only has global scope, so we have to do everything, handle all the module stuff before we send anything to the browser. But now, the browser has a module system, so how about we just let the browser do that?
That's the idea, right? Because we've seen that a lot of the -- I mean I personally worked on higher-level tooling on top of Webpack and it's complicated as hell. At the same time, I keep thinking all these things we've been doing, if I just write it -- so, given there is ... in the browser already, I can probably simplify this by a whole lot. That's kind of the driving idea behind it when I first started experimenting with....
Chris: You lucked out in a way that browsers in ES modules is super-fast.
Evan: Yeah. Yeah.
Chris: It just wants to be fast, which is nice. If it wasn't fast, maybe this wouldn't work.
Chris: You even said the metrics are -- you can even get up to hundreds, you were saying, hundreds of modules and it's still fast, still good.
Evan: Yeah, there are a lot of optimizations that you actually have to do to avoid having too many modules. Most importantly, because you're still sort of fetching these modules over HTTP. Every request has an overhead. In local development, even if you use HTTP2, an actual request is still a lot more overhead than just reading from disk directly. But typically, we can get the total modules down to a reasonable amount where, even for huge projects that we've tested in real world, it's still overall a better experience than, say, the Webpack equivalent.
Chris: I'm curious then if the browser -- if in dev, not bundling and leaning on ESM is so fast, why not production then too? Why does it have to be a different story for production, at all?
Evan: For production, the story is network latency. That's the whole difference. Because you're doing local development, there's literally no latency at all. Everything is on your disk. But if you ship this to production, then you have a whole different category of problems. The first is the change network waterfall because you will have ES modules and A imports B imports C.
The way it works right now is, if you don't have any sort of resource prefetch and hints, the browser will just fetch A. Once A is fetched and it parses it, then realize, "Oh, I need B," then it parses B. Then it fetches C.
Chris: Yeah. Right.
Evan: It creates this--
Chris: It's a waterfall.
Evan: Yeah, and the waterfall kind of compounds with the latency. If you are a slow network on the phone, this just causes a lot of problems. You have to -- optimizing this is sort of tedious.
Evan: It has to do a lot with -- I don't think there is a really mature way to completely automate this yet, even with HTTP2. Another aspect of this is caching because individual module caching is sort of -- it's kind of a dilemma because you either fingerprint these files or you don't. If you don't, then you can't really cache it locally. You cannot use strong cache headers. You have to always hit the server to revalidate. But if you fingerprint, then you're essentially involving a build process, which is actually also pretty complicated.
Chris: Yeah. You'd think it would have to change the actual HTML that's requesting it or the script.
Evan: Yeah. Yeah.
Chris: Do you push those? Do you un-waterfall the waterfall in dev? Do you smash all the imports up to the top level and let them all happen at once?
Evan: The waterfall is actually almost negligible during dev.
Evan: Typically, it's only a few levels deep, right? Because it's local, the latency is literally one millisecond, so in most cases, you won't even notice it. But in production environments on a phone, it can be up to a second or two seconds. That can be pretty brutal.
Chris: That's not going to change in the next anywhere near soon. Network latency is just a fact of life. It's physics, right?
Evan: Yeah, and it depends on what market you're targeting. If you're targeting pure 5G, it's probably better. But if you're targeting developing countries with slow network providers, then it's a whole different story.
Chris: It seems like that'll be true for--I don't know--at least a while that, you know, don't bundle in dev; bundle in production. Vite seems well placed for years to come.
Evan: Yeah, there are obviously folks working on the platform, the Web platform, hoping to enable production capable unbundled delivery. I think one thing that import map kind of has to play with that a little bit.
Chris: Import view from Vue is invalid ESM is the problem, right?
Evan: Yeah, that's one thing, though. Import map also kind of helps with caching.
Chris: Oh, it does. Okay.
Evan: Yeah, because you can actually move the fingerprinting process into the import map. Let's say you have A, B, C--
Chris: Oh! Really?! Cool.
Evan: Your files can remain un-fingerprinted, but you move the fingerprinting into the import map, so the import map is in your HTML. You request the HTML, which always revalidates, but then the import map will actually fetch different resources.
Chris: It reminds me of service workers, how you have to ship a new service worker when you invalidate certain caches and stuff.
Evan: Yeah, I guess everything is simpler than service worker.
Chris: [Laughter] Everything is simpler. That's what we'll call this episode. [Laughter] No, probably not.
[Banjo music starts]
Chris: This episode of ShopTalk Show is brought to you in part by WooCommerce. WooCommerce is an e-commerce plugin for your WordPress site. Super, super popular, I'm sure partly due because WordPress is really popular, but also because it's awesome. It's a really good e-commerce plugin that you can do tons of stuff with.
I use it. I've used it a bunch in the past. I'm using it right now as the store on CSS-Tricks, which is probably not like one of these stores that has 10,000 projects. It's not exactly stretching the limits of what WooCommerce can do, but it does one cool thing. Well, whatever. It does a bunch of cool things, actually.
One is for actual, physical products I sell from it, right? I sell digital stuff too, but we make some posters that get printed and sold, and a sweatshirt, which is a very nice sweatshirt that I think is cool.
I don't have a bunch of preprinted sweatshirts here in my office that I package up and send to you to when you order it. I could set it up that way. That'd be no problem, but I was hoping for easier.
One of the things I do is use a print-on-demand service. The one I happen to use is Printify, which I think is fine. They do okay, but there are other versions of it. They're not the sponsor here. It's about WooCommerce. What's cool is that the integration is so tight, so you order from my store, you never leave my store, and a poster, a sweatshirt, or whatever shows up at your door thanks to the integration, which is pretty cool.
There is a thing I had to troubleshoot the other day that was weird. I thought that it would be nice if people got shipment notifications. But that would be Printify's job for sending it, not WooCommerce. It doesn't know when it sends. I just had a setting wrong, so if this ever happens to you, please reach out to me because I will fix it for you.
There is an aspect of WooCommerce where you can add notes to an order after it's done. There are all kinds of different types of notes that have different colors. Then there's a setting that says, "Do you want to email the customer when you update the order with a note of this type?" I had it to off for who knows what reason.
Printify did actually the smart thing where they would update the order with the tracking information for the order. It just wasn't working, wasn't working, wasn't working. Then that's when I found the setting. I flipped it on and, oh, thank god. Now all my customers, when they order something, you get an email about your order that has the tracking information the second it ships. It just feels so satisfying to have that solved, so thank you, WooCommerce, for making that ability nice.
[Banjo music stops]
Chris: Very cool. There are so many aspects of this, speed being one of them. It's not just this leaning on ESM locally, right? There's also this, other than Vite, everybody's favorite thing is esbuild and you're leveraging that, too, right?
Evan: Mm-hmm. Yeah. Yes.
Chris: Are you buying some of the speed from the fact that Go is involved?
Evan: Yeah. ESbuild is definitely a big factor in what makes Vite fast. The idea, going back to our previous idea, you know, going full unbundled, Vite isn't truly full unbundled.
Let's imagine you have these ES module dependencies like lodash-es. This module alone, if you import it just using a named import like import debounce from Lodash, this thing alone is going to pull in 600 modules because the main entry points of lodash-es actually imports every single utility it contains inside of it.
Sadly, the browser doesn't really know how to do tree-shaking. [Laughter] So, essentially, it has to just parse and fetch everything. In my early testing, when I was testing out the idea, I was like, "What happens if I input just load import lodash-es?" It takes a whole second for the page to load by just importing it. That's obviously not ideal.
Chris: Who is tree-shaking? Is esbuild tree-shaking or is it your own magic, Vite's magic?
Evan: There is actually no need to do tree-shaking, but we need to do pre-bundling. The idea is, we squash all these 600 lodash-es modules into one thing. People would be like, "Oh, now we're going back to bunding." But the idea is, your dependencies probably don't change very often, so Vite kind of separates your code between your source code and your dependencies.
Your source code probably changes every day (when you work on it) but your dependency, once you install it, once your lock file is there, as long as your lock file doesn't change, we can assume your dependencies did not change. Unless you were to manually edit it, but you can force validate the cache if you want to.
The idea is, we use the lock file as sort of a cache freshness hint. Once we pre-bundle a dependency once, then we're good until the next time you install something else.
Chris: That seems like -- I mean not that you want to -- this is what Snowpack does, too.
Chris: They've been hot on this idea.
Evan: Yeah. Yeah, so Snowpack had this. Snowpack version 1 was actually exactly that, something that converts CommonJS into ESM. They turned it into a standalone thing called ES Install, now, which is Rollup-based. The early version of Vite did almost the same thing. We used Rollup as well because we already used Rollup for production.
The upside is, you only do this one, every time your dependency cache invalidates. But if you have, say, a huge project with some crazy dependencies like material UI, a whole UI framework, these UI frameworks typically have hundreds of modules as well. It can take a couple of seconds to pre-bundle, even.
In my personal development, this was before Vite 2, I was using Vite 1, which was doing the pre-bundler with Rollup. This is probably the only part that I felt like, "We should probably improve this," because it still reminds you of the bundling days where you have to wait for something to startup. It's just less often.
I actually opened the issue to ask for a standalone transform API from Evan Wallace so that I could use it in Vite. After using it for just transforming individual modules, esbuild became a lot more mature in bundling libraries. Once it had this capability of doing multi-entries, I realized, "Okay, it already has the capability to do what I was previously doing with Rollup to pre-bundle the dependencies," so I started experimenting with it and was able to completely switch the whole pre-bundling process to use esbuild under the hood. That dramatically improved the startup speed.
Chris: Yeah, I bet.
Evan: Even with cold cache, typically. I'm on an M1 and I was running the non-M1 optimized version of esbuild for a very long time. I did huge projects that take 30 seconds on an M1 Mac to pre-bundle with Rollup. Now with esbuild, it's like 1.5 seconds.
Chris: Whoof, 30x, almost. Pre-bundling seems interesting. You get this dependency ready and then just leave it alone because you've already bundled it. Even though it's 1.5 seconds, still you only incur it once, which is wild.
But then there's also this -- to me, a part of the story--and maybe I'm just wrong, but it seems like it--is that a lot or most of NPM isn't ESM ready. It's like whoever wrote it, they didn't write it in that way.
Chris: Something has to smurf it together to make it ESM ready.
Evan: Yeah. Exactly, yeah, that's another part of it. Yeah. You need to convert all these wild formats into standard ESM. It's actually really tough.
When I was testing this new pre-bundling stuff, I literally get incompatibility reports every single day. I think I kind of appreciate all the work tools like Webpack does in handling all these wildly contradicting usage of package formats. [Laughter] We have all these non-standard fields impact JSON like browser field, module field, jsnext, and now we have conditional exports.
The community just can't seem to agree on how to actually use these fields. It's like we come into these situations where this package expects these fields to work this way, and that package expects it to work that way. The tool can't accommodate both at the same time.
In those cases, we have to either ask the user to alias it to the correct entry or we have to have these internal hacks where, say, one of the hacks we have to do is a package that has the browser field and the module field. Some packages ship ESM for both and expect the module field to work in Node and the browser field to work in the browser.
Evan: Some packages, they ship UMD files in the browser field and they ship browser-oriented ESM in the module field.
Evan: The tool, Vite has to basically make its best guess at what the package author actually means. Because these are not actual standards, you can't tell people, "Hey, you're just using it wrong." [Laughter] It's kind of wild west in how to define, especially shipping a package that has multiple formats like UMD, CommonJS, ESM. What makes it worse is Node shipped in native ES module support, so a lot of packages now say, "Oh, we support ESM," but what they're actually doing is having this file that imports from CommonJS then re-expert everything on ESM.
Chris: You mean they didn't offer it that way? They just shipped it through two tools? [Laughter]
Evan: The reason for them to do that is because Node recommends it because it avoids a problem called dual package hazard. Essentially, if you ship your ESM and CommonJS as separate copies of modules, it's possible (in your application module graph) for someone to require your module, someone to import your module, and these would end up with different copies of your module.
Chris: Oh, no!
Evan: The way to avoid that is to make your ESM entry point just a proxy to your actual CommonJS copy.
Evan: But that breaks compatibility with browser tooling because we expect -- if you are declaring your ESM, we expect you to be ESM all the way through, instead of just proxying to CommonJS again. There are all these wild things that I discovered while trying to make everything work.
Chris: Yeah. That sounds like "throw your computer into a volcano" kind of stuff, to me. That's terrible. You know this stuff really well, so I'd love to be like, "Here is our recommendation. If you publish something to ESM, do this because it's good for everybody." What is "do this"?
Evan: It's actually tough. I think you should probably start your package directly with conditional experts field since I believe that's -- you know the situation with module fields and browser fields is, there are so many established conflicting usage that a lot of tools have. Webpack has its own thing. Rollup has its own thing.
We're essentially relying on de facto implementations as reference points, but the exports, conditional exports field is something that is probably documented and spec'd in NodeJS. This is something -- we have an opportunity to say, "If all future tooling converge on this, then we have this unambiguous way to figure out what you should resolve to," unlike previously where every package ships like these main, JS, Next, module kind of package, unpackage, browser - you know, all these fields. [Laughter] Conditional exports doesn't make this any simpler, but at least it's a new opportunity to de-ambiguate all this stuff, I guess.
Chris: Is it the field that's just called "exports" in package.json?
Chris: You refer to it as conditional export?
Evan: Yeah, it should be just the exports field, yeah. Conditional exports is one of the features it provides.
Chris: Okay. Yeah. Yeah, we've been messing with that. That's interesting. And we don't really have any advice. Good luck. The advice is, "Good luck."
Evan: [Laughter] Yeah, it's tough because shipping it correctly, especially if you have an existing project, adding exports field is sort of risky because it will probably break some existing tooling that expects to work in a certain way.
Chris: I guess if it works for you, though, maybe you can just be like, "Then don't use Dave Carousel. Dave Carousel only--"
Isn't there a world where you write ESM, you ship ESM, and you just stop caring about anything that isn't ESM? [Laughter]
Evan: Yeah. I mean if you're shipping pure browser-oriented libraries and you're like, "I don't support anything that expects CommonJS for the browser," then yes, I would actually recommend that. You should just ship plain ESM. Then you just tell them, "Hey, I don't have CommonJS."
Evan: The problem is, a lot of times your library probably, with all this server rendering stuff around, people expect your library to be usable in NodeJS, and NodeJS kind of complicates the scene because it kind of supports ESM in the latest versions with a lot of gotchas, but in earlier versions if people are stuck on, say, Node 12, they don't actually have proper ESM. They'd be like, "Hey, you need to ship a CommonJS version of your lib for it to work in my server-side rendering projects running on Node 12." It's a tough job for library authors to support all that stuff.
Dave: Do you think you're rounding the corner on supporting that stuff in Vite, or are you still hitting those issues day-to-day?
Evan: I think we're pretty good now, since we're seeing all these people reporting, migrating their existing projects to Vite without much problem. We still run into a few edge cases here and there, but it seems, for the most common cases, it's working fine. It still handles both CommonJS and ES modules. It allows mixing both.
It does a very decent job at that already, but there are some really, really weird cases where, similar to how the case where you have a dependency (A, B, C) and B requires A and C imports A, both thinking they are requesting the same module, but one is imported and one is requiring it. Sometimes, it confuses esbuild. Yeah, things like that. But we found hacks, workarounds.
Chris: Do you have any if material design or if ant design code in Vite?
Evan: Um... Actually, not yet. I think I was able to remove most of them.
Evan: I had a special case, Babel for one case, and was able to remove it after I reported the request to esbuild and it got fixed. I mean it got shipped.
Evan: So, I was able to remove that special condition. Yeah. But, yeah, Babel, that was the thing I was talking about is Babel 7.13 added a different set of exports field to its Babel helpers package.
Evan: Which broke a bunch of things and they had to release six or seven hot patches just to fix all the stuff.
But then people are like, "Um, but what about JSX?" or whatever, like I have Babel do that. What are the things remaining that we need it in? Are its days numbered or will it just be useful forever? What's up?
Evan: I think Babel is because it's not a single purpose tool, it's a whole co-transformation infrastructure, so people use it to do all kinds of different things like JSX, even TypeScript. Some use it to transpile for legacy browsers. Some people use it for using experimental syntax or macros that they write themselves, right? All these are different use cases.
If we separate them into three categories, one is standard transformations like JSX or TypeScript. These are spec'd. We all expect them to transpile to more or less the same thing. Tools like ... or esbuild can already do this and can do it 20 to 30 times faster (maybe even more) than Babel.
Then there is transpiling for legacy browsers. For transpiling legacy browsers, there is no point in doing it in development. Why would you, unless you are trying to test on an actual legacy browser? You should avoid it as much as possible and only do it for production testing.
Then there is macros or future syntax. This is the part where I think Babel will still be very valuable because I think the concept that development -- front-end development, especially front-end developers, they're more comfortable with working with compilers nowadays. So, a lot of people are coming up with these ideas, especially in the CSS JS scenes, people use Babel to do these crazy write CSS and JS, but compile it into something different, extract it away, or you can do things like stage three proposals. I want to use it, I want to use it now, but browsers don't support it.
These are, I think, still valid cases. But if you are only doing, say, JSX or TypeScript and you are only transpiling for legacy browsers, then I believe you don't really need Babel in the future because there are faster tools and there are better strategies to deal with this.
If you just stick to, say -- and we also transpile syntax down to ES 2015, so essentially, if you are just -- unless you're using something that are features that are not simply syntax transforms, then you should just be good.
Chris: Does it leave your async/await alone?
Chris: Does it leave your spreads alone? Yeah, that's probably--
Evan: Yeah, so you need to be aware of that. Spreads can be turned into syntax transform. You enlighten a helper and then turn it into a call, which esbuild already does. These are kind of covered.
You do need to be a little aware, but it's much better than, say, having to configure all these Polyfills and stuff for no good reason.
Chris: If you want to put Babel in, can you do it in Vite?
Evan: Yes, of course. Yeah.
Dave: Vite does some other stuff, right?
Dave: Like Vue, right? That's not--
Chris: Isn't that a Babel plugin? How do you turn a .vue file into whatever it turns into?
Evan: That's not a Babel plugin. Vue has its own compiler called the SFC compiler (single file components compiler). Both Vite 2 and Vite 3 has a package that's dedicated for parsing and transforming single file components.
Vite has a plugging system, which is inspired by Rollup. It's actually a superset of the Rollup plugin interface. If you are writing a Vite plugin -- if you already know how to write a Rollup plugin, you kind of already know how to write a Vite plugin. There is the resolve ID, load, and transform. That's the three main hooks that you need to know and you're good to go.
Vite plugin Vue is in fact just a port of Rollup plugin Vue with a bunch of Vite-specific tweaks to make hot module replacement work.
Chris: Oh, nice.
Dave: Then you do source maps and stuff like that, too? When I open dev tools, I see the Vue file, actually. [Laughter] I was like, "Wait a minute? How?" You know?
Evan: Yeah. We do ship source files as well.
Dave: That's pretty cool. For me, the development experience is like -- we talked about this a bit on the last show, but it's been so long since I've been in a project that had working source maps. [Laughter] We're you're like, "Oh, I actually can see," and I feel like it's part of this tooling where the delta between what I'm loading in my Vite app and then what is getting transpiled or code mod'd or whatever, that delta is very low. It's just one file to one file, more or less.
Evan: Yeah. I think what makes a source map finicky in a lot of projects is just how long the built pipeline is. Any step in between the transformations, there is one tool that just forgets to return the source map or messes it up, and then it just breaks everything.
Evan: Yeah. It's kind of -- I don't know. Working with source maps, I think the biggest problem is source maps doesn't really have a very easy-to-understand explainer of how it works. It's kind of always this really mysterious thing and you always kind of have to do it with trial and error. Major bundler authors, I think Tobias, who worked on Webpack, Everette Wallace who worked on esbuild, they all built their source map visualizer just to be able to figure it out how it works.
Chris: Yeah. It's not like you open dev tools and it won't even tell you, "Oh, it looks like you're trying to load a source map but you have the syntax wrong." It won't tell you. It's just not there.
Chris: Then if there's something wrong with the source map, it's not like it says, "Oh, on line 12 of your source map there's a syntax error, so we could only parse this part." It won't tell you shit.
Sorry, I should swear. [Laughter]
Evan: Yeah. As tooling authors, it's not pretty fun either. The thing itself, you can't read it. It's like Bay 64. Well, it's a special format. It's not humanly readable, so you kind of have to build some tool to be able to understand, "Oh, I'm actually generating this line wrong." It's not something like when you're debugging; you can put a debugger statement in there and figure out, "Oh, I actually have this line offset by one." You can only trial and error this until it works.
Chris: It's nice that you get it because then, at the end of the day, the DX is really good, right? Now you have this really nice map that maps to it. That seems like the story overall here. If I can make this really fast, the DX is good. If I can ship production projects that make really smart decisions for me and are tree shaken and bundled intelligently and whatever kind of magic happens, all my production story is good too. That's awesome.
Evan: Yeah. I think that is what Vite -- I guess that's why I call Vite a bit opinionated in the sense that it actually sort of packs in all these recommendations or best practices that we kind of learned along the way in Vue CLI. For typical users, we realized, okay, you will most likely want this, so let's just provide it as the default. I think that's what Parcel also does really well.
The reason a lot of people like Parcel is because it's opinionated and works out of the box. A lot of the stuff that you think, "Oh, I need -- if I import CSS, it should do this. If I import TypeScript, it should do this." A lot of stuff just works.
That's kind of the result if you are doing, say, with Webpack, right? People already kind of come -- today's developers, they already come with expectations because most of them started using Webpack with a higher-level pex tool like Create React App or NextJS, NuxtJS, or VCLR. A lot of these common conventions between these major higher-level tooling (or meta frameworks) people just nowadays they take it for granted.
In a lot of cases, we should make it just work without having to force everyone to say, "Okay, to get this working, you need to first install B. Then this, this, this, this, these loaders, and then write your config file like this. Then, voila, you can have this basic project running," right?
We don't want to force people to go through all that again because we, as a community, have gone through this all together and we are like, "Okay, this is where we're at now. Let's just sort of bake it into the tool."
Evan: Then make it just work out of the box.
[Banjo music starts]
Chris: This episode of ShopTalk Show is brought to you in part by the makers of axe DevTools. Literally, it's like a dev tools plugin you add to your browser so that when you open the native dev tools, there's an axe tab there and you can run tests. It's really good.
I just did a video with Preety from there on CSS-Tricks, go watch that if you haven't because we really dig into all the possibilities there. Pretty amazing.
They just launched axe DevTools Pro. You can try it for free for 14 days. Otherwise, try it 20% off with promo code shoptalk.
What it unlocks for you is it makes that plugin way better. It has these things in it called Intelligent Guided Tests, which you have to see. There are amazing accessibility things that you can test, but it has to walk you through some stuff because it has to ask you some questions and gain some insight to what's happening on your page, which is stuff that a purely automated test isn't going to catch but is super vital for the accessibility of a website.
You probably didn't set out to build an app that was purposefully inaccessible. None of us do that where, like, "I'm going to make a crappy, inaccessible site." But you probably did. I run it on my site and I'm like, "Whoa! There are some problems here. Oops, I guess I better fix those."
You didn't set out for problems, but you still need to fix them. The axe DevTools Pro browser extension helps you find them and you don't have to be an expert at all about accessibility. It's that helpful, so start catching and squashing these accessibility issues as you code.
Friends don't let friends ship inaccessible code. Follow the link in the show notes or just go find axe DevTools Pro and use the code shoptalk to get it.
[Banjo music stops]
Dave: You're providing plugins like Vite. Obviously, you work on Vue. Vue is like a first-party or, I guess, maybe this is the perfect example of a second party thing. [Laughter] But it works with JSX. It works with React. You can kind of build these projects in it as well.
It's not just limited to the Vue ecosystem. You're just a translation layer, as I'm understanding it. You roll up translator on top of esbuild that is very, very fast and has a Web server packed in - sort of.
Evan: Sort of, yeah.
Dave: I'm getting too simple, probably. But I don't know.
Webpack was very useful for a very long time and still useful, but you kind of just write your config, cross your fingers, and pray to God you never have to change it again. [Laughter] All this stuff happens kind of behind the scenes. The code you wrote dramatically changes. Now, it just seems like it's slimmer and a new way to build sites.
Chris: What are the changes you need to update your Vite config? Is it low? Is the goal to the be like most projects don't need to touch it at all?
Evan: I would hope so. I think, especially for -- I would say for 80% of the projects, if you're just common, you know, typical React or Vue projects, your config file should be pretty -- I mean the default config file should be pretty good. Some of the stuff people will probably use is just like common pay VSCs, you know, setting the public path, the base option. These are straightforward. People already know what they do.
Some of the more, crazy config files I've seen are people who like to write their own plugins. People really have different ways of using stuff. Like early adopters, they -- I don't know. [Laughter] They like to abuse the hell out of these tools. I've seen people report issues with a simple project, but they rolled like five custom plugins just so that they can get it the way they like. Some users are like that, but I believe, for most users, it should be just a pretty suite out of the box experience.
Chris: How about -- I want to do that, the first two minutes with Vite thing, but I have a question about mono repos. Is it healthy there? Is the config cool that it will reach up and out to another folder at a higher level? Is it cool with that? [Laughter]
Evan: Yeah, it actually works with mono repos, right? One of the limitations when we first started working on a native ESM dev server is we realized, okay, if it's just a simple HTTP server, you can only serve things inside your current directory. If you're importing to a sibling package--
Evan: --how does it do that, right? We figured it out. [Laughter] We do some sort of weird thing to rewrite your URL so that it's like, oh, the dev server knows you're actually requesting a file out of the root directory.
Evan: We are able to resolve and load it. Then we do a lot of--
Chris: I see some trickery with that module syntax, too. I imagine it's similar to that, right? If you request from /@module, it does some fancy crap.
Evan: Yeah, so if you request an out of root file, it gets turned into something like /@fs/absolutefilepath.
Chris: Fancy. Well done.
Evan: Yeah, and then the dev server knows all of this should be resolved from the file system. It applies all the same transforms. We also do some SPAR heuristics so that we know, "Oh, this is a linked package in a mono repo instead of inside Node modules," so we will not pre-bundle it because you probably expect it to work in its source code format. You may even edit it.
Evan: So, the common practice for that is, if you have a mono repo where you have Vite in one of the packages, one of the packages is a Vite project, but it imports all these sibling packages as dependencies. You just alias all these packages to their source file instead of the build distribution file, so when you say, "Import foo," which is a sibling package, you're in fact importing foo/source/index.ts or something. Right?
Chris: Okay. Okay.
Evan: Then it'll just work like normal source files. If you edit a sibling package, it even triggers hot module replacement.
Chris: Oh, that's so cool. You kind of maybe don't even need lerna.
Evan: Yeah. I mean lerna does a lot of other things.
Chris: I know, but that's the one that makes the sim links for buddy packages. I use it just only for that and it'd be cool to get rid of it.
Evan: I use it -- I think people have used Vite with yarn workspaces, with pnpm workspaces, and it kind of just works.
Chris: It just works.
Chris: Good. Okay, the first two minutes with Vite, let's say it's a Vue project. You said it's parcel-like, so you make an index.html file. At the bottom of the body, there's a script source and it says ./script/index. Do you just write .vue right in the HTML? Like in Parcel, if you're writing Sass, you just make your link tag to a .scss file and it just knows what to do. So, it makes some alternative version of your index.html file and puts it in a dist folder that's already been trans--?
Evan: Yeah, so here's the smart part, right? We parse all the script tags in your HTML. Then we rewrite the inline script into a script source=/htmljsproxy? blah-blah-blah, right?
Evan: Then the server knows, okay, this is actually -- so, what it does is just moves this inline script into an actual ES module.
Evan: Then apply the transform just as everything else. Yes, you can import .vue inside your HTML in the inline module script if you want to.
Chris: Inline module script. Wow, that's while. Yeah, it just knows what you're doing. Then you better remember to import Vue itself, too. Right?
Evan: Yeah. If you import from Vue, then it just knows it resolves to the Vue in your Node modules.
Chris: Nice. Then there's a dist folder with an index.html file in it that's been all transmogrified. You don't even need to open that because your Vite server is already running, right? So, you just hit the localhost.
Evan: Yeah. I think the goal that we're trying to do here is, although there is a lot of magic going on under the hood, the experience is very akin to a simple HTTP server you're starting.
In the early days when we were working locally, we were just creating an index.html to fire up the HTTP server. Then, you know, refresh every time you say and we're good, right? That's the early days of development.
Evan: You edit some CSS. You refresh. Add the CSS, you refresh, and everything is kind of snappy and fast because, in those days, we don't do all these crazy transpiling, bundling, and all this stuff.
One of the goals, just the personal goal for me with Vite is to bring that experience back. When you want to start working on something, you just fire up a server with an a-.html and everything kind of just flows from there.
Evan: I believe we can do that with Vite today, right?
You wouldn't call it hot module reloading. You'd just call it style injection, I guess. I don't know what you'd call it.
Evan: Yeah, it updates your CSS without reloading the page.
Chris: Very cool. Love that.
Evan: With link tags as well, yes. The link tags also work with preprocessors.
Chris: Okay. Which ones do you get out of the box? Sass, Less?
Evan: Sass, Less, Stylus. PostCSS is included by default, so if you want to use PostCSS, just add a postcss.config.js and you're good to go. If you want to use Sass or Less, just install Sass or Less itself. There is no need to install a plugin for them.
Chris: Oh! Cool. Then it knows by file extension? That's your hint to it that tells it what to do?
Evan: Yeah, that's the conventional part. Vite is indeed a bit opinionated in how you expect these things to work. If you import .scss, it should SCSS syntax. Also, if you import JS versus JSX, Vite insists that you separate them because otherwise, we would have to guess JSX for all the JS files, which will require unnecessary transforms.
Dave: I saw you tweet about that. I thought that was A) a bold decisions, but B) it make sense because JSX is so kind of fundamentally different from what it has to do. It incurs extra processes, so it just seems like, yeah, it should have its own extension.
Evan: Yeah. I just find the practice of putting nonstandard syntax in a .js file problematic. It works if your whole organization assumes that. if you have an organization-wide tooling infrastructure that just assumes .js will contain nonstandard syntax, then fine because you're Facebook, so your JS file probably always contains something nonstandard.
Evan: Flow, JSX, right? They put all that stuff in JS, but if you are a community ecosystem tool, we can't assume that because a lot of times we expect .js to just work directly in the browser without having to transpile it.
Chris: I'm on this thing right now where CSS modules is actually not a nonstandard syntax. It's just what happens to it once it's imported does fancy stuff, but the syntax itself, for the most part. I think it has one or two little fancy crap things it does that's nonstandard.
Chris: But the file extension is often just .css.
Chris: But I was on a Next project and they were like, "No! If you want CSS modules, you have to name it .module.css, otherwise--"
Evan: Ah, yeah. Vite does that too, actually.
Chris: Oh, yeah. Good. I like that. I was like, "Oh, then I'll have to go back and change a bunch of old crap in my project." But I was like, I'm glad to because I think it's more clear. I think it's more obvious to people coming to the file like, "Oh, that's what that file is."
Evan: Yeah, and that's the part where I always say it's opinionated because--
Chris: Because it's a good opinion.
Evan: We don't see -- unless you have a really strong reason that--
A lot of times, people will open requests like, "Because I prefer to do it the other way." I'm like, so... But is it worth adding an option for it or making this whole thing configurable? Then if we make everything configurable, then we're just back to Webpack, right?
Evan: Yeah. There is a challenge in this because ES modules kind of brought this onto itself, like, "We have MJS and NodeJS and all that stuff."
Dave: Yeah. Yeah.
Evan: But I still think if you are shipping some code for front-end, just let the extension be explicit about what it's doing in there. The tool can make--
You know, if you just follow the simple conventions, just name your extension properly, then the tool will handle most of the other stuff for you. I think that's a good compromise. That's a good tradeoff, in my opinion.
Chris: Happy path. Go with it. That's what I like.
Dave: I want to talk. I know we're kind of running out of time here. I want to talk about Vue 3 because that's something that has launched since the last time we talked. Is Vite starting to make its way into the Vue ecosystem? I think VuePress or you're working on a version of VuePress with it or will Nuxt ever get it?
Evan: Yeah. VitePress is this VuePress alternative built on top of Vite. In fact, I built VitePress and Vite almost kind of in parallel because one of the big drawing factors for me to work on Vite was, I was working on all these docs and I was fed up with how slow VuePress was, which was Webpack-based. I'm like, "If I can just swap this with Vite, my life would be so much better."
So, yeah, I built VitePress and I'm pretty happy with it. If you're writing new documentation, you should definitely check it out. It almost has all the things that VuePress can do, but it's lighter, faster, produces smaller sites. Obviously, it's simpler. It doesn't have plugins or all that stuff, but it's pretty flexible.
For Nuxt, the Nuxt team already has all these crazy, experimental integrations, so they made this bundler part swappable, so they already shipped something that allows you to use Vite in Nuxt too.
Evan: They also already showed me an experimental version of Nuxt 3 running on Vite. I think there are some tradeoffs involved in there because Nuxt makes certain assumptions about how the server-side stuff works. Vite actually ships its own server-side rendering support.
Yeah, I didn't -- I should probably mention this, but Vite, as a scope, it also has this server rendering capability that allows you to load your--
Because you are now writing ES modules and all these Vue files, JSX stuff, and if you expect them to work in Node for server-side rendering, typically, in our days with Webpack, you have to bundle Webpack for a client, bundle for a server. Then you need to re-bundle both (whenever you make a change). Vite does this thing by converge, like transforming your client-oriented modules on the fly, load them in NodeJS and memory, maintain this graph, and then do this in-memory replacement (kind of like hot module replacement) directly in Node.
So, this whole thing, this is like what Rich Harris came up in his exploration for Svelte Kit, so I felt that's a good solution to improve the DX for server-side rendering-related projects. So, I implemented in Vite, and now Rich is moving Svelte Kit to be built on top of Vite.
Dave: Oh, wow. Awesome.
Evan: Yeah, so I think that's some really cool collaboration that's going on here. Rich actually already submitted a few PRs to fix some server-side rendering latest stuff in Vite as well. I expect to see some cool stuff coming out of the Svelte team as well.
Chris: Nice. Nice.
Dave: Yeah, that's cool that it can -- I don't know. It could support now two frameworks or two different front-end libraries.
Evan: Yeah, the server-side rendering is a pretty generic implementation. It works with React, Vue, Svelte, or other stuff like I know SolidJS is also doing a Vite-based template. I mean if you want to get Preact rendering in there, it probably will work too.
I think it's a good -- it's just something that I wanted myself, right? Just a no-hassle server rendering environment that's fast and, at the same time, we managed to make it framework agnostic, which I think is a good thing.
Chris: Yeah. Yeah.
Dave: That's awesome. That's awesome. Well, I know we're kind of at time here.
Chris: Yeah. We have 30 seconds left. Let's talk about Web components.
Dave: Web components.
Dave: Do they work? Anyway, I do have Web component questions, so I'll just gently throw those in the trash.
Dave: Vue 3 is out. People should use it. I guess that's what you would say, Evan. Is that right - high level?
Evan: Yeah, if you are starting new projects then by all means go for Vue 3. It's just smaller, faster. You get better TypeScript support. Yeah, and you get to play with some of the experimental stuff that we've been brewing like script setup with composition API.
We haven't really heavily publicized it yet, but some early adopters have been running it in production and they are super happy with it. Yeah.
Chris: I remember there was an idea. It was experimental in Vue at one point. Then I became really bullish on the idea (although it's gone nowhere) which is the ideas that all state should be mapped to CSS properties. You shouldn't have to ask for that to happen. Any state that you declare should just be a CSS property, custom property.
Evan: That's actually a thing. There is an RFC for it. Inside a single file component in the style section, you can use -- I need to double-check, but I think we add this special V-bind thing in your CSS, so you can just bind state. Yeah, it already works, so you can try it out in a Vite project. If you start a Vite Vue project, it already works. It's marked as experimental, but it does work.
Chris: Sweet! Sweet! I think that's a good, good, good idea.
Dave: Well, cool. Yeah, we'll just end it here. Thank you, Evan, so much for coming on the show. For people who aren't following you and giving you money, how can they do that?
Evan: Yeah, you can. There's a supporting link, supporting Vue page on our website where you can learn all about the sponsor info or you can find me on GitHub. I have GitHub sponsors. I'm also on Patreon. Or Vue has an open collective and then we have all these team members who also have their own GitHub sponsors. If you use one of their projects and you think it helps you, please consider donating, supporting them as well.
Dave: Awesome. Well, thank you so much. Thank you, dear listener, for downloading this in your podcatcher of choice. Be sure to star, heart, favorite it up. That's how people find out about our show. Follow us on Twitter, @ShopTalkShow, for tons of tweets a month.
We have a Patreon, too. Head over to patreon.com/shoptalkshow and join the Discord. That gets you access to the Discord, which is popping off. Thank you.
Chris, do you have anything else you'd like to say?
Chris: [Laughter] That's it. ShopTalkShow.com.