- 前端模块化
- webpack 核心概念
# 背景
前端 Web 应用更加复杂和庞大,应用范围也更加广泛
# 模块化
是指把一个复杂的系统分解到多个模块以方便编码
早期以命名空间来组织代码,如 JQuery 的 $
- 命名空间冲突
- 无法合理管理项目的依赖和版本
- 无法控制依赖加载顺序
# CommonJS
广泛的 JS 规范,核心思想是通过 require 来同步加载依赖的模块
module.exports
暴露接口,Node.js 采用这种方式,后引入到网页开发
优点:
- 可复用于 Node 环境下运行,如同构应用
- 通过 NPM 发布的很多第三方模块很多都使用了 CommonJS 规范
缺点:
- 无法直接运行在浏览器端,需要通过工具转换为 ES5
CommonJS1 不支持 module.exports, CommonJS2 在 1 的基础上增加了,现在一般指 CommonJS2
# AMD
JS 模块化规范,AMD 主要通过异步方式加载依赖的模块,为了解决针对浏览器的环境问题
优点:
- 可在不转换代码的情况下直接在浏览器运行
- 异步加载依赖
- 并行加载依赖
- 可运行在 Node.js 和浏览器环境下
缺点:
JS 运行环境没有原生支持 AMD,需要先引入 AMD 库
# ES6 模块化
在语言层面上实现了模块化。浏览器和 Node.js 都宣布要原生支持。逐渐取代 CommonJS 和 AMD,成为浏览器和服务器通用的模块解决方案。
缺点在于目前运行在大部分 JS 环境下,需通过工具转换为 ES5
# 样式模块化
SCSS:常用的样式片段定义,通过 @import
导入
# 新框架
直接操作 DOM 的方式使代码变得复杂和难以维护,React,Vue,Angular。
# 新语言
# ES6
- 模块规范化
- 箭头函数
let
const
声明代码块内变量- Class
- Async
- Set 和 Map
# TypeScript
JS 的超集,除了提供 ES6,还提供静态检查,开发大型项目时,多个模块,不同人编写,在对接时静态类型检测会检测出可能的问题,语法更啰嗦,无法直接运行在浏览器和 Node 环境
# Flow
类似 TS 的类型检查
# SCSS
CSS 预处理器,更好的管理代码,抽离公共部分,写出更灵活的代码
# 新思想,新框架,新语言共同点
源代码无法直接运行,必须经过转化后才可正常运行
构建:
- 代码转换:TS 转换为 JS,SCSS 转换为 CSS
- 文件优化:压缩代码,压缩图片
- 代码分割:抽离公共代码,提取首屏不执行的代码异步加载
- 模块合并:采用模块化的项目里面有多个模块,需把模块分类合并为一个文件
- 自动刷新:监听本地源代码变化,自动重新构建,刷新浏览器
- 代码校验:在代码发布到仓库前进行校验是否符合规范,以及单元测试是否通过
- 自动发布:更新完代码,自动构建出线上代码传输给发布系统
工程化,自动化的思想在前端的体现,一系列流程用代码去实现,让代码自动执行。解放生产力
大多数构建工具都是 Node.js 开发的:
# NPM Script
安装 Node.js 时附带的包管理。 scripts
底层原理是运行一段 shell 脚本
# Webpack
模块化打包 JS 工具,一切皆模块,通过 Loader 转换文件,通过 Plugin 注入钩子,最后输出多个模块组合的文件。
清晰描述各个模块的依赖关系,以便进行组合和打包,最终会输出浏览器可以使用的静态资源。
优点:
- 专注于处理模块化的项目,开箱即用
- Plugin 扩展,完整好用不失灵活
- 使用场景不限于 web 应用
- 社区庞大活跃,紧跟时代发展
- 良好开发体验
缺点是只能用于采用模块化开发的项目
# Rollup
类似 webpack,专注于 ES6 模块打包,针对 ES6 进行 Tree Shaking,Scope Hoisting 减小输出文件大小提升运行性能。很快被 webpack 模仿和实现。
- webpack 后出现
- 生态链不完善
- 功能不如 webpack,配置和使用更简单
- 不支持 Code Splitting
在打包 JS 库时比 webpack 更加有优势,打包出来更小更快。
# 为什么选择 webpack
- 大多数团队在开发新项目时会采用新技术,"新框架+新语言+模块化",webpack 可以提供一站式解决方案
- 良好的生态链和开发团队,提供良好开发体验和保证质量
- 被大量使用,有各个层面所需的教程和分享
# 核心概念
- Entry 入口文件,构建第一步从入口文件开始,即输入
- Module 模块,一切皆模块,一个模块对应一个文件,会从配置的 Entry 递归找出依赖模块
- Chunk 代码块,一个 Chunk 由多个模块组成,用于代码合并和分割
- Loader 模块转换器,用于将模块原内容按需求转换为新内容
- Plugin 扩展插件,在 Webpack 构建流程中的特定时机注入扩展逻辑来改变构建结果
- Output 输出结构,在 webpack 经过一系列处理并得出最终想要的代码后输出结果
webpack 会从 Entry 里配置的 module 开始递归解析 module 所依赖的所有 module,每找到一个 module,就会根据配置的 loader 找到对应的转换规则,对 module 进行转换后,再解析出当前 module 依赖的 module。这些模块以 Entry 为单位进行分组,一个 Entry 和其所依赖的 module 被分到一个组即一个 Chunk。最后 webpack 会把所有的 Chunk 转换成文件输出。在整个流程中 webpack 会在恰当的时机执行 Plugin 里定义的逻辑。