2

【webpack篇】原理

之前每件事都差不多,直到现在才发现差很多。

现在才发现理清一件事的原委是多么快乐的一件事,我们共同勉励。

懒得扯淡,直接正题

不基于例子的讲原理都是扯淡,知乎一样的举例都是卖弄

要说现在的模块打包肯定用的最多的就是webpack,下面由浅入深的讲一下它的原理,在这里举例打包js和css模块。

ps: 基于webpack 4

打包构建解析

示例环境依赖及部分代码

依赖
  • "clean-webpack-plugin": "^0.1.18",
  • "css-loader": "^0.28.10",
  • "html-webpack-plugin": "^3.0.4",
  • "style-loader": "^0.20.2",
  • "webpack": "^4.0.1",
  • "webpack-cli": "^2.0.10"
webpack.config.js
const path = require('path');
const webpack = require('webpack');
//用于插入html模板
const HtmlWebpackPlugin = require('html-webpack-plugin');
//清除输出目录,免得每次手动删除
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
    mode: 'development',
    entry: {
        index: path.join(__dirname, 'index.js'),
    },
    output: {
        path: path.join(__dirname, '/dist'),
        filename: 'js/[name].[chunkhash:4].js'
    },
    plugins: [
        new CleanWebpackPlugin(['dist']),
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: 'index.html',
        })
    ],
    module: {
        rules: [{
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
        }]
    }
};
index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>webpack-learn</title>
</head>
<body>
    <div class="wrapper">webpack-learn</div>
</body>
</html>
index.css
.wrapper {
    font-size: 20px;
    color: #f00;
}
js 文件
// index.js
const test = require('./src/js/test');
require('./src/css/index.css');
console.log(test);
// test.js
const str = 'test is loaded';
module.exports = str;

页面结构如下:

clipboard.png

运行
$ webpack 

打包结果分析

查看 dist/js/index.[chunkhash:4].js 文件,发现文件有点大,不知道从何处看起,那么我们把入口js文件进行剥茧抽丝,清空,看一下,最简单的打包后的文件。

/******/ (function(modules) { // webpackBootstrap
/******/     var installedModules = {};
/******/     function __webpack_require__(moduleId) {
/******/         if(installedModules[moduleId]) {
/******/             return installedModules[moduleId].exports;
/******/         }
/******/         var module = installedModules[moduleId] = {
/******/             i: moduleId,
/******/             l: false,
/******/             exports: {}
/******/         };
/******/         modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/         module.l = true;
/******/         return module.exports;
/******/     }
/******/     __webpack_require__.m = modules;
/******/     __webpack_require__.c = installedModules;
/******/     __webpack_require__.d = function(exports, name, getter) {
/******/         if(!__webpack_require__.o(exports, name)) {
/******/             Object.defineProperty(exports, name, {
/******/                 configurable: false,
/******/                 enumerable: true,
/******/                 get: getter
/******/             });
/******/         }
/******/     };
/******/     __webpack_require__.r = function(exports) {
/******/         Object.defineProperty(exports, '__esModule', { value: true });
/******/     };
/******/     __webpack_require__.n = function(module) {
/******/         var getter = module && module.__esModule ?
/******/             function getDefault() { return module['default']; } :
/******/             function getModuleExports() { return module; };
/******/         __webpack_require__.d(getter, 'a', getter);
/******/         return getter;
/******/     };
/******/     __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/     __webpack_require__.p = "";
/******/     return __webpack_require__(__webpack_require__.s = "./index.js");
/******/ })
/******/ ({
/***/ "./index.js":
/***/ (function(module, exports) {
eval("//# sourceURL=webpack:///./index.js?");
/***/ })
/******/ });

发觉其打包产出是一个FFII,参数为由模块名和模块文件处理成的函数组成的对象,由此,我们可以猜测 webpack在打包时做了模块文件到函数的转换。我们再把入口文件内容恢复,再看一下打包结果的FFII参数。

clipboard.png

除了 src/js/test.jssrc/css/index.css 模块以外还有 node_modules 里面的 css-loaderstyle-loader。由此,我们可以猜测 webpack在打包时做了模块依赖的解析和深度遍历模块的依赖


luckyyulin
217 声望9 粉丝

有一种鸟没有脚,他的一生只能在天上飞来飞去,飞累了就在风里睡觉,一辈子只能落地一次,那就是他死的时候