From 6bda967da30e2a452f8e818b3d6e496d01276ac3 Mon Sep 17 00:00:00 2001 From: Sunny-117 Date: Sun, 17 Mar 2024 18:24:40 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B7=A5=E7=A8=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/.DS_Store | Bin 6148 -> 6148 bytes docs/.vitepress/dist | 2 +- docs/.vitepress/engineer.ts | 4 + .../engineering-onepage.md | 1354 ++++++++++++ docs/front-end-engineering/performance.md | 38 + ...57\345\267\245\347\250\213\345\214\226.md" | 1963 +++++++++++++++++ 6 files changed, 3360 insertions(+), 1 deletion(-) create mode 100644 docs/front-end-engineering/engineering-onepage.md create mode 100644 "docs/front-end-engineering/\343\200\220\345\256\214\347\273\223\343\200\221\345\211\215\347\253\257\345\267\245\347\250\213\345\214\226.md" diff --git a/docs/.DS_Store b/docs/.DS_Store index 32baa0bbad1cb41dd2c1f010a0b316ea9c68fac3..58e91c81dbd50805a0cb8652733feb0d31cfcd9a 100644 GIT binary patch delta 73 zcmZoMXfc@J&&aYdU^gQp%Vr)X7DjDRhBSsEhJ1!Rh7tx{hEyP(0;SU#GJ(8QAS?p2 Q(l;|QpJCa|&heKY0A98buK)l5 delta 32 ocmZoMXfc@J&&a$nU^gQp^JX3<7RJq9%zIfTHdt+D=lIJH0G%)itpET3 diff --git a/docs/.vitepress/dist b/docs/.vitepress/dist index 09446220..63f17f51 160000 --- a/docs/.vitepress/dist +++ b/docs/.vitepress/dist @@ -1 +1 @@ -Subproject commit 094462201540f26020e6fa131657a60bcba67070 +Subproject commit 63f17f51c36f7cc082d71783aac3b7eddb157542 diff --git a/docs/.vitepress/engineer.ts b/docs/.vitepress/engineer.ts index d13d7e25..ef95f617 100644 --- a/docs/.vitepress/engineer.ts +++ b/docs/.vitepress/engineer.ts @@ -1,4 +1,8 @@ export default [ + { + text: "前端工程化 OnePage", + link: "/front-end-engineering/engineering-onepage", + }, { text: "前端性能优化方法论", link: "/front-end-engineering/performance", diff --git a/docs/front-end-engineering/engineering-onepage.md b/docs/front-end-engineering/engineering-onepage.md new file mode 100644 index 00000000..84327eac --- /dev/null +++ b/docs/front-end-engineering/engineering-onepage.md @@ -0,0 +1,1354 @@ +# 前端工程化 OnePage + + +## 为什么会出现前端工程化 + +> 模块化:意味着 JS 总算可以开发大型项目(解决 JS 的复用问题) +> +> 组件化:解决 HTML、CSS、JS 的复用问题 +> +> 工程化:前端项目越来越复杂、前端项目模块(组件)越来越多 +> +> 为什么前端项目越来越复杂? +> +> 在书写前端项目的时候,可能会涉及到使用其他的语言,typescript、less/sass、coffeescript,涉及到编译 +> +> 在部署的时候,还需要对代码进行丑化、压缩 +> +> 代码优化:为 CSS 代码添加兼容性前缀 +> +> 前端项目模块(组件)越来越多? +> +> 专门有一个 node_modules 来管理这些可以服用的代码。 +> +> 前端工程化的出现,归根结底,其实就是要解决开发环境和生产环境不一致的问题。 + + +## nodejs对CommonJS的实现 + +为了实现CommonJS规范,nodejs对模块做出了以下处理 + +1. 为了保证高效的执行,仅加载必要的模块。nodejs只有执行到`require`函数时才会加载并执行模块 +> nodejs中导入模块,使用相对路径,并且必须以./或../开头,浏览器可以省略./,nodejs不行 + +2. 为了隐藏模块中的代码,nodejs执行模块时,会将模块中的所有代码放置到一个函数中执行,以保证不污染全局变量。 +```javascript + (function(){ + //模块中的代码 + })() +``` + +3. 为了保证顺利的导出模块内容,nodejs做了以下处理 + 1. 在模块开始执行前,初始化一个值`module.exports = {}` + 2. `module.exports`即模块的导出值 + 3. 为了方便开发者便捷的导出,nodejs在初始化完`module.exports`后,又声明了一个变量`exports = module.exports` +```javascript + (function(module){ + module.exports = {}; + var exports = module.exports; + //模块中的代码 + return module.exports; + })() +//面试题经常考module.exports与module几乎没区别,只是最后返回module.exports +``` +面试 +```javascript +var util = require('./index.js'); + +console.log(module.exports == exports);//没区别 +module.exports = { + getNumber: function () { + count++; + return count; + }, + abc: 123 +} +console.log(module.exports == exports);//module被赋值了,exports={},他两个不一样了。应用:下一题 +// 最终导出的是module.exports +``` +经典面试题 +util.js +```javascript +var count = 0; +module.exports = { + getNumber: function () { + count++; + return count; + }, + abc: 123 +} +exports.bcd = 456; +``` +index.js +```javascript +var util = require('./util.js'); +console.log(util.bcd)//undefined +// 因为最终返回module.exports,当前面被重新赋值,意味着module.exports和exports无关了 +``` +经验:对exports赋值无意义,建议用module.exports + +4. 为了避免反复加载同一个模块,nodejs默认开启了模块缓存,如果加载的模块已经被加载过了,则会自动使用之前的导出结果 + + +过去,JS很难编写大型应用,因为有以下两个问题: + +1. **全局变量污染** +2. **难以管理的依赖关系** + +这些问题,都导致了JS无法进行精细的模块划分,因为精细的模块划分会导致更多的全局污染以及更加复杂的依赖关系 +于是,先后出现了两大模块化标准,用于解决以上两个问题: + +- **CommonJS** +- **ES6 Module** +> 注意:上面提到的两个均是模块化**标准**,具体的实现需要依托于JS的宿主环境 + +## nodejs + +node环境支持 CommonJS 模块化标准,所以,要使用 CommonJS,必须要先安装node + +官网地址:[https://nodejs.org/zh-cn/](https://nodejs.org/zh-cn/) + +nodejs直接运行某个js文件,该文件被称之为入口文件 + +nodejs遵循EcmaScript标准,但由于脱离了浏览器环境,因此: + +1. 你可以在nodejs中使用EcmaScript标准的任何语法或api,例如:循环、判断、数组、对象等 +2. 你不能在nodejs中使用浏览器的 web api,例如:dom对象、window对象、document对象等 +## CommonJS标准和使用 +node中的所有代码均在CommonJS规范下运行 +具体规范如下: + +1. 一个JS文件即为一个模块,一个模块就是一个相对独立的功能,模块中的所有全局代码产生的变量、函数,均不会对全局造成任何污染,仅在模块内使用 +2. 如果一个模块需要暴露一些数据或功能供其他模块使用,需要使用代码`module.exports = xxx`,该过程称之为模块的**导出** +3. 如果一个模块需要使用另一个模块导出的内容,需要使用代码`require("模块路径")` + 1. 路径必须以`./`或`../`开头 + 2. 如果模块文件后缀名为.js,可以省略后缀名 + 3. require函数返回的是模块导出的内容 +4. 模块具有缓存,第一次导入模块时会缓存模块的导出,之后再导入同一个模块,直接使用之前缓存的结果。 + +同时也解决了JS的两个问题 +浏览器里面可以直接用的函数变量都在全局,但是commonjs里面require不在全局,undefined,同理module + +**原理:** require中的伪代码 +```javascript +function require(modulePath){ + //1. 根据传递的模块路径,得到模块完整的绝对路径 + var moduleId = require.resolve(modulePath); + //2. 判断缓存 + if(cache[moduleId]){ + return cache[moduleId]; + } + //3. 真正运行模块代码的辅助函数 + function _require(exports, require, module, __filename, __dirname){ + // 目标模块的代码在这里 + } + //4. 准备并运行辅助函数 + var module = { + exports: {} + }; + var exports = module.exports; + var __filename = moduleId; // 得到模块文件的绝对路径 + var __dirname = ...; // 得到模块所在目录的绝对路径 + _require.call(exports, exports, _require, module, __filename, __dirname);// exports绑定this,说明this == exports + //5. 缓存 module.exports + cache[moduleId] = module.exports; + //6. 返回 module.exports + return module.exports; +} +// 根据传递的模块路径,得到模块完整的绝对路径 +require.resolve = function(modulePath){ + // 略 +} +``` + +1. 根据传递的模块路径,得到模块完整的绝对路径。因为绝对路径不会重复。 + +2. require引入相同模块会有缓存,不会重复加载 + +3. 如果没有缓存。真正运行模块代码的辅助函数 +```javascript +function _require(exports, require, module, __filename, __dirname) { + // 目标模块的代码在这里 +} +``` + +6. 返回 module.exports + +`this === exports === module.exports === {}` + +## 下面的代码执行结果是什么? +```javascript +// a.js +exports.d = 4;//this === exports ==={a:1,d:4} +this.e = 5;//{a:1,d:4,e:5} +console.log(this === exports);//true +console.log(this === module.exports);//false +console.log(exports === module.exports);//false + +// index.js +var a = arguments[1]("./a.js"); +// 原理可知 arguments[1]相当于require +// a === module.exports ===fn {c:3} +console.log(typeof a);//function +console.log(a.a, a.b, a.c, a.d, a.e);//undefined undefined 3 undefined undefined +console.log(arguments.length);//5 +``` +## ES6 module + +由于种种原因,CommonJS标准难以在浏览器中实现,因此一直在浏览器端一直没有合适的模块化标准,直到ES6标准出现 +ES6规范了浏览器的模块化标准,一经发布,各大浏览器厂商纷纷在自己的浏览器中实现了该规范 + +模块的引入:浏览器使用以下方式引入一个ES6模块文件 + +```html +