Webpack 的基础使用

Webpack 和 Babel 好像用得很多了,但就是每次配置项目的时候查一下文档,这里稍微总结一下

ES Module 和 Webpack

ES2015 开始,JavaScript 有了模块的概念。这里一个模块就是一个独立的 js 文件。

没有模块之前,在一个文件里面定义的变量或者函数之类的,都是全局的。在另一个 js 文件里面也能访问到,也就是没有作用域 (scope)。网页开发中就有可能会引入多个 JS 的情况下,出现方法名被覆盖这种问题。

有了 Module 之后,作用域限定在了一个文件内,冲突的可能性也少多了。

模块化之后也会带来一些问题,比如零散文件会变多,请求数会增加(但 HTTP/2 可以解决这个问题)。比较旧的浏览器不支持 import 等等。

但模块化开发十分方便,所以 Webpack 出现了,它能够把众多的 Modules 打包成一个文件。不仅如此,它还支持把 css、模板 html 等,还有静态资源也能打包到一起,方便部署。

Webpack 官方网站

前期准备

需要 Node.js 和 npm 环境,这个就不需要多说了。

ES Module

推荐阅读阮一峰的ES6教程

简单来说,不同模块之间需要调用的时候,需要有明确的导出和导入,即 exportimport

这是 hello.mjs 代码:


const message = "Hello world"

const hello = () => {
    return message;
}

export {hello}

这是 index.mjs 的代码:

import { hello } from "./hello.mjs";

console.log(hello());

然后我们执行 node --experimental-modules index.mjs 就可以看到输出了。

注意:目前 Nodejs 需要导入导出模块的话,需要使用 .mjs 后缀名,并且运行的时候要加上 --experimental-modules 参数。

使用 Webpack 的话就不用了。

Webpack 的作用

Webpack 的作用就是把 import 调用的所有文件,通过一些方式连接在一起,输出为单一的一个 js 文件,称为 Bundle。

使用 Webpack

Webpack 安装

首先在一个新的目录下,用 npm init 命令来创建一个新的项目吧。

接下来使用 npm 安装 Webpack

npm install webpack webpack-cli --save-dev

这里安装了 Webpack 的本体,以及它相关的命令行工具。

Webpack 官方不推荐全局安装 Webpack,所以每个项目都独立安装一份吧。

附上官方安装指南页面

准备我们的项目

创建一个 src 目录,准备我们的代码文件。

sample/
  └ src/
      ├ hello.js
      └ index.js

用的还是刚才的代码,不过这次不需要使用 mjs 后缀了,可以用回 js 后缀。

hello.js 代码:


const message = "Hello world"

const hello = () => {
    return message;
}

export {hello}

index.mjs 代码:

import { hello } from "./hello"; // 这里后缀名是可以省略掉的

console.log(hello());

使用 Webpack 进行打包

运行以下命令就可以进行打包了

npx webpack

npx 是 npm 提供的一个命令,如果不存在,要确认以下 npm 的版本是不是太低,或者 Path 环境变量配置有问题了。

实际上 npx 是帮你执行 \node_modules.bin 里面的 webpack。

Webpack 打包完成之后,可以看到一个 dist 文件夹。打开里面的 main.js ,可以看到十分复杂的东西。

!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}
/* 中间省略 */
return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t,r){"use strict";r.r(t);console.log("Hello world")}]);

有种 js uglify 压缩过的样子。运行一下试试吧。

node .\dist\main.js

webpack.config.js 的配置

在项目根目录下创建一个 webpack.config.js,可以进行 Webpack 的配置。当然这些配置大部分都可以通过命令行参数来实现。

最基础的配置文件如下。可以查看官方文档查看所有可配置项目。

module.exports = {
    entry: './src/index.js', 
    output: {
        path: __dirname + '/dist',
        filename: 'main.js'
    }
};
  • entry 是入口点的文件名。
  • output 是输出文件相关的配置。

默认 Webpack 使用的是 webpack.config.js,但你也可以在命令行参数上直接指定使用的配置文件名。比如一套 development 配置,一套 production 配置。

npx webpack --config <文件名>

模式配置

Webpack 打包的时候你应该会看到一个警告

The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.

因为 Webpack 要求指定一个 mode,其中有两个可选:

  • development 开发模式,方便 debug
  • production 生产模式,尽量减少文件体积 (这个是默认值)

虽然有警告提示,但 Webpack 默认使用的是 production

我们试试 development 模式是什么效果。

修改 webpack.config.js 如下

module.exports = {
    mode: 'development',
    entry: './src/index.js', 
    output: {
        path: __dirname + '/dist',
        filename: 'main.js'
    }
};

再次 npx webpack 之后,打开 dist/main.js 看看。

/******/ (function(modules) { // webpackBootstrap
/******/     // The module cache
/******/     var installedModules = {};
/******/
/******/     // The require function
/******/     function __webpack_require__(moduleId) {
/******/
/******/         // Check if module is in cache
/******/         if(installedModules[moduleId]) {
/******/             return installedModules[moduleId].exports;
/******/         }
/******/         // Create a new module (and put it into the cache)
/******/         var module = installedModules[moduleId] = {
/******/             i: moduleId,
/******/             l: false,
/******/             exports: {}
/******/         };
/******/
/******/         // Execute the module function
/******/         modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/         // Flag the module as loaded
/******/         module.l = true;
/******/
/******/         // Return the exports of the module
/******/         return module.exports;
/******/     }
/******/
/******/
/******/     // expose the modules object (__webpack_modules__)
/******/     __webpack_require__.m = modules;

可以发现它多了很多的注释,变量名也比较清楚。这样也方便让我们理解它是怎么实现的。

Source Map

使用 Source Map 可以方便 Debug 的时候,找到源代码对应的行数。

module.exports = {
    mode: 'development',
    devtool: 'inline-source-map',
    /* 省略 */
};

添加 devtool 配置即可。在 Chrome 里就可以看到源码文件了。

这里可以配置很多不同的值,具体每个不同的效果,可以参照官方文档

Watch 模式

开启 Watch 模式,可以让你修改过文件之后,立刻打包新的文件。而且第二次以后是差分更新,速度会快很多,方便开发。

在运行 webpack 命令的时候,加上 --watch 参数就可以了。

npx webpack --watch

如果不像每次都输入,直接配置在 webpack.config.js 里也是可以的。

module.exports = {
    watch: true,
    /* 省略 */
};

有些文件,比如 node_modules,一般不需要加入到监视文件列表里面,这时候增加一个忽略名单。

module.exports = {
    watch: true,
    watchOptions: {
        ignored: ['node_modules']
    },
    /* 省略 */
};

退出 Watch 模式直接按 Ctrl + C 即可。

添加到 NPM Script

可以把执行的命令用添加到 NPM 里面,方便运行。

打开 package.json,修改里面的 script 内容。

"scripts": {
    "build": "webpack"
},

就这么简单,运行的时候使用 npm run build,就可以执行这个脚本。

当然,只是这么简单的也没有必要,那么一般是怎么用的呢?

基于上面的 webpack.config.js,我们可以配出一份开发用的,一份部署用的配置。

  • webpack.dev.config
  • webpack.prod.config

然后我们可以创建两个 script

{
    "scripts": {
        "start": "webpack --watch --config webpack.dev.config",
        "build": "webpack --config webpack.pro.config"
    },
    /* 省略 */
}

这个 start 的 script,在运行的时候可以不用使用 npm run start,直接 npm start 即可。