美文网首页
webpack解惑

webpack解惑

作者: 风之化身呀 | 来源:发表于2017-12-26 00:26 被阅读133次

1、webpack的模块化原理
webpack 本身维护了一套模块系统,这套模块系统兼容了所有前端历史进程下的模块规范,包括 amd commonjs es6 等

(function(modules) {
  function __webpack_require__(moduleId) {
    var module =  {
      i: moduleId,
      l: false,
      exports: {}
    };
    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    return module.exports;
  }
  return __webpack_require__(0);
})([(function (module, __webpack_exports__, __webpack_require__) {
    // 模块的逻辑代码
    ...
  })]

原理的关键有两点:1、所有的模块都被封装成function (module, webpack_exports, webpack_require){}的形式,2、webpack_require函数,该函数内部有一个module对象,该对象有两个重要属性:i代表模块id,exports代表要暴露给外面的对象。每次调用webpack_require时都会传入一个数字作为模块id,这样不同模块就能被区分,另外该函数将module.exports作为返回值。每个模块的导出值都会被记录在module.exports对象里,其他依赖该模块的模块就能取到对应数据
2、webpack2是如何支持import和require两种引入模块的方式
首先webpack是基于node的,node的模块规范是commonjs,该规范就是使用require和module.exports来引入和导出模块的;其次,es6 module是静态的依赖,所以可以在运行前进行代码转换。import的本质其实就是require,webpack在进行静态分析时会将其转为require。这也说明了在webpack中可以混用import和require,因为二者本质上都是require

3、如何使用webpack2的tree-shaking技术
webpack2的tree-shaking基于ES6的模块静态依赖机制,babel也是可以将ES6模块转换为commenjs模块的,但是你一旦这样做了就会失去tree-shaking技术。所以在使用babel转换ES6时一般会如下配置,即只使用bable的ES6语法转换能力,不使用它的模块处理,而是使用webpack2自己的模块处理。

presets: [['babel-preset-es2015', {modules: false}]]

需要说明的是,即使在 引入模块时使用了 es6 ,但是引入的那个模块却是使用 commonjs 进行输出,这也无法使用tree-shaking。
而第三方库大多是遵循 commonjs 规范的,这也造成了引入第三方库无法减少不必要的引入。
所以对于未来来说第三方库要同时发布 commonjs 格式和 es6 格式的模块。es6 模块的入口由 package.json 的字段 module 指定。而 commonjs 则还是在 main 字段指定。

4、import及export转换为require和module.exports的规则是啥样的

  • es6 的 export default 都会被转换成 exports.default
  • export 的所有输出都会添加到module.exports对象上
  • 使用require去引用ES6模块的export default输出时,注意用require('**').default

5、babel如何转换ES6模块语法

  • 导出
// ES6
export default 123;
export const a = 123;
const b = 3;
const c = 4;
export { b, c };
// 转换后
exports.default = 123;
exports.a = 123;
exports.b = 3;
exports.c = 4;
exports.__esModule = true;

babel 转换 es6 的模块输出逻辑非常简单,即将所有输出都赋值给 exports,并带上一个标志 __esModule 表明这是个由 es6 转换来的 commonjs 输出。

  • 导入
// 1、普通导入
import a from './a.js'     //引入一个 es6 模块中的 default 输出
// babel会这么转
function _interopRequireDefault(obj) {
    return obj && obj.__esModule
        ? obj
        : { 'default': obj };
}
var _a = require('./a.js');
var _a2 = _interopRequireDefault(_a);
var a = _a2['default'];
// 2、通配符引入
import * as a from './a.js'  //将 es6 模块的所有命名输出以及defalut输出打包成一个对象赋值给a变量
// Babel内部这么转
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;
    }
}
// 3、具名引入
import { a } from './a.js'  // 将 es6 模块的a引入
//babel这样转
require('./a.js').a

相关文章

网友评论

      本文标题:webpack解惑

      本文链接:https://www.haomeiwen.com/subject/ywvrgxtx.html