Contents
  1. Project Creation and What Vue CLI Produces
  2. Single File Components and vue-loader
  3. Template Compilation
  4. Babel and Transpilation
  5. Webpack and the Dependency Graph
  6. npm run serve vs npm run build
  7. What Lives in dist/
  8. What to Do Now
← All posts

From Code to Build: The Vue Development Pipeline

A Vue project created with Vue CLI is not a collection of files the browser can read directly. This documents every stage of the pipeline, from .vue file to browser.

A Vue project created with Vue CLI is not a collection of files the browser can read directly. A .vue file is not valid HTML, CSS or JavaScript on its own. Before anything reaches the browser, a pipeline of tools processes the source code and produces output the browser can understand. This blog documents every stage of that pipeline.

Project Creation and What Vue CLI Produces

Vue CLI scaffolds a project with a pre-configured build pipeline. Running vue create my-app produces a folder structure including src/, public/, package.json, babel.config.js and an internal webpack configuration managed by the CLI.

my-app/
  public/
    index.html
  src/
    main.js
    App.vue
    components/
  package.json
  babel.config.js

The public/index.html is a template. It is not served directly. The build process injects the compiled JavaScript and CSS bundles into it before output.

Single File Components and vue-loader

A .vue file is a Single File Component. It contains three sections in one file: <template>, <script> and <style>.

<template>
  <div class="greeting">{{ message }}</div>
</template>

<script>
export default {
  data() {
    return { message: 'Hello' };
  }
};
</script>

<style>
.greeting { color: blue; }
</style>

The browser cannot read this format. vue-loader is a webpack loader that parses .vue files, splits them into their three sections, and passes each section to the appropriate processor. The <template> is compiled into a JavaScript render function. The <script> is passed to Babel. The <style> is passed to the CSS processing pipeline.

Template Compilation

Vue’s template compiler transforms HTML templates into JavaScript render functions before the code reaches the browser. A template like <div>{{ message }}</div> becomes a function that creates a virtual DOM node. This compilation happens at build time when using Vue CLI, meaning the compiler does not need to be shipped to the browser as part of the production bundle.

Babel and Transpilation

JavaScript written using modern syntax, such as arrow functions, async/await, optional chaining or destructuring, may not be supported by older browsers. Babel reads the JavaScript produced by vue-loader and transforms it into a syntax that a wider range of browsers can execute.

The babel.config.js file controls which transformations Babel applies. Vue CLI configures this automatically using @vue/cli-plugin-babel.

Webpack and the Dependency Graph

Vue CLI uses webpack internally. Webpack reads src/main.js as the entry point, traces every import statement across the entire application, builds a dependency graph of every module, and bundles them into output files.

During this process:

  • vue-loader processes .vue files as described above
  • CSS loaders process styles and either inject them into the page via JavaScript or extract them into a separate .css file
  • Asset loaders handle images and fonts, copying them to the output directory and updating references in the code

npm run serve vs npm run build

npm run serve starts a development server. The application is compiled in memory, not written to disk. Webpack watches for file changes and applies Hot Module Replacement, updating the browser without a full reload. The development build is not optimised. Source maps are included for debugging and minification is disabled.

npm run build triggers a production build. The output is written to the dist/ folder. The following optimisations are applied:

Minification removes whitespace, shortens variable names, and reduces file sizes. Tree shaking, enabled by webpack’s production mode, analyses the dependency graph and removes code that is imported but never executed. CSS is extracted into a separate file rather than injected via JavaScript. File names receive a content hash, for example app.3a1f9c.js, which enables cache busting: when the file content changes, the hash changes, and the browser fetches the updated file instead of serving a stale cached version.

What Lives in dist/

After npm run build, the dist/ folder contains:

  • index.html, with script and link tags pointing to the compiled bundles
  • js/app.[hash].js, the compiled application code
  • js/chunk-vendors.[hash].js, third-party dependencies from node_modules bundled separately
  • css/app.[hash].css, all extracted styles
  • Any assets referenced in the source code, copied and fingerprinted

This folder is what gets deployed to a web server or static hosting service. The browser loads index.html, which references the bundles, and the application runs.

What to Do Now

Create a Vue CLI project, run npm run build, and inspect the dist/ folder:

vue create pipeline-demo
cd pipeline-demo
npm run build

Open dist/index.html in a text editor. Observe the injected script and link tags. Compare the sizes of the development and production bundles in the terminal output. The production bundle is substantially smaller because minification and tree shaking have been applied.

← All posts