
---
title: 性能优化--webpack初探           
date: 2022/3/29 14:30
tags:                    
- 前端
- 文件下载
- JavaScript             
author: 刘磊         
---

### 概念
本质上，webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时，它会在内部从一个或多个入口点构建一个 依赖图(dependency graph)，然后将你项目中所需的每一个模块组合成一个或多个 bundles，它们均为静态资源，用于展示你的内容。
<!-- more -->
### 模块化
大家在接触到webpack的时候，可能并不知道它有什么用处，只知道它必不可缺而且听着很复杂。那到底为什么要使用它呢？首先需要了解模块化。

```
代码一
    <script src="jquery.js"></script>
　　<script src="jquery_scroller.js"></script>
　　<script src="main.js"></script>
　　<script src="other1.js"></script>
　　<script src="other2.js"></script>
　　<script src="other3.js"></script>
代码二
    var id = ''
    ....
    var id = ''
```
无模块化缺点很明显:
- 代码可读性差难以维护
- 全局变量重复几率大大增加，因为代码都在一个作用域中
- 依赖关系混乱，js代码从上到下执行，因此需要弄清楚js之间的引入依赖关系
......

随着web的发展，简单的网页已经不满足用户需求，代码也随之越来越复杂，在大牛的推动下，js的第一个模块化规范出现了

**commonJs（服务端模块化）**
Nodejs出现开创了一个新的纪元，使得我们可以使用javascript写服务器代码，对于服务端而言必然是需要模块化的。CommonJS对模块的定义非常简单，主要分为模块引用，模块定义和模块标识3部分，基于node来说的，所以前面说的CommonJS都是针对服务端的实现。
- 模块引用
  
```
var add = require('./add.js');
var config = require('config.js');
var http = require('http');
```

- 模块定义
 
```
module.exports.add = function () {
  ...
}
module.exports = function () {
  return ...
}
```

- 模块标识

**(AMD,CMD,UMD,ES6)前端模块化** 
- 服务端加载一个模块，直接就从硬盘或者内存中读取了，消耗时间可以忽略不计
- 浏览器需要从服务端下载这个文件，所以说如果用CommonJS的require方式加载模块，需要等代码模块下载完毕，并运行之后才能得到所需要的API。
- 如果我们在某个代码模块里使用CommonJS的方法require了一个模块，而这个模块需要通过http请求从服务器去取，如果网速很慢，而CommonJS又是同步的，所以将阻塞后面代码的执行，从而阻塞浏览器渲染页面，使得页面出现假死状态。

*ES6模块化*
- ES6 在语言标准的层面上，实现了模块功能，而且实现得相当简单，完全可以取代 CommonJS 和 AMD 规范，成为浏览器和服务器通用的模块解决方案。
- ES6 模块设计思想：尽量的静态化、使得编译时就能确定模块的依赖关系，以及输入和输出的变量（CommonJS和AMD模块，都只能在运行时确定这些东西）。
- 优点：
容易进行静态分析
面向未来的 EcmaScript 标准
- 缺点：
原生浏览器端还没有实现该标准
全新的命令字，新版的 Node.js才支持。

**require与import的区别**

require使用与CommonJs规范，import使用于Es6模块规范；所以两者的区别实质是两种规范的区别；
*CommonJS：*
- 对于基本数据类型，属于复制。即会被模块缓存；同时，在另一个模块可以对该模块输出的变量重新赋值。
- 对于复杂数据类型，属于浅拷贝。由于两个模块引用的对象指向同一个内存空间，因此对该模块的值做修改时会影响另一个模块。
- 当使用require命令加载某个模块时，就会运行整个模块的代码。
- 当使用require命令加载同一个模块时，不会再执行该模块，而是取到缓存之中的值。也就是说，CommonJS模块无论加载多少次，都只会在第一次加载时运行一次，以后再加载，就返回第一次运行的结果，除非手动清除系统缓存。
- 循环加载时，属于加载时执行。即脚本代码在require的时候，就会全部执行。一旦出现某个模块被"循环加载"，就只输出已经执行的部分，还未执行的部分不会输出。

*ES6模块*

- ES6模块中的值属于【动态只读引用】。
- 对于只读来说，即不允许修改引入变量的值，import的变量是只读的，不论是基本数据类型还是复杂数据类型。当模块遇到import命令时，就会生成一个只读引用。等到脚本真正执行时，再根据这个只读引用，到被加载的那个模块里面去取值。
- 对于动态来说，原始值发生变化，import加载的值也会发生变化。不论是基本数据类型还是复杂数据类型。
- 循环加载时，ES6模块是动态引用。只要两个模块之间存在某个引用，代码就能够执行。
