Статьи

Jargon-Free Webpack Intro для пользователей Vue.js

Для многих разработчиков Vue.js является первой интерфейсной JavaScript-инфраструктурой, которую они изучили. Если это правда для вас, у вас, вероятно, еще не было причин изучать Webpack. Но продолжая работу с Vue, вы увидите, как Webpack снова и снова всплывает в документации, в примерах проектов и в отношении таких инструментов, как Vue CLI.

Webpack обещает отличные вещи для пользователей Vue:

  • Автоматизированный процесс разработки, который делает кодирование легким.
  • Мир удобных функций разработки, таких как любимые однофайловые компоненты Vue.
  • Оптимизация для вашего кода, чтобы сделать его быстрым и экономным.

Но диапазон возможностей Webpack также поначалу так пугает. Оказывается , сделать так много вещей , что трудно понять , что это на самом деле есть .

Руководства по Webpack становятся все лучше и лучше объясняют Webpack, но определенное количество базовых знаний все еще предполагается. В этой статье я попытаюсь дать вам этот фон без жаргона, который иначе может сбить вас с толку.

Пример проекта

Webpack помогает вам разрабатывать приложения на JavaScript, поэтому для его обсуждения нам нужно иметь в виду простой пример проекта. Вот что я буду ссылаться в этой статье:

app.js

const app = new Vue({
  el: '#app',
  data: {
    message: 'Hello World'
  }  
});

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Vue.js Project</title>
</head>
<body>
  <div id="app">{{ message }}</div>
  <script type="text/javascript" src="vue.js"></script>
  <script type="text/javascript" src="app.js"></script>
</body>
</html>

зависимости

The story of Webpack begins with some observations about how JavaScript dependencies are managed in an HTML document. By «dependencies» I mean third-party libraries like Vue, jQuery or Lodash, or even other script files from your own code base.

In fact, there’s no real way of managing dependencies in an HTML document other than to ensure any shared functions and variables have global scope and that scripts are loaded in the right order.

For example, since vue.js defines a global Vue object and is loaded first, we’re able to use the Vue object in our app.js script. If either of those conditions was not met, the script would break. Consider the following where we attempt to use Vue before it has loaded:

<script>
  console.log(Vue);
  // Uncaught ReferenceError: Vue is not defined
</script>
<script type="text/javascript" src="vue.js"></script>

In a complex web application, this system is insufficient because:

  • Global variables introduce possibilities of naming collisions.
  • Script loading order is fragile and can be easily broken as the app grows.
  • Performance optimizations, like loading scripts asynchronously, cannot be utilized.

Modules

A solution to the dependency management problem is to use a module system where code is modularized and imported into other scripts. Over the years, there have been several different JavaScript module systems developed, but ES modules is the system that is now being incorporated into the JavaScript standard.

Here’s a simple ES modules example:

moduleA.js

export default function(value) {
  return value * 2;
}

moduleB.js

import multiplyByTwo from './moduleA';
console.log(multiplyBy2(2));
// 4

Could we make Vue.js a module and avoid the problems discussed? Yes! The Vue.js script file that’s used directly in a browser is just one of the available builds of Vue. There is also an ES module build named vue.esm.browser.js which can be used in our example project like this:

app.js

import Vue from './vue.esm.browser.js';

const app = new Vue({
  el: '#app',
  data: {
    message: 'Hello World'
  }  
});

Script order isn’t a problem now since the compiler knows it has to wait until vue.esm.browser.js is available before it can run. Global variables aren’t needed either because modules are referenced by their file name.

The problem is that ES modules are not consistently supported in browsers. In fact, until a few months ago, it wasn’t supported in any browser.

If we want to use ES modules or any other JavaScript module system, we’ll need to resolve the code into something that can be reliably used in a browser. Enter Webpack.

Bundling

Webpack is a Node.js tool that runs offline in your development environment. Webpack is able to resolve JavaScript modules into browser-friendly code in a process called «bundling.»

Bundling begins with an «entry file.» Webpack analyzes the entry file to find any dependencies. In the example project, app.js is the entry file and has just one dependency, Vue.js. In most projects, there will be many more.

Webpack then analyzes the dependencies to find any dependencies that they might have. This process continues until all dependencies of the project are found.

The result is a graph of dependencies. For the example project, the graph includes app.js, vue.js and a few other dependencies required by Webpack.

Webpack uses this graph as a blueprint for bundling all the code into a single browser-friendly file.

In the example project, the bundle file will replace the individual script files vue.js and app.js in the HTML document:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Vue.js Project</title>
</head>
<body>
  <div id="app">{{ message }}</div>
  <script type="text/javascript" src="bundle.js"></script>
</body>
</html>

Loaders

Webpack provides a reliable solution to the JavaScript dependency management problem. From this foundation, other powerful emerge, e.g. loaders.

Loaders allow Webpack to transform a file before it’s bundled. For example, the Webpack Babel loader transforms next-generation JavaScript syntax like ES2015 into standard ES5. This allows developers to write their code using modern features but still provide support in older browsers.

For example, in app.js we use the ES2015 const, which isn’t supported by IE10:

app.js

const app = new Vue({
  el: '#app',
  data: {
    message: 'Hello World'
  }  
});

If the Webpack Babel loader is used const will be transformed to var before it’s added to the bundle:

bundle.js

...

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello World'
  }  
});

...

There are many other loaders including:

  • CSS loader
  • Sass loader
  • TypeScript loader
  • Vue Loader (for single-file components)

Running Webpack

Webpack uses a declarative config file to describe each aspect of the build. These config files are notoriously long and difficult to follow, but for a simple project you should be able to get the gist:

webpack.config.js

module.exports = {
  // Entry file
  entry: './app.js',
  output: {
    // Output bundle
    filename: 'bundle.js'
  }, 
  module: {
    rules: [
      {
        // For .js files...
        test: /\.js$/,
        use: {
          // Use the Babel loader
          loader: 'babel-loader'
        }
      }
    ]
  },
  resolve: {
    alias: {
      // Ensure the right Vue build is used
      'vue$': 'vue/dist/vue.esm.js'
    }
  }
};

With the config file created, Webpack can then be run with a CLI command:

$ webpack

As Webpack runs, it outputs statistics about the build in the terminal. Many of these stats won’t have meaning right now, but you can at least see that this build took about three seconds to complete and the output file, bundle.js, is 299KB.

Next Step

This article hasn’t gotten you very far in learning Webpack, but the goal was to give you the background I think is missing from the official docs and other guides.

The big takeaway I hope you’ve gotten is that Webpack is first and foremost a module bundler. All of Webpack’s other features emerge from this basic model.

For the next step, I recommend you go through the Concepts section of the Webpack Docs:

https://webpack.js.org/concepts/

Good luck!