工程化的意义
一家公司想要实现盈利,就需要各个岗位的人分工合作,对各个岗位的管理就是组织管理, 组织管理的目标就是发挥资源的最大效能, 组织管理也需要各种工具, 以降低管理成本, 提高组织效能, 比如SOP, 打卡器...
前端工程化就是前端这个岗位的管理工具, 让不同能力的工程师可以顺利的参与产品开发, 降低开发成本, 提高开发效率
模块化
模块化的思想就是分解和聚合, 分解契合的是主观规律(学科分类), 聚合契合的是客观规律(合作攻关)
函数模块化
// 判断数据是否是素数
function isPrime(n) {
}
// 数组排序
function sort(arr) {
}
// 筛选数组中的素数后排序
function getSortEndPrimies(arr) {
const newArr = []
for(let i = 0; i < arr.length;i++) {
if(isPrime(arr[1])) {
newArr.push(arr[i])
}
}
return sort(newArr)
}
文件模块化
在JS中, 函数的模块是很成熟的, 但是文件的模块化存在全局污染和依赖混乱的问题
模块化要解决的就是文件级别的分解和聚合问题, 拆分的时候能够隐藏内部实现, 不污染全局, 聚合的时候, 依赖不要混乱,明确表达依赖关系
// 数组排序
function sort(arr) {
console.log("降序排序!");
}
// 变量
var name = '张三'
// 数组排序
function sort(arr) {
console.log('升序排序!');
}
// 打印name
function priName() {
console.log(name);
}
<body>
<script src="./1.js"></script>
<script src="./2.js"></script>
<script>
// 全局变量污染
// 同名的方法发生覆盖
sort() // '降序排序'
// 依赖关系混乱
// 无法看出文件的依赖关系
priName() // '张三'
</script>
</body>
模块化标准
CommonJS:
- 简称CJS, 是比较早的, 比较成熟的社区解决方案
- 运行时: 只有代码运行期间才确定依赖关系
if(xxx) {
// 运行到这一行代码, 才确定依赖关系
const a = require('./1.js')
} else {
const b = require(./'2.js')
}
- 不利于代码的优化
Ecmascript Module:
- 简称ESM, 是官方的模块化解决方案
- 编译时: 代码编译期间就确定了依赖关系
// 代码不远行, 也知道依赖关系
import xxx from './1.js'
// 动态导入: ESM也支持运行时, 但是用的少
import('./2.js')
- 有利于代码的优化
其他标准:
- AMD, CMD, UMD, 都已经很少使用
具体实现
标准只是一些规则, 标准的落实要由各种环境去实现, 不同环境支持的标准不一样
浏览器: 只支持ESM标准
node : 支持CJS和ESM标准
构建工具: 不同的构建工具支持的标准不同, 但是webpack, vite, cli都是同时支持CJS和ESM
包管理
所谓包就是一系列模块的集合, 模块化的最小单元就是函数, 其次是文件(模块), 最大单元就是包
- 包和框架在概念上是相近的,都是提供一些列方法, 帮助我们更好的开发
- 在代码结构上是完全不同的:
- 包不限制代码结构, 只要引入包就可以使用相关方法, 比如react/jquery/lodash
- 框架限制代码结构, 要在特定的地方书写特定的代码, 比如vue/uni-app
包管理器
包管理器就是解决使用包的一系列问题, 比如包的下载, 包的卸载 包的升级, 包的发布, 版本控制等
官方的包管理器是npm, npm提供了cli(命令行)工具, 第三方也有GUI(图形化)工具
基于npm还衍生出了yarn和pnpm, 也是很常用的
JS工具链
虽然JS本身也在不断迭代, 但是面对复杂的工程化问题, 我们还是需要使用更多的工具, 提高开发体验
1.兼容性问题
API兼容
随着JS版本的迭代, 一些新的API增强了开发能力, 但是新的API在老版本中不能使用, 这就是API兼容问题
- 解决API兼容问题的思路, 就是polyfill(翻译: 垫片或者填充物), 流行的工具就是core-js
- 他的作用也很简单, 老版本中缺失add方法, 我就定义一个add方法然后填充进去, 这样就抹平了版本的API差异
- 但是core-js并不是万能的, 如果API需要环境的支持, 就没办法通过垫片的方法解决, 不过这种情况很少出现
语法兼容
扩展运算符... / 解构 / async和await 这些新的语法, 在老版本中不支持, 这就是语法兼容问题
- 解决语法兼容问题的思路, 就是语法转译, 把高级语法转成普通语法
- 不同的语法要用不同的工具做兼容性处理
- 有专门做扩展运算符兼容的工具, 也有专门做async/await兼容的工具 ...
2.语言缺陷
所有的语言都有自己的特点, 同时也会有自己的缺点, 通过工具可以优化这些的短板, 核心思想也是语法转译
- jsx语法<h1>xxxx</h1> 转译为 Rreact.createElement('h1', 'xxxx') 普通语法
- ts语法通过 tsc 工具转译为js语法
3.babel
通过工具解决问题是很爽的事情, 但是那么多的工具都要手动安装配置, 就会非常繁琐, 所以就出现了整合工具
- 目前流程的工具是babel, 他提供了各种预设, 当然也支持自定义, 就可以快速使用一系列工具, 解决各种问题
- 预设就是默认的一堆插件, 用的最多的预设就是@babel/preset-env
CSS工具链
总体来说CSS存在两类问题, 语法缺失(循环, 判断, 拼接) 和 功能缺失(颜色函数, 数学函数. 自定义函数)
- sass/less/style等语言是css的超集, 扩展了css的能力,
- 这些语言有自己的编译器,通过编译器可以把代码编译成浏览器识别的css代码
- postcss是后编译器的一种, 可以对css代码进一步优化
- postcss本身不处理代码, 通过配置插件, 实现不同的处理效果, 常见插件有:
- autoprefixer: 自动添加厂商前缀
- cssnano: 压缩css体积
- purgecss: 移除未使用的css
- css module: css模块化
构建工具
现代的开发过程中, 开发和维护的工程与运行时的工程是不一致的, 所以需要构建工具帮助我们进行结构转译
常见的构建工具
- webpack, rollup, esbuild, turbopack, snowpack, grunt, gulp, Rspack
- 这些构建工具的作用都是一样的, 就是进行结构转译
- 在转译的过程中, 构建工具要考虑三个问题
- 哪种工程更适合开发和维护
- 哪种工具更适合运行时
- 如何转译(打包)
- 以上那么多的构建工具, 无非是在这三个层面有不同的考虑
webpack
1. 打包过程:
把入口文件转换成字符串, 构建AST(抽象语法树), 识别出导入语句, 通过模块查找规则, 识别模块间的依赖关系
指定入口文件
指定路径别名
2. 开发服务器:
如果每次修改代码, 都需要打包, 再运行打包结果, 就太麻烦了, 所以webpack内嵌了开发服务器
- 开发服务器的名称webpack-dev-server, 使用了express技术
- live server插件用的也是这个开发服务器
- 开发服务器的作用就是托管静态资源, 通过服务地址就可以访问静态资源, 并且支持HMR(热更新)
3. 文件指纹
文件指纹主要影响缓存, 首次访问资源, 服务器会返回资源, 为了提高加载速度, 浏览器会缓存资源, 当资源变化时, 缓存的资源也要更新, 就是通过文件指纹的对比实现的
资源一旦变化, 文件指纹就会重新生成, 所以浏览器会请求新的资源, 实现资源的更新
4. css modules
打包会合并css, 为了防止css合并过程中可能的类名冲突, 就需要对类名进行处理
5. 源码地图
源码地图记录着源码和打包代码的对应关系, 可以方便我们对代码进行断点调试
- 设置fasel可以关闭源码地图
- 也可以设置其他模式
脚手架
脚手架是对构建工具的进一步封装, 提供交互界面和工程模板, 简化构建工具的配置和使用
常见的脚手架: vue-cli vite cra umijs
标签:思想,模块化,前端,语法,转译,工程化,工具,代码,css From: https://blog.csdn.net/CSDN20221005/article/details/141287146