Vite in a simple html+js use case
Tags: javascript, webdev
Published: 2021-06-04 20:51:07

In this series, I'll take a look on a simple usecase of js+html application, build with various js bundlers. This time, it's time for [vite](https://vitejs.dev/).

# Vite
So vite itself is rather a development server/tooling than a js bundler. It's splitting completely the use cases of development server & production build. For example, in webpack you normally run a complete bundling process in dev server - maybe skipping some optimization, but besides that production build & development server are approached in a similar way. Vite in development compiles files separately & servers them unbundled. This saves us from waiting for the whole project to be rebuild after every change we do on the code side. The production build is done with rollup - the integration is seamless so from the point of view of the developer it could be done with any other bundler.

This series focus on a production build - therefore, it can be a bit unjust for vite, as it's ignoring the aspect that is main focus of this tool.


# The app

![application screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xacwuk055mv5c4cdot9z.png)

same as other articles of this series, simple app with 1 component with template & data in separate files.

# Code

The main html file, defines entry points of the application. Each value of `<script src>` or `<link href>` will be compiled by vite. It's similar approach to parcel.js, and a bit refreshing after having to specify entry points manually for so long in webpack.

```html
<!-- index.html -->
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Contact App</title>
    <link rel="shortcut icon" href="#" />

    <script type="module" src="./src/index.js"></script>
    <link rel="stylesheet" href="./style.css" />
  </head>
  <body></body>
</html>
```

After build, in the output folder (`dist/index.html`) we get:
```html
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Contact App</title>
    <link rel="shortcut icon" href="#" />

    
    
  <script type="module" crossorigin src="/assets/index.1d9c2da7.js"></script>
  <link rel="stylesheet" href="/assets/index.03175e43.css">
</head>
  <body></body>
</html>
```

with each original import replaced by build assets.

Main js file:

```js
// src/index.js
import "./contact-list/contact-list";
```
no surprises here

# The component

The component is broken down into 3 files - so code, template & data goes to best matching code type - JS, HTML & JSON. 

Main component file:
```js
// src/contact-list/contact-list.js
import template from "./contact-list.html?raw";
import contacts from "./data.json";

const contactList = document.createElement("div");

contactList.className = "contact-list";

contacts.forEach((entry) => {
  const element = document.createElement("div");
  element.className = "contact";

  element.innerHTML = template;

  element.querySelector(".name").innerHTML = entry.name;
  element.querySelector(".phone").innerHTML = entry.phone;

  contactList.appendChild(element);
});

document.body.appendChild(contactList);
```

Let's take a closer look on `import template from "./contact-list.html?raw"`. The `?raw` makes vite import the value as string. It's similar approach to defining loaders inline in webpack, but here seems to be the only way to tell vite how to treat different files. Pretty unfortunate, if we expect migrating between different build tools.

The html file we import:
```html
<!-- src/contact-list/contact-list.html -->
<h2 class="name">name</h2>

<p class="phone">phone</p>
```

JSON files are understood by vite by default. We just define `src/contact-list/data.json`, the data file:
```json 
[
  {
    "name": "Christopher L Sanders",
    "phone": "769-232-1807"
  },
  {
    "name": "Frances J Nolte",
    "phone": "901-287-0419"
  }
]
```

and the import works as expected - no config, no plugins & no `?` magic words needed.

# Build dependencies & configuration
For a successful build of the above code, we just need `vite` package. To install it, you can run:
```bash
$  npm install --save-dev vite
```

For easy access to build script, you can add following line to `package.json`:
``` js
  "scripts": {
    // other scripts
    "build": "vite build --base=./"
  }
```

The `--base=./` forces vite to use relative path for the browser side imports. Without it, your build code would work only on the top level of the domain. As long as you use the default entry file - `index.html` you don't need more configuration in our simple use case.

If all were set up correctly, the build will pass:
```bash
$ npm run build

> vite@1.0.0 build
> vite build

vite v2.3.6 building for production...
transforming...
✓ 6 modules transformed.
rendering chunks...
dist/index.html                  0.34kb
dist/assets/index.03175e43.css   0.23kb / brotli: 0.14kb
dist/assets/index.1d9c2da7.js    0.44kb / brotli: 0.21kb
```

# Complete code & application example

If you want to see the application in action in the browser you can see it here:
https://marcin-wosinek.github.io/js-html-comparison-vite/dist/

and for the working code example you can go here:
https://github.com/marcin-wosinek/js-html-comparison-vite