前端工程化入门

HCX大约 6 分钟工程化小白向

为了更好的管理团队,降低管理成本,需要将代码进行统一标准化,为新人或者初级工程师提供便捷的工具,使得其能够更好的发挥自己的作用

一、模块化和包管理

1.1 模块化解决了什么问题?

模块化的思想为分解和聚合。分解契合的是主观规律,即人为主观的进行分解,降低认识的成本,更好的分析问题。而聚合是客观规律,所见到的大部分都是模块聚合的结果

  • 函数层面上来看分解和聚合:

比如说书写一个基本的功能函数,会针对领域内的问题进行细分出来一系列的功能函数(分解),由这些功能函数聚合成要实现的功能(聚合)

  • 文件层面上的分解和聚合:

比函数更高一级的分解和聚合,各个文件里有着不同的功能实现,多个文件聚合成一个大的应用场景

相关信息

文件层面上在前端上有两个问题,是 JS 语言层面上的历史原因导致的,分别是:

  1. 全局污染,在引用多个 JS 文件时,可能发生的命名冲突,没有隐藏内在实现(分解上的实现问题)

  2. 依赖混乱,文件与文件之间的依赖关系不明确,随着系统的复杂性增加,为了进行功能解耦,会做许多细化的分解,因此导致文件越来越多,文件之间的依赖关系形成一个巨大的网格(聚合上的实现问题)

模块化解决的就是文件层面的分解和聚合,在模块化里面有相应的标准

1.2 模块化标准

  • CommonJS CJS 民间标准,运行时
  • Ecmascript Module ESM 官方标准,编译时

一个是运行是才知道具体依赖关系,另一个则是在运行前就能知道依赖关系,在编译时就知道了,能方便提前进行优化

实现层面上:

有了标准后,根据标准进行实现,也就是语言的运行环境

  • 浏览器,只支持官方的标准,不支持 CJS
  • node,CJS 和 ESM 都支持
  • 构建工具,模块化的核心应用场景,webpack、rollup、esbuilder,通常 CJS 和 ESM 都支持

1.3 包管理

包:package,一系列模块的集合。按照聚合程度的由低到高,从函数到文件再到包

相关信息

框架和库的区别,框架会约束代码的书写规则,而库更偏向于功能上的实现,供开发者调用开发

包管理需要考虑的问题有:

  • 从哪里下载?
  • 如何升级?
  • 如何卸载?
  • 如何发布?
  • 版本控制?

目前前端的包管理方案还是 npm

  • 可以通过 package.json 文件中看到包的相关信息

  • registry 更改包的来源

  • cli(command-line interface) 是包的命令行操作界面

由于企业需求和 npm 的缺陷,也有一些其他的包管理器,如

  • pnpm (使用较多)
  • yarn

二、JS 工具链

解决语言层面的缺陷和兼容性考虑

  • 兼容性
    • 语法兼容(可选链,async 等等)
      • syntax transformer(runtime) 语句转换:目前没有大而统一的兼容,一般是一个工具解决一个语法的兼容
    • API 兼容
      • polyfill(垫片): core-js
  • 语法增强
    • jsx 转换工具
    • typescript tsc 转换工具

代码转换工具集成各个 JS 工具链,进行统一转换,如 babel

npm i -D @babel/core @babel/cli

babel 会根据源代码生成抽象语法树 AST,再根据 AST 转换成代码,也就是说如果没有扩展的情况下,代码转换后并无变化

通过插件来修改 AST,从而影响最后的代码生成结果

书写 babel 的配置文件来定义相关插件,babel 预设里面有常见的插件

主要用于处理兼容性: npm i -D @babel/preset-env

// babel.config.js
module.exports = {
  presets: [['@babel/preset-env']],
};

三、CSS 工具链

CSS 中从语言上来说缺少基本循环、判断语句。

从功能上来说,函数仍有不足,颜色函数、数学函数

因此有 sass、less、stylus 出现,来增强 css 语言,通过 css 预编译器生成 css

但这只是语言增强,生成的 css 还有兼容性问题和其他问题

  • 兼容各个浏览器,厂商前缀
  • 代码体积压缩
  • 代码剪枝,去除无用代码

通过后处理器对 css 进行处理从而符合标准

提示

核心其实就是代码转换

预处理器 -> css -> 后处理器(postCSS) -> css

postCSS 和 babel 一样,只负责转换代码,通过插件来实现各个功能

四、构建工具和脚手架

4.1 构建工具

前面二和三说到的都是语言层面上的转换,接下来介绍工程层面上的转换,如何将一个工程目录下的文件转换成传统的html,css,js文件

npm run build 时发生的便是工程的转换

开发和维护的代码和运行时的代码并不一致,结构也不一致

运行时的代码需要考虑具体的兼容

    1. 哪种工程更适合开发和维护?
    1. 哪种工程更适合运行时?传统工程
    1. 如何转换(打包)webpack

webpack 做的工作:

webpack 通过配置的入口区解析字符串,生成 AST,分析依赖关系,进行深层遍历然后打包

webpack 还能运行本地服务器,从而预览代码效果,不用先打包再去运行打包结果

文件指纹,打包生成的文件名中带有哈希值,会随着源码的内容改动而改动。涉及到文件缓存,如请求一个 JS 文件,如果有文件指纹的话,当文件内容更新就会产生新的哈希值,从而使得 html 页面(html 一般不会缓存)里的导入该文件的语句发生变化,向服务器发起请求获取该文件。因为文件名不一致,所以会发起新的请求,而如果没有文件指纹,即使服务器文件内容更新了也无法得知,文件名没有发生变化,使用的还是之前的浏览器本地缓存的文件。

css modules,为了避免类名冲突打包后的 css 类名也发生了变化,如果需要运行时去找到变换后的类名,需要使用导入语句。import styles form './main.less'

source map,源码地图。将运行时的代码和源代码对应起来,方便调试。

相关信息

webpack 的功能并不止上面这些,而开发服务器并不是 webpack 本身的,css modules 时也是专门的库实现的。

webpack 集成了许多的技术,通过 loader 和 plugin 来实现之前讲到的代码转换和兼容

4.2 脚手架

  • vue-cli
  • vite
  • cra

脚手架负责生成工程目录和配置文件

  • 提供界面交互
  • 提供工程模板