天天看点

笔记:前端常用打包工具-webpack原理webpack官方定义

webpack原理与实现

  • webpack官方定义
    • webpack打包原理
    • webpack文件管理
    • 代码分析
    • 总结

webpack官方定义

At its core, webpack is a static module bundler for modern JavaScript applications.

百度翻译:webpack的核心是一个用于现代JavaScript应用程序的静态模块绑定器。

什么意思呢?

简单来说就是一个模块打包的工具。

模块打包带出几个问题思考:

1.对于前端什么是模块?如何定义模块?

对于一些新人可能对javascript模块历史不熟悉的可以跳转这里了解熟悉javascript模块。

2.webpack是如何实现模块打包?

webpack打包原理

1.webpack把前端应用的代码和资源看作是一个个的模块,然后处理这些模块之间依赖的关系最后输出bundle.js文件。

2.对于任意方式定义的模块,webpack都能兼容处理,它是通过loader机制进行转换实现的。

一切都是模块:

每个js文件是一个模块,每个css、html 和image也可以看作是一个个模块,只要它们本身被依赖,例如require(‘cssFile.css’)。

模块加载:

webpack可以将所有模块编译打包输出庞大的bundle.js,这种加载模块方式对于体验是极其不好的,所以webpack可使用许多特性来分割代码生成多个较小的bundle.js文件,通过异步加载的方式请求资源。

笔记:前端常用打包工具-webpack原理webpack官方定义

webpack文件管理

webpack打包通过webpack.config.js描述的相关信息执行,webpack本身是一个node的模块,所以webpack.config.js是以commonjs形式书写的。

// webpack.config.js
module.exports = {
  entry:'./a.js',
  output:{
    filename:'bundle.js'
  }
};
           

1.entry属性是webpack执行打包过程加载文件的入口,属性值被称作是入口文件。

2.output属性是webpack执行打包后输出的文件。

3.webpack会把入口文件进行分析,入口文件代码中所依赖(即require)的资源全部打包在一起,一个资源多次引用的话,也只会打包一份。

4.对于多个入口的情况,其实就是分别独立的执行单个入口情况,每个入口文件都互不相干独立的执行各自的打包程序(可用CommonsChunkPlugin优化)

代码分析

模块a

// a.js
var b = require('./b.js');//  a模块依赖b

console.log('我是a模块');

b.fn();  //执行b模块的b1方法
           

模块b

// b.js
exports.fn = function () {
  console.log('我是B模块方法')
};

           

打包输出的bundle.js文件

// bundle.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] = {
/******/            exports: {},
/******/            id: moduleId,
/******/            loaded: false
/******/        };

/******/        // Execute the module function
/******/        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/        // Flag the module as loaded
/******/        module.loaded = true;

/******/        // Return the exports of the module
/******/        return module.exports;
/******/    }


/******/    // expose the modules object (__webpack_modules__)
/******/    __webpack_require__.m = modules;

/******/    // expose the module cache
/******/    __webpack_require__.c = installedModules;

/******/    // __webpack_public_path__
/******/    __webpack_require__.p = "";

/******/    // Load entry module and return exports
/******/    return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

    var b = __webpack_require__(1);

    console.log('我是a模块');

    b.fn();


/***/ },
/* 1 */
/***/ function(module, exports) {

    exports.fn = function () {
      console.log('我是B模块方法')
    };

/***/ }
/******/ ]);
           

1.bundle.js 是一个匿名的自执行函数,参数则为一个数组。数组的每一项都为个function。function的内容则为每个模块的内容,并按照require的顺序排列。

2._webpack_require是模块加载函数,接收的参数是模块id(每个模块都会有一个独一无二的id,也就是模块数组的索引)

3.有一个模块加载缓存机制,若无加载过得模块则会创建一个模块对象实例,并赋值给installedModules 数组中。

var module = installedModules[moduleId] = {
    exports: {},
   	id: moduleId,
   	loaded: false
 };
           

4._webpack_require加载函数会用call函数去执行每个模块的代码内容,执行对象是上面新创建的模块对象实例的exports属性引用的对象。

笔记:前端常用打包工具-webpack原理webpack官方定义

5.a模块依赖b模块,所以在a模块中调用了webpack加载模块的函数

6.webpack初始化执行第一个模块

总结

遗留思考:

1.上面提到的loader的实现原理是什么?

2.如何实现一个简单的webpack,有哪几个步骤?

3.webpack和其它打包工具如grunt/gulp对比的优劣?