Vite (pronounced “veet”) is a newish JavaScript bundler. It comes batteries-included, requires virtually no configuration to be helpful, and consists of loads of configuration choices. Oh—and it’s quick. Extremely quick.
This put up will stroll by means of the method of changing an present undertaking to Vite. We’ll cowl issues like aliases, shimming webpack’s dotenv dealing with, and server proxying. In different phrases, we’re taking a look at how one can transfer a undertaking from its present bundler to Vite. In case you’re trying as an alternative to start out a recent undertaking, you’ll wish to leap to their documentation.
Lengthy story, quick: the CLI will ask to your framework of alternative—React, Preact, Svelte, Vue, Vanilla, and even lit-html—and whether or not you need TypeScript, then offer you a totally functioning undertaking.
Scaffold first! In case you are desirous about studying about integrating Vite right into a legacy undertaking, I’d nonetheless advocate scaffolding an empty undertaking and poking round it a bit. At instances, I’ll be pasting some clumps of code, however most of that comes straight from the default Vite template.
Our use case
What we’re taking a look at is predicated alone expertise migrating the webpack construct of my booklist undertaking (repo). There isn’t something significantly particular about this undertaking, but it surely’s pretty huge and outdated, and leaned exhausting on webpack. So, in that sense, it’s a superb alternative to see a few of Vite’s extra helpful configuration choices in motion as we migrate to it.
What we gained’t want
One of the vital compelling causes to succeed in for Vite is that it already does rather a lot proper out of the field, incorporating lots of the responsibilities from different frameworks so there are fewer dependencies and a extra established baseline for configurations and conventions.
So, as an alternative of beginning by calling out what we have to get began, let’s go over all of the frequent webpack issues we don’t want as a result of Vite provides them to us without spending a dime.
Static asset loading
We normally want so as to add one thing like this in webpack:
{
check: /.(png|jpg|gif|svg|eot|woff|woff2|ttf)$/,
use: [
{
loader: “file-loader”
}
]
}
This takes any references to font information, photos, SVG information, and so forth., and copies them over to your dist folder to allow them to be referenced out of your new bundles. This comes normal in Vite.
Kinds
I say “types” versus “css” deliberately right here as a result of, with webpack, you may need one thing like this:
{
check: /.s?css$/,
use: [MiniCssExtractPlugin.loader, “css-loader”, “sass-loader”]
},
// later
new MiniCssExtractPlugin({ filename: “[name]-[contenthash].css” }),
…which permits the applying to import CSS or SCSS information. You’ll develop bored with listening to me say this, however Vite helps this out of the field. Simply remember to set up Sass itself into your undertaking, and Vite will deal with the remainder.
Transpilation / TypeScript
It’s doubtless your code is utilizing TypeScript, and or non-standard JavaScript options, like JSX. If that’s the case, you’ll have to transpile your code to take away these issues and produce plain outdated JavaScript {that a} browser (or JavaScript parser) can perceive. In webpack that will look one thing like this:
j)sx?$/,
exclude: /node_modules/,
loader: “babel-loader”
,
…with a corresponding Babel configuration to specify the suitable plugins which, for me, regarded like this:
{
“presets”: [“@babel/preset-typescript”],
“plugins”: [
“@babel/plugin-proposal-class-properties”,
“@babel/plugin-syntax-dynamic-import”,
“@babel/plugin-proposal-optional-chaining”,
“@babel/plugin-proposal-nullish-coalescing-operator”
]
}
Whereas I may have in all probability stopped utilizing these first two plugins years in the past, it doesn’t actually matter since, as I’m certain you’ve guessed, Vite does this all for us. It takes your code, removes any TypeScript and JSX, and produces code supported by fashionable browsers.
In case you’d wish to assist older browsers (and I’m not saying you need to), then there’s a plugin for that.
node_modules
Surprisingly, webpack requires you to inform it to resolve imports from node_modules, which we do with this:
resolve: {
modules: [path.resolve(“./node_modules”)]
}
As anticipated, Vite already does this.
Manufacturing mode
One of many frequent issues we do in webpack is distinguish between manufacturing and improvement environments by manually passing a mode property, like this:
mode: isProd ? “manufacturing” : “improvement”,
…which we usually surmise with one thing like this:
const isProd = course of.env.NODE_ENV == “manufacturing”;
And, in fact, we set that surroundings variable through our construct course of.
Vite handles this a bit in another way and provides us completely different instructions to run for improvement builds versus these for manufacturing, which we’ll get into shortly.
File extensions
On the danger of belaboring the purpose, I’ll rapidly notice that Vite additionally doesn’t require you to specify each file extension you’re utilizing.
resolve: {
extensions: [“.ts”, “.tsx”, “.js”],
}
Simply arrange the correct of Vite undertaking, and also you’re good to go.
Rollup plugins are suitable!
That is such a key level I needed to name it out in its personal part. In case you nonetheless wind up with some webpack plugins you want to exchange in your Vite app whenever you end this weblog put up, then attempt to discover an equal Rollup plugin and use that. You learn that appropriately: Rollup plugins are already (or normally, no less than) suitable with Vite. Some Rollup plugins, in fact, do issues which can be incompatible with how Vite works—however basically, they need to simply work.
For more information, try the docs.
Your first Vite undertaking
Bear in mind, we’re shifting an present legacy webpack undertaking to Vite. In case you’re constructing one thing new, it’s higher to begin a brand new Vite undertaking and go from there. That stated, the preliminary code I’m displaying you is principally copied proper from what Vite scaffolds from a recent undertaking anyway, so taking a second to scaffold a brand new undertaking may additionally a good suggestion so that you can examine processes.
The HTML entry level
Yeah, you learn that proper. Relatively than placing HTML integration behind a plugin, like webpack does, Vite is HTML first. It expects an HTML file with a script tag to your JavaScript entrypoint, and generates all the things from there.
Right here’s the HTML file (which Vite expects to be referred to as index.html) we’re beginning with:
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″ />
<title>The GOAT of internet apps</title>
</head>
<physique>
<div id=”house”></div>
<script sort=”module” src=”/reactStartup.tsx”></script>
</physique>
</html>
Observe that the <script> tag factors to /reactStartup.tsx. Alter that to your individual entry as wanted.
Let’s set up just a few issues, like a React plugin:
npm i vite @vitejs/plugin-react @sorts/node
We additionally create the next vite.config.ts proper subsequent to the index.html file within the undertaking listing.
import { defineConfig } from “vite”;
import react from “@vitejs/plugin-react”;
export default defineConfig({
plugins: [react()]
});
Lastly, let’s add just a few new npm scripts:
“dev”: “vite”,
“construct”: “vite construct”,
“preview”: “vite preview”,
Now, let’s begin Vite’s improvement server with npm run dev. It’s extremely quick, and incrementally builds no matter it must, based mostly on what’s requested.
However, sadly, it fails. Not less than for proper now.
We’ll get to how one can arrange aliases in a second, however for now, let’s as an alternative modify our reactStartup file (or no matter your entry file is named) as follows:
import React from “react”;
import { render } from “react-dom”;
render(
<div>
<h1>Hello there</h1>
</div>,
doc.getElementById(“house”)
);
Now we will run it our npm run dev command and browse to localhost:3000.
Sizzling module reloading (HMR)
Now that the event server is operating, strive modifying your supply code. The output ought to replace virtually instantly through Vite’s HMR. That is one among Vite’s nicest options. It makes the event expertise a lot nicer when adjustments appear to mirror instantly moderately than having to attend, and even set off them ourselves.
The remainder of this put up will go over all of the issues I needed to do to get my very own app to construct and run with Vite. I hope a few of them are related for you!
Aliases
It’s not unusual for webpack-based initiatives to have some config like this:
resolve: {
alias: {
jscolor: “util/jscolor.js”
},
modules: [path.resolve(“./”), path.resolve(“./node_modules”)]
}
This units up an alias to jscolor on the supplied path, and tells webpack to look each within the root folder (./) and in node_modules when resolving imports. This enables us to have imports like this:
import { factor } from “util/helpers/foo”
…anyplace in our element tree, assuming there’s a util folder on the very high.
Vite doesn’t let you present a complete folder for decision like this, but it surely does let you specify aliases, which comply with the identical guidelines because the @rollup/plugin-alias:
import { defineConfig } from “vite”;
import react from “@vitejs/plugin-react”;
import path from “path”;
export default defineConfig({
resolve: {
alias: {
jscolor: path.resolve(“./util/jscolor.js”),
app: path.resolve(“./app”),
css: path.resolve(“./css”),
util: path.resolve(“./util”)
}
},
plugins: [react()]
});
We’ve added a resolve.alias part, together with entries for all the things we have to alias. Our jscolor util is ready to the related module, and now we have aliases for our top-level directories. Now we will import from app/, css*/*, and util/ from any element, anyplace.
Observe that these aliases solely apply to the foundation of the import, e.g. util/foo. When you’ve got some different util folder deeper in your tree, and also you reference it with this:
import { factor } from “./helpers/util”;
…then the alias above will not mess that up. This distinction just isn’t nicely documented, however you’ll be able to see it within the Rollup alias plugin. Vite’s alias matches that very same habits.
Surroundings variables
Vite, in fact, helps surroundings variables. It reads config values out of your .env information in improvement, or course of.env, and injects them into your code. Sadly, issues work a bit in another way than what you is perhaps used to. First, it doesn’t exchange course of.env.FOO however moderately import.meta.env.FOO. Not solely that, but it surely solely replaces variables prefixed with VITE_ by default. So, import.meta.env.VITE_FOO would truly get replaced, however not my unique FOO. This prefix will be configured, however not set to empty string.
For a legacy undertaking, you might grep and exchange all of your surroundings variables to make use of import.meta.env, then add a VITE_ prefix, replace your .env information, and replace the surroundings variables in no matter CI/CD system you utilize. Or you’ll be able to configure the extra traditional habits of changing course of.env.ANYTHING with values from a .env file in improvement, or the actual course of.env worth in manufacturing.
Right here’s how. Vite’s outline characteristic is principally what we want. This registers international variables throughout improvement, and does uncooked textual content alternative for manufacturing. We have to set issues up in order that we manually learn our .env file in improvement mode, and the method.env object in manufacturing mode, after which add the suitable outline entries.
Let’s construct that each one right into a Vite plugin. First, run npm i dotenv.
Now let’s take a look at the code for the plugin:
import dotenv from “dotenv”;
const isProd = course of.env.NODE_ENV === “manufacturing”;
const envVarSource = isProd ? course of.env : dotenv.config().parsed;
export const dotEnvReplacement = () => {
const replacements = Object.entries(envVarSource).cut back((obj, [key, val]) => {
obj[`process.env.${key}`] = `”${val}”`;
return obj;
}, {});
return {
identify: “dotenv-replacement”,
config(obj) {
obj.outline = obj.outline || {};
Object.assign(obj.outline, replacements);
}
};
};
Vite units course of.env.NODE_ENV for us, so all we have to do is test that to see which mode we’re in.
Now we get the precise surroundings variables. If we’re in manufacturing, we seize course of.env itself. If we’re in dev, we ask dotenv to seize our .env file, parse it, and get again an object with all of the values.
Our plugin is a perform that returns a Vite plugin object. We inject the environment values into a brand new object that has course of.env. in entrance of the worth, after which we return our precise plugin object. There may be quite a lot of hooks obtainable to make use of. Right here, although, we solely want the config hook, which permits us to change the present config object. We add a outline entry if none exists, then add all our values.
However earlier than shifting ahead, I wish to notice that the Vite’s surroundings variables limitations we’re working round exist for a purpose. The code above is how bundlers are steadily configured, however that also means any random worth in course of.env is caught into your supply code if that key exists. There are potential safety considerations there, so please maintain that in thoughts.
Server proxy
What does your deployed internet utility seem like? If all it’s doing is serving JavaScript/CSS/HTML—with actually all the things taking place through separate providers situated elsewhere—then good! You’re successfully accomplished. What I’ve proven try to be all you want. Vite’s improvement server will serve your belongings as wanted, which pings all of your providers identical to they did earlier than.
However what in case your internet app is sufficiently small that you’ve got some providers operating proper in your internet server? For the undertaking I’m changing, I’ve a GraphQL endpoint operating on my internet server. For improvement, I begin my Specific server, which beforehand knew how one can serve the belongings that webpack generated. I additionally begin a webpack watch activity to generate these belongings.
However with Vite delivery its personal dev server, we have to begin that Specific server (on a separate port than what Vite makes use of) after which proxy calls to /graphql over to there:
server: {
proxy: {
“/graphql”: “http://localhost:3001”
}
}
This tells Vite that any requests for /graphql needs to be despatched to http://localhost:3001/graphql.
Observe that we do not set the proxy to http://localhost:3001/graphql within the config. As an alternative, we set it to http://localhost:3001 and depend on Vite so as to add the /graphql half (as nicely any any question arguments) to the trail.
Constructing libs
As a fast bonus part, let’s briefly talk about constructing libraries. For instance, what if all you wish to construct is a JavaScript file, e.g. a library like Redux. There’s no related HTML file, so that you’ll first want to inform Vite what to make:
construct: {
outDir: “./public”,
lib: {
entry: “./src/index.ts”,
codecs: [“cjs”],
fileName: “my-bundle.js”
}
}
Inform Vite the place to place the generated bundle, what to name it, and what codecs to construct. Observe that I’m utilizing CommonJS right here as an alternative of ES modules because the ES modules don’t minify (as of this writing) attributable to considerations that it may break tree-shaking.
You’d run this construct with vite construct. To start out a watch and have the library rebuild on change, you’d run
vite construct –watch.
Wrapping up
Vite is an extremely thrilling software. Not solely does it take the ache, and tears out of bundling internet apps, but it surely tremendously improves the efficiency of doing so within the course of. It ships with a blazingly quick improvement server that ships with sizzling module reloading and helps all main JavaScript frameworks. In case you do internet improvement—whether or not it’s for enjoyable, it’s your job, or each!—I can’t advocate it strongly sufficient.
Including Vite to Your Current Internet App initially printed on CSS-Tips. You must get the publication and develop into a supporter.
Subscribe to MarketingSolution.
Receive web development discounts & web design tutorials.
Now! Lets GROW Together!