webpack 模块化

首先,说明两种不同的模块规范:

  • commonjs规范:node应用是由模块组成的,每一个文件都是一个模块,拥有自己的变量、作用域和方法。每个模块内部都会包含一个对象module,这个对象的exports属性是对外的接口,每次加载这个模块都是加载这个属性中的内容,require方法用于加载某个模块。
  • ES6模块规范:ES6模块规范是我们现在常用的,它是通过import进行模块导入、通过export进行模块导出。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。

webpack模块化原理

直接上demo:

// webpack.config.js
const path = require('path');

module.exports = {
  entry: './a.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  }
};
// a.js
import a from './c';

export default 'a.js';
console.log(a);
// c.js

export default 333;
// 打包之后的代码
(function(modules) {

  
  function __webpack_require__(moduleId) {
    var module =  {
      i: moduleId,
      l: false,
      exports: {}
    };
    modules[moduleId].call(module, module.exports, __webpack_require__);
    return module.exports;
  }

  return __webpack_require__(0);
})([
	// 入参数组
  (function (module, __webpack_exports__, __webpack_require__) {

    // 引用 模块 1
    "use strict";
    Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
    /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__c__ = __webpack_require__(1);

/* harmony default export */ __webpack_exports__["default"] = ('a.js');
console.log(__WEBPACK_IMPORTED_MODULE_0__c__["a" /* default */]);

  }),
  (function (module, __webpack_exports__, __webpack_require__) {

    // 输出本模块的数据
    "use strict";
    /* harmony default export */ __webpack_exports__["a"] = (333);
  })
]);

打包之后的代码就是webpack运行时的代码,包括webpack模块的实现。
我们打包之后的代码其实是一个自执行函数。

(function(modules) {

})([]);

自执行函数的入参是各个文件通过babel转码之后组成的code模块数组。
重点在于__webpack_require__函数的实现(webpack自己实现的require函数),这个函数就是webpack自己实现的require函数。该函数本质上就是执行一个模块的代码,然后将相应的导出变量挂载在module.exports对象上。这样就可以在其他模块通过__webpack_require__引入。

注:webpack在最后生成文件的时候会将代码中的require方法替换成__webpack_require__,否则会报错:require is not defined.

在自执行函数执行的最后,会将主文件的输出模块module.exports返回出来,便于日后我们可以require这个包的内容。

最后:这样打包之后的js文件,并不能被其他的文件引用,因为它只作用于当前作用域,这个js文件不能被其他模块通过import或者require的方式引用。

webpack编译后的文件如何被其他模块引用?

webpack通过output.libraryTarget属性来设置打包输出的包的引用方式。
打包输出方式可以参见我的另一篇博客
output.libraryTarget :commonjs2;
会将打包过的代码赋值给module.exports。

这样,就可以在别的模块利用require引用这个模块。

babel的作用

babel在webpack中用来转换es6语法,那它是怎么转换es6语法的呢?

1.处理导出模块

export default 123;

export const a = 123;

const b = 3;
const c = 4;
export { b, c };

babel会将这些都转换成commonjs的exports写法:

exports.default = 123;
exports.a = 123;
exports.b = 3;
exports.c = 4;
exports.__esModule = true;

exports.__esModule = true;表示是由ES6转换来的。

2.处理默认的导入模块

import a from './a.js';
function _interopRequireDefault(obj) {
    return obj && obj.__esModule
        ? obj
        : { 'default': obj };
}

var _a = require('assert');
var _a2 = _interopRequireDefault(_a);

var a = _a2['default'];

最后的 a 变量就是 require 的值的 default 属性。如果原先就是commonjs规范的模块,那么就是那个模块的导出对象。

3.引入 * 通配符

import * as a from './a.js'
function _interopRequireWildcard(obj) {
    if (obj && obj.__esModule) {
        return obj;
    }
    else {
        var newObj = {}; // (A)
        if (obj != null) {
            for (var key in obj) {
                if (Object.prototype.hasOwnProperty.call(obj, key))
                    newObj[key] = obj[key];
            }
        }
        newObj.default = obj;
        return newObj;
    }
}

4.import { a } from './a.js’
直接转换成 require(’./a.js’).a 即可。

总结:由于babel会帮我们将ES6的模块转换为commonjs,所以我们在引入的时候可以混合使用ES6和commonjs规范。

为什么有时候需要使用require(’’).default来引用模块?

babel在对模块进行转换的时候,会把es6的export default转换为exports.default属性,即使这个模块只有一个输出。所以引用的时候我们需要加上default属性来引用这个模块的默认导出。

再来一波模块化预习复习(预习)

  • 前端模块化方案有哪些?

commonjs、AMD、CMD、ESModule等。

  1. Commonjs
    Commonjs是node服务端使用的规范。用同步的方式去加载模块,由于是在服务端,各个模块文件都存储在本地磁盘,同步的方式读取很快,不会出现问题。

2.AMD
AMD规范采用异步的方式去加载模块。模块的加载不会影响到后面代码的实现。所有依赖这个模块的代码,都放在一个回调函数中,当模块加载完毕后才会执行回调。

3.CMD
与AMD类似,CMD推崇后置依赖,在用到某个模块时,才去加载它,而AMD是提前加载所有的模块。

4.ES6 Module
ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。

  • webpack是如何实现模块化的?
    在webpack打包时,babel会将ES6模块转换成commonjs规范,但是我们前面不是说commonjs不能用在浏览器端吗?为什么这里可以?这是因为webpack自己实现了一个require函数,用来加载commonjs模块的内容,使得最后的打包代码可以在浏览器中使用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值