WebPack对ESMoudle和CommonJS 的不同处理

1,973 阅读2分钟

ES6支持了原生的Moudle(简称:ESM),在此之前前端的模块化主要依靠CommonJS。
两者在使用上的直观区别是语法不同,但在底层的处理方式是不同的,主要的区别在于两者作用的阶段不一样。

  1. CommonJS是在运行时加载的,因为本质上CommonJS的require只是一个JS函数,只能在JS引擎执行代码时才生效,而ESM是在JS引擎进行静态解析的时候生效的。

  2. ESM输出的是值引用,CommonJS输出的是拷贝。假如我们用ESM声明了模块A,而B和C都引用了A,那么当B修改了A之后,C中的A也会跟着改变。而CommonJS规范在这种情况下,C就不会跟着改变。

这里就思考一个问题,日常开发大型项目,一般是使用了Webpack的。不管你使用什么规范,经过Webpack编译之后,都被集成在一个Bundle中了,并且经验证编译后的JS同样实现了上面的第2条效果。那么Webpack是如何实现的呢? 我们写个DEMO看一看

环境准备

首先,搭建一个简单的Webpack环境 新建一个项目,执行
npm init
npm i webpack --save 配置一下webpack

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

module.exports = {
  // JavaScript 执行入口文件
  entry: './main.js',
  output: {
    // 把所有依赖的模块合并输出到一个 bundle.js 文件
    filename: 'bundle.js',
    // 输出文件都放到 dist 目录下
    path: path.resolve(__dirname, './dist'),
  }
};

创建一个Html入口

// index.html
<html>

<head>
  <meta charset="UTF-8">
</head>
<body>
  <div id="app"></div>
  <script src="./dist/bundle.js"></script>
</body>

</html>

目录如下:

|-- index.html
|-- main.js
|-- webpack.config.js

ESM

声明模块

//esm.js
export let name = 'congxiaobai'
export function show(content) {
    name = content
    console.log(name)
}

引用

//main.js
import {show,name} from './ems'
// 执行 show 函数
console.log(name)
show('Webpack');
console.log(name)

执行结果:

congxiaobai
Webpack Webpack

看一下编译结果:

//bundle.js
(()=>{"use strict";
    let o="congxiaobai";
    console.log(o),
    o="Webpack",
    console.log(o),
    console.log(o)})();

CommonJS

声明模块

//common.js
let name = 'ws'
function show(content) {
    name = content
    console.log(name)
}

// 通过 CommonJS 规范导出 show 函数
module.exports = {
    show:show,
    name:name
};

引用

//main.js
const show = require('./show.js');
console.log(show.name)
show.show('Webpack');
console.log(show.name)

执行结果

congxiaobai
Webpack
congxiaobai

//bundle.js
(() => {
    var o = {
        298: o => {
            let e = "congxiaobai";
            o.exports = {
                show: function (o) { e = o, console.log(e) },
                name: e
            }
        }
    },
    e = {};
    function n(r) {
        var s = e[r];
        if (void 0 !== s) return s.exports;
        var t = e[r] = { exports: {} };
        return o[r](t, t.exports, n), t.exports
    }
    (() => {
        const o = n(298);
        console.log(o.name),
            o.show("Webpack"),
            console.log(o.name)
    })()
})();

总结

由编译结果可知:
1. webpack最终将两种规范都编译成了立即执行函数,并通过闭包来实现commonjs的效果。 2.编译之后,对浏览器来说已经没有所谓的Moudle概念了,都在一个Bundle中了。