谈谈你对webpack的理解

webpack主要是用来解决模块化问题的。

什么是模块

将某一个复杂的项目按照某种规则或者规范划分为多个文件,每个文件就是一个模块。模块内部是数据是私有的。

模块化实现历程

早期模块化的方式中,每个能实现某些功能js文件被设计为一个单独的模块,然后通过script标签引入

1
2
<script src="module-a.js"></script>
<script src="module-b.js"></script>

这种方式的缺点很明显,被引入后,模块中的变量都成为全局变量,存在变量污染问题,而且模块之间没有依赖关系

随后,就出现了命名空间方式,规定每个模块暴露一个全局对象,然后模块的内容都挂载到这个对象中。

1
2
3
4
5
6
window.moduleA = {
data:20
method1: function () {
console.log('moduleA#method1')
}
}

这样就解决了全局变量污染的问题,但是没有解决依赖混乱的问题,而且不安全,模块内部的数据可以被随意修改

后来又选择用立即执行函数为模块添加私有空间, 解决了内部数据可以被随意修改的问题。

1
2
3
4
5
6
7
8
9
10
11
12
(function ($) {
var name = 'module-a'

function method1 () {
console.log(name + '#method1')
$('body').animate({ margin: '200px' })
}
//挂载到window对象上只向外暴露方法,而且暴露的方法也使用了命名空间的思想,避免了全局冲突
window.moduleA = {
method1
}
})(jQuery)

支持传入参数,能在一定程度上解决模块依赖问题,但是必须注意引入模块的先后顺序,否则就会出现undefined的问题。

理想的解决方式是,在页面中引入一个JS入口文件,其余用到的模块可以通过代码控制,按需加载进来。

除了模块加载的问题以外,还需要规定模块化的规范,如今流行的则是CommonJSES Modules

我们上述讨论的模块化的范围只包括js文件,后来html,css等文件也可以被模块化,这就需要借助webpack

模块化的好处

解决了声明冲突问题,提高了代码的可维护性与复用性,使得项目中文件的依赖关系明确,支持按需加载。

什么是webpack

用于现代JavaScript应用程序的静态模块打包工具。

webpack的构建流程

  • 初始化阶段

    合并配置文件shell语句中的配置参数,创建compiler对象,并初始化插件

  • 编译阶段

    调用compiler对象的run方法,开始编译,从入口文件出发,使用配置的loader递归解析依赖的文件,把他们转变成可用的js模块,并构建模块依赖图

  • 打包并输出

    根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件并输出。

loader和plugin

loader

loader主要被用来进行文件的转化,使之变成可用的模块,扩大了webpack模块化的范围。

plugin

主要用来解决loader无法解决的其他事情,本质是一个具有apply方法的js对象,这个方法会被compiler对象调用。webpack构建过程中会广播很多事件,plugin可以监听自己感兴趣的事件,从而改变最后的打包结果。

常见的plugin:

  • html-webpack-plugin:

    在打包结束后,自动生成⼀个 html 文件,并自动引入打包后的js文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    module.exports = {
    plugins: [
    new HtmlWebpackPlugin({
    title: "My App",
    filename: "app.html",
    template: "./src/html/index.html"
    })
    ]
    };
  • mini-css-extract-plugin:

    提取 CSS 代码到一个单独的文件中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    module.exports = {
    module: {
    rules: [
    {
    test: /\.s[ac]ss$/,
    use: [MiniCssExtractPlugin.loader,'css-loader','sass-loader']
    }
    ]
    },
    plugins: [
    new MiniCssExtractPlugin({
    filename: '[name].css'
    })
    ]
    }