webpack前端模块化

2021-11-26 13:18:54 浏览数 (1)

举个例子:一个公司需要正常运转,就有市场部,技术部,人事部等等,这每个部门就相当于一个模块,在前端项目中也就有比如专门网络请求的模块,错误处理的模块,专门渲染的模块。

传统做法会引入多个js脚本,它们共处于全局作用域下,就容易导致全局作用域变量冲突(例如同名变量冲突),而发生一些不可预测的事情。 例如:

代码语言:txt复制
/*moduleA.js里*/
代码语言:txt复制
var a=10;
代码语言:txt复制
/*moduleB.js里*/
代码语言:txt复制
var a=11;
代码语言:txt复制
/*index.html里*/
代码语言:txt复制
<body>
代码语言:txt复制
    <script src="./moduleA.js"></script>
代码语言:txt复制
    <script src="./moduleB.js"></script>
代码语言:txt复制
    <script src="./moduleC.js"></script>
代码语言:txt复制
</body>
代码语言:txt复制
复制代码

当出现上面得冲突后,a的值还能确定吗?——不能!

然后就有人想出,每个js脚本里都使用一个对象包裹,形成一个局部作用域。

代码语言:txt复制
// 定义模块内的局部作用域,以moduleA为例
代码语言:txt复制
    var Susan = {
代码语言:txt复制
        name: "susan",
代码语言:txt复制
        sex: "female",
代码语言:txt复制
        tell: function(){
代码语言:txt复制
            console.log("im susan")
代码语言:txt复制
        }
代码语言:txt复制
    }
代码语言:txt复制
复制代码

但是这样又有各严重的问题,就是对象里值我们能更改,无法保证模块属性内部安全性,对于比如说用户名密码等数据的情景就很严重了。

于是又改进到了立即执行函数和闭包的形式。

代码语言:txt复制
// 定义模块内的闭包作用域(模块作用域),以moduleA为例
代码语言:txt复制
    var SusanModule = (function(){
代码语言:txt复制
        var name = "susan"
代码语言:txt复制
        var sex = "female"
代码语言:txt复制
        functioon tell(){//这样就不能更改其中的数据了
代码语言:txt复制
            console.log("I'm ", this.name)
代码语言:txt复制
        }
代码语言:txt复制
    })()
代码语言:txt复制
复制代码

我们再改进下写法,为立即执行函数写入参数为window

代码语言:txt复制
// 定义模块内的闭包作用域(模块作用域),以moduleA为例
代码语言:txt复制
    (function(window){
代码语言:txt复制
        var name = "susan"
代码语言:txt复制
        var sex = "female"
代码语言:txt复制
        functioon tell(){
代码语言:txt复制
            console.log("I'm ", this.name)
代码语言:txt复制
        }
代码语言:txt复制
        window.susanModule = {tell}
代码语言:txt复制
    })(window)// window作为参数传给
代码语言:txt复制
//////////////////////
代码语言:txt复制
//测试
代码语言:txt复制
window.susanModule.tell(); //im susan
代码语言:txt复制
复制代码

这样大概就是早期的模块化的形式了。

现在的模块化方案有

  • AMD (Asynchronous Module Definition 异步模块定义)
代码语言:txt复制
//大概形式如下
代码语言:txt复制
//定义
代码语言:txt复制
define("mymodule", ["dep1", "dep2"], function(d1, d2) {
代码语言:txt复制
});
代码语言:txt复制
// 加载
代码语言:txt复制
require(["module", "../file"], function(module, file) {
代码语言:txt复制
});
代码语言:txt复制
复制代码
  • CommonJs :Node.js 专用, 该方案的核心思想就是允许模块通过require方案同步加载依赖的其他模块,通过exports或module.exports来暴露出需要的接口。
代码语言:txt复制
// 通过require函数来引用
代码语言:txt复制
const math = require("./math");
代码语言:txt复制
// 通过exports将其导出
代码语言:txt复制
exports.getSum = function(a,b){
代码语言:txt复制
    return a   b;
代码语言:txt复制
}
代码语言:txt复制
复制代码
  • ES6 Module :该方案最大的特点就是静态化,静态化的优势在于可以在编译的时候确定模块的依赖关系以及输入输出的变量。上面提到的CommonJs和AMD都只能在运行时确定这些东西。
代码语言:txt复制
// 通过import函数来引用
代码语言:txt复制
import math from "./math";
代码语言:txt复制
// 通过export将其导出
代码语言:txt复制
export function sum(a, b){
代码语言:txt复制
    return a   b;
代码语言:txt复制
}
代码语言:txt复制
复制代码

此外说说ES6模块化和CommonJs的模块化的区别:

  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。

注意:CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值

ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。

  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。

原因:CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 `ES6

模块`不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。

  • CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。

前端模块化主要解决了两个问题: “命名空间冲突”,“文件依赖管理”

和介绍webpack又有什么关系呢?

在webpack中,一切皆模块。我们在模块化开发的时候,通常会使用`ES

Module或者CommonJS规范导出或引入依赖模块,webpack打包编译的时候,会统一替换成自己的webpack_require`来实现模块的引入和导出,从而实现模块缓存机制,以及抹平不同模块规范之间的一些差异性。

0 人点赞