How to build with esbuild code generated by Vue CLI
Published: 2021-07-16 07:14:25

If you are interested in trying out esbuild with your Vue CLI generated app, in this article I will walk you through setting it up for a freshly generated application. This should be a good starting point for migrating your Vue application to esbuild.

# Code generation

I generate new application with:
```sh
$ npx -p @vue/cli vue create esbuild-vue-cli -d
```
* `-d` - skips prompts with generating options & use default options - vue version 2
* `npx -p ...` - generates code without global installation

The generate code can be build with:
```sh
$ npm run build
> esbuild-vue-cli@0.1.0 build
> vue-cli-service build


 DONE  Compiled successfully in 1622ms8:20:58 AM

  File                                 Size               Gzipped

  dist/js/chunk-vendors.5028b17c.js    90.35 KiB          32.40 KiB
  dist/js/app.5b09fec2.js              4.58 KiB           1.63 KiB
  dist/css/app.fb0c6e1c.css            0.33 KiB           0.23 KiB

  Images and other types of assets omitted.

 DONE  Build complete. The dist directory is ready to be deployed.
 INFO  Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html
```

Key information here - the built code has about 95 KiB, and it took about 1.6s to get it.

# Esbuild installation & naive build

First we have to install esbuild:
```sh
$ npm install --save-dev esbuild

added 1 package, and audited 1326 packages in 3s

82 packages are looking for funding
  run `npm fund` for details

....
```

If we were trying to apply the approach used in the [create-react-app example](https://how-to.dev/how-to-build-code-generated-by-create-react-app-with-esbuild), we would en up with a build command in `package.json` like this one:
```json
{
  ...
  "scripts": {
    ...
    "esbuild": "esbuild src/main.js --bundle --outfile=dist/main.js"
  },
  ...
}
```

Running this script fails:
```sh
$ npm run esbuild

> esbuild-vue-cli@0.1.0 esbuild
> esbuild src/main.js --bundle --outfile=dist/main.js

 > src/main.js:2:16: error: No loader is configured for ".vue" files: src/App.vue
    2 │ import App from './App.vue'
      ╵                 ~~~~~~~~~~~

1 error
```

There are 2 things happening here:
* we need a loader for VUE files. Luckily there is a  [plugin that we can use](https://www.npmjs.com/package/esbuild-vue)
* for using this, or any other esbuild plugin we need to move from building with CLI command to build script - something I already covered [here](https://how-to.dev/how-to-manage-complex-configuration-of-esbuild)

# Installing the plugin & setting the build script

We can install the plugin with:
```sh
$ npm install --save-dev esbuild-vue

added 91 packages, and audited 1417 packages in 6s

82 packages are looking for funding
  run `npm fund` for details
...
```

For the build script, I follow the example form esbuild-vue's  [Getting started](https://www.npmjs.com/package/esbuild-vue#user-content-getting-started):
```js
const vuePlugin = require("esbuild-vue");

require("esbuild").build({
  entryPoints: ["src/main.js"],
  bundle: true,
  outfile: "dist/main.js",
  logLevel: "info",
  plugins: [vuePlugin()],
  define: {
    "process.env.NODE_ENV": JSON.stringify("development"),
  },
});
```

Plus I:
* added `logLevel: "info",` to get logs about successful builds as well
* set entryPoints & outfile

Now, we replace the `package.json` esbuild script with:
```json
{
  ...
  "scripts": {
    ...
    "esbuild": "node build.js"
  },
  ...
}
```

The build passes:
```sh
$ npm run esbuild 

> esbuild-vue-cli@0.1.0 esbuild
> node build.js


  dist/main.js  200.2kb

⚡ Done in 634ms
```

The build is faster - about 0.6s, but the output is bigger - 200 KiB. Before we will start optimizing it, let's first test if it's working as expected.

For testing our build, let's paste this into `dist/index.html`:
```html
<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link rel="icon" href="./favicon.ico" />
    <title>esbuild-vue-cli</title>
  </head>
  <body>
    <noscript
      ><strong
        >We're sorry but esbuild-vue-cli doesn't work properly without
        JavaScript enabled. Please enable it to continue.</strong
      ></noscript
    >
    <div id="app"></div>
    <script src="./main.js"></script>
  </body>
</html>
```

It's the HTML build by the original `npm run build`, but tweaked to the files names we used in esbuild. The application works:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lvxw22t1kuy4z3k3z1u3.png)

but it's missing a logo. That's because contrary to webpack, esbuild is not parsing HTML files to treat `src="<some-file>"` as file imports - we will need to do it ourself, but this is something to be covered in other article in this series.

# Size optimization

For optimizing the build size, we just need to add to `build.js`:
```js
...
require("esbuild").build({
  ...
  minify: true,
  ...
});
```

With this in place, our build is as fast as before:
```sh
$ npm run esbuild

> esbuild-vue-cli@0.1.0 esbuild
> node build.js


  dist/main.js  89.9kb

⚡ Done in 600ms
```

but the size is more or less the same as for the original build script.

# Links
* [my course about esbuild](https://bit.ly/esbuild-course)

# Summary
In this article, we have seen how to build Vue CLI generate code with esbuild. You can find the code repository  [here](https://github.com/marcin-wosinek/esbuild-vue-cli) , and the generate page  [here](https://marcin-wosinek.github.io/esbuild-vue-cli/dist) .