A同窗开发了模块a,B同窗开发了模块b,在页面下经过以下方式进行引用node
<script src="a.js"></script> <script src="b.js"></script>
这时模块a,模板b中的代码都暴露在全局环境中,若是模块a中定义了一个方法del
。同窗b并不知道,在模块b中也定义了一个方法del
。这时便形成了命名冲突的的问题。如图webpack
C同窗开发了一个公共的工具库utils.js
,D同窗开发了一个公共的组件tab.js
,tab.js
依赖utils.js
。同窗E须要使用D同窗开发的tab.js
,就须要经过以下方式引用web
<script src="util.js"></script> <script src="tab.js"></script>
同窗E本身也开发了一个dailog.js
同时它也依赖util.js
。如今页面同时引用了dialog.js
和tab.js
,代码以下缓存
<script src="util.js"></script> <script src="dialog.js"></script> <scrpt src="tab.js"></script>
同窗E不只须要同时引用这三个js文件,还必须保证文件之间的引用顺序是正确的。同时,从上面的代码咱们没法直接看出模块与模块之间的依赖关系,若是不深刻tab.js
,咱们没法知道tab.js
究竟是只依赖util.js
仍是dialog.js
或者二者都依赖。随着项目逐渐增大,不一样模块之间的依赖关系则会变的愈来愈难以维护也会致使许多模块中大量的变量都暴露在全局环境中。模块化
模块化的规范有不少种, 以下
| 规范 | 实现方案 |
| --- | --- |
| CommonJS | node.js |
| AMD | Require.js |
| CMD | Sea.js
| UMD | |
| ES6 Module | |函数
webpack支持CommonJS,AMD,ESModule等多种模块化方式的语法工具
在webpack中,一切皆模块。下面咱们经过webpack来打包如下代码。经过对打包代码的解析,来一步一步的了解模块化的实现原理。ui
目录结构以下:spa
代码以下:code
// webpack.config.js const path = require('path'); module.exports = { entry: 'a.js', output: { path: path.resolve(__dirname, "dist"), filename: "[name].js" }, resolve: { modules: [path.resolve(__dirname)] }, optimization: { minimize: false } }
// a.js var b = require('b'); module.exports = b.text + ' world';
// b.js exports.text = 'hello';
在simple目录下执行webpack
命令,会在simple目录下生成dist/output.js
文件。
// outout.js // 代码及注释以下 (() => { // 全部导入的模块都存储在__webpack_modules__对象中,而且每一个模块都要一个标识该模块的id var __webpack_modules__ = ({ 847: ((module, __unsed_webpack_exports, __webpack_require__) => { // 模块a... }), 996: ((__unused_webpack_module, exports) => { // 模块b... }) }) var __webpack_module_cache__ = {}; function __webpack_require__(moduleId) { // 检查缓存中不存在847导出对象,防止模块847屡次执行 if (__webpack_module_cache__[moduleId]) { // 从缓存中返回847导出对象 return __webpack_module_cache__[moduleId].exports; } // 1.建立{exports: {}}对象 // 2.像缓存中添加该对象,并让该对象与模块id 847相关联 var module = __webpack_module_cache__[moduleId] = { exports: {} } // 3.经过__webpack_modules__查询模块847 // 4.执行模块847并传入刚刚建立的模块847的导出对象module,以及module.exports等 __webpack_modules__[moduleId](module, module.exports, __webpack_require__); // 5.返回模块847的导出对象 return module.exports; } // 导入模块847 __webpack_require__(847); })()
如上代码咱们能够知道,全部的的模块都存储在__webpack_modules__
对象中,模块的导出对象则存储在__webpack_module_cache__
对象中,咱们定义的模块均可以经过传入moduleId
来调用__webpack_require__
接口来访问该模块以及该模块的导出对象。
当咱们经过__webpack_require__
接口访问模块847
的导出对象时。会先判断__webpack_module_cache__
对象中有没有该模块的导出对象,若是有的话,则直接返回。若是没有的话则会
var module = { exports: {} }
__webpack_module_cache__
对象中__webpack_module_cahce__[moduleId] = module
__webpack_modules__
查询模块847并执行// 传入模块847的导出对象,以及require接口 __webpack_modules__[moduleId](module, module.exports, __webpack_require__)
return module.exports
图解以下:
经过模块化的管理方式
require
接口传入依赖的模块,因此模块与模块之间的依赖关系也是很是明了的。如图a -> b -> c -> d
require
接口会像cache
中添加导出对象。并返回添加的导出对象。require
接口查询cache
对象时,返回cache
中对应的导出对象