Why?

  1. 提升开发效率
  2. 降低开发难度
  3. 提升产品质量
  4. 降低企业成本

简单划分

5个部分:开发、构建、部署、性能、规范化

image.png
image.png
image.png
图片来源:

开发

模块化、包管理、代码规范

模块化发展

一、无模块化标准阶段

1. 文件划分

通过手动管理script标签顺序的方式,变量定义在全局调试困难

2. 命名空间

每个文件导出一个对象,该文件中变量和方法都定义在该对象中,解决全局命名冲突

3. IIFE(立即执行函数)

进一步划分命名空间

4. prototype时期

最早的模块化雏形就是使用宏注释来标明依赖。

二、模块化标准阶段

1. CJS

node中使用,同步,导出的变量可修改
主要用于服务器端
也可以用在浏览器端,但是需要browserify等工具编译。

2. AMD

和CJS同一时期出现的,RequireJS , AMD是其模块化规范,其最大的优势就是支持各种插件。
它是异步加载的,主要用在浏览器端。

3. CMD UMD

SeaJS:阿里 CMD规范

4. ESM

ES6引入
在node端使用CJS和EJS:总结为一句话:.mjs文件总是以 ES6 模块加载,.cjs文件总是以 CommonJS 模块加载,.js文件的加载取决于package.json里面type字段的设置。
特点:双端支持、异步、可以静态分析、导出变量为引用无法修改(但是调用导出的修改方法可以修改)

CJS与ESM的区别

  1. 使用方式不同:CJS使用require和module.exports进行导入导出,ESM使用import 和export 导入导出。ESM在浏览器端要将script标签的type=”module”,且文件后缀名需要为mjs
  2. CJS是运行时加载,ESM是编译时输出接口,因此可以进行静态分析从而进行treeshaking等操作。
  3. CJS输出值拷贝,ESM输出值引用(该引用只读)
  4. 循环引用时表现不同

https://es6.ruanyifeng.com/#docs/module-loader#%E5%BE%AA%E7%8E%AF%E5%8A%A0%E8%BD%BD
CJS只能取得模块中已加载部分,执行过的脚本会缓存而不会重新执行.
ESM不会缓存,它会认为加载过的模块的接口已经正常输出,开发者要自己保证此时已经可以取得该接口,否则报错。

5. CJS是同步加载,而ESM可以异步加载,可以在顶层使用await命令

6. 相互加载:
CJS只能通过import()方法加载EJS模块

EJS加载CJS模块只能整体加载,不能只加载某项

包管理方案

三大包管理器:npm yarn pnpm
https://liyucang-git.github.io/2021/02/12/%E5%89%8D%E7%AB%AF%E5%8C%85%E7%AE%A1%E7%90%86%E5%99%A8%E5%AF%B9%E6%AF%94-npm-yarn-%E5%92%8C-pnpm/

什么时候需要包管理器?

当我们要使用一些第三方库时,可以通过script标签引入手动管理,但是当依赖变多和需要升级时就会变得很麻烦,这时就可以将包管理的工作交给包管理器,让它帮我们进行包的安装、管理、发布、升级。

包管理器发展

npm1 / 2

npm install发生什么?

  1. 构建依赖树
  2. 解析包版本号
  3. 下载对应的tar包到本地镜像(unix或类unix系统下的压缩包文件,理解为一个打包了的文件就好,需要解压)
  4. 将tar包解压到本地缓存。
  5. 将包从缓存拷贝到项目的node_modules文件夹中。

npm 1 / 2中包的管理呈现嵌套结构
image.png
导致3个问题:

  1. 依赖过深,文件名过长
  2. 重复安装,占用空间(每个包的依赖都放在自己的node_modules中)
  3. 模块示例不共享(由第二个问题引出)

npm3 / yarn

扁平化管理,解决嵌套层级深、包重复安装(node中require会一直往上级的node_modules中找,找到就不再安装)问题
又有新问题:

  1. 幻影依赖Phantom :package.json中未声明的包(一些依赖自己依赖的包)可以直接使用
  2. 分身依赖Doppelgangers :node_modules安装的不稳定性,不同包依赖不同版本的同一包时产生,见下图
  3. 平铺算法耗时

image.png

npm5.x / yarn带有lock文件的平铺node_modules

lock文件用于解决node_modules安装的不稳定性,基本原理就是生成一个lockfile记录依赖版本号

pnpm - 基于符号链接的node_modules结构

https://pnpm.io/zh/blog/2020/05/27/flat-node-modules-is-not-the-only-way
安装的package都存储在一个任何文件夹都可以访问的目录里,并通过硬链接(指向inode,指向真实物理磁盘地址的指针)的方式连接到各个node_modules,以节省磁盘空间(高效)。
package.json指定的依赖解析使用软链接平铺在node_modules文件夹中(指向项目node_modules目录下.pnpm文件夹下依赖的对应绝对路径),只允许使用package.json中声明的包。
image.png
扁平化+网状结构
扁平:项目直接依赖,软链接
网状:真实的硬链接

对比pnpm 与 yarn / npm

yarn / npm 缺点:

  1. 幻影依赖
  2. 分身依赖
  3. 平铺算法耗时速度慢

pnpm优点:
概括为严格高效快速

  1. 严格: 解决幻影依赖,只允许使用package.json中声明过的包
  2. 高效:安装的packages放在一个任何文件夹都可以访问的文件夹里,通过硬链接的方式链接到各个node_modules中,节省了磁盘空间。
  3. 有了以上特点,安装更快。

pnpm install

跟 npm install 类似,安装项目下所有的依赖。但对于 monorepo 项目,会安装 workspace 下面所有 packages 的所有依赖。不过可以通过 –filter 参数来指定 package,只对满足条件的 package 进行依赖安装。

代码规范

这一块可以看看这个仓库https://github.com/haixiangyan/linter-tutorial

eslint

诞生于2013年,用nodejs写的一个js代码格式检查工具,可以在不运行代码的情况下发现代码格式错误。
官方文档https://eslint.org/docs/user-guide/command-line-interface
eslint会遵循两个隐式的忽略规则:忽略node_modules/ 忽略 **'.'**开头的文件(除了**.eslintrc.js**
在vite项目中集成eslint
“lint”:”npx eslint . —ext .vue,.js,.ts,.jsx,.tsx —fix” 指定文件扩展名和自动修复
image.png

  1. npx eslint --init // 如果未安装会提示安装

规则:https://eslint.bootcss.com/docs/rules/
插件可能有对应的规则集可以用于extends
eslint插件eslint-plugin-vuehttps://eslint.vuejs.org/user-guide/#usage

  1. module.exports = {
  2. "env": {
  3. "browser": true,
  4. "es2021": true,
  5. "node": true
  6. },
  7. // 继承eslint推荐的规则集,vue基本的规则集,typescript的规则集
  8. "extends": [
  9. "eslint:recommended",
  10. "plugin:vue/vue3-recommended",
  11. "plugin:@typescript-eslint/recommended",
  12. "./.eslintrc-auto-import.json"
  13. ],
  14. // 新增,解析vue文件中的template
  15. "parser": "vue-eslint-parser",
  16. // 支持ts的最新语法
  17. "parserOptions": {
  18. "ecmaVersion": "latest",
  19. // 解析vue文件中的script
  20. "parser": "@typescript-eslint/parser",
  21. "sourceType": "module"
  22. },
  23. // 添加vue和@typescript-eslint插件,增强eslint的能力
  24. "plugins": [
  25. "vue",
  26. "@typescript-eslint"
  27. ],
  28. "rules": {
  29. "vue/multi-word-component-names": 0,
  30. "@typescript-eslint/no-var-requires": 0
  31. }
  32. }
  33. // .vite.config.js
  34. // 配合自动导入使用
  35. // 配置eslint解析规则,防止报错
  36. eslintrc: {
  37. enabled: true, // 设置为true自动生成
  38. filepath: './.eslintrc-auto-import.json', // Default `./.eslintrc-auto-import.json`
  39. globalsPropValue: true, // Default `true`, (true | false | 'readonly' | 'readable' | 'writable' | 'writeable')
  40. },

prettier

先看https://zhuanlan.zhihu.com/p/81764012
再看官方文档https://prettier.io/
使用eslint插件https://www.npmjs.com/package/eslint-plugin-prettier
一个代码格式化工具:

  • An opinionated code formatter: opinionated 的意思是必须按照它的规定来执行,Vue和React就是unopinionated
  • Supports many languages:支持html js css markdown等
  • Integrates with most editors
  • Has few options: 只给必要的配置项,其他的按我说的来!

配置

  1. module.exports = {
  2. printWidth: 100, // 超过最大值换行
  3. tabWidth: 2, // 缩进数
  4. useTabs: false, // 缩进不使用tab,使用空格
  5. semi: false, // 句尾添加分号
  6. singleQuote: true, // 使用单引号代替双引号
  7. proseWrap: 'preserve', // 默认值。因为使用了一些折行敏感型的渲染器(如GitHub comment)而按照markdown文本样式进行折行
  8. arrowParens: 'avoid', // (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid:省略括号
  9. bracketSpacing: true, // 在对象,数组括号与文字之间加空格 "{ foo: bar }"
  10. // disableLanguages: ['vue'],
  11. // 不格式化vue文件,vue文件的格式化单独设置
  12. // vueIndentScriptAndStyle: true,
  13. //是否缩进 Vue 文件中的代码<script>和<style>标签
  14. endOfLine: 'auto', // 结尾是 \n \r \n\r auto
  15. htmlWhitespaceSensitivity: 'ignore',
  16. trailingComma: 'es5', // 在对象或数组最后一个元素后面是否加逗号(在ES5中加尾逗号)
  17. }
  18. // prettierignore
  19. /dist/*
  20. .json
  21. env.d.ts
  22. .local
  23. .output.js
  24. /node_modules/**
  25. **/*.svg
  26. **/*.sh
  27. /public/*
  28. .md
  29. package.json
  30. .config.json
  31. .config.js
  32. .eslintrc.js

Stylelint

css样式代码的格式化工具
https://stylelint.io/user-guide/get-started
https://www.npmjs.com/package/eslint-plugin-prettier 修复样式顺序插件
样式顺序https://www.npmjs.com/package/stylelint-order
less支持https://www.npmjs.com/package/postcss-less

  1. // .stylelintrc.json
  2. {
  3. "extends": [
  4. "stylelint-config-standard",
  5. "stylelint-config-prettier",
  6. "stylelint-config-recommended-vue"
  7. ],
  8. "customSyntax": "postcss-less",
  9. "plugins": [
  10. "stylelint-order"
  11. ],
  12. "rules": {
  13. "order/order": [
  14. "custom-properties",
  15. "declarations"
  16. ],
  17. "order/properties-order": [
  18. "position",
  19. "top",
  20. "right",
  21. "bottom",
  22. "left",
  23. "z-index",
  24. "display",
  25. "justify-content",
  26. "align-items",
  27. "float",
  28. "clear",
  29. "overflow",
  30. "overflow-x",
  31. "overflow-y",
  32. "margin",
  33. "margin-top",
  34. "margin-right",
  35. "margin-bottom",
  36. "margin-left",
  37. "padding",
  38. "padding-top",
  39. "padding-right",
  40. "padding-bottom",
  41. "padding-left",
  42. "width",
  43. "min-width",
  44. "max-width",
  45. "height",
  46. "min-height",
  47. "max-height",
  48. "font-size",
  49. "font-family",
  50. "font-weight",
  51. "border",
  52. "border-style",
  53. "border-width",
  54. "border-color",
  55. "border-top",
  56. "border-top-style",
  57. "border-top-width",
  58. "border-top-color",
  59. "border-right",
  60. "border-right-style",
  61. "border-right-width",
  62. "border-right-color",
  63. "border-bottom",
  64. "border-bottom-style",
  65. "border-bottom-width",
  66. "border-bottom-color",
  67. "border-left",
  68. "border-left-style",
  69. "border-left-width",
  70. "border-left-color",
  71. "border-radius",
  72. "text-align",
  73. "text-justify",
  74. "text-indent",
  75. "text-overflow",
  76. "text-decoration",
  77. "white-space",
  78. "color",
  79. "background",
  80. "background-position",
  81. "background-repeat",
  82. "background-size",
  83. "background-color",
  84. "background-clip",
  85. "opacity",
  86. "filter",
  87. "list-style",
  88. "outline",
  89. "visibility",
  90. "box-shadow",
  91. "text-shadow",
  92. "resize",
  93. "transition"
  94. ]
  95. }
  96. }

lint_staged+husky

https://www.npmjs.com/package/lint-staged
https://typicode.github.io/husky/#/?id=install
lint-staged在commit之前运行配置的任务,只会对暂存区的文件运行任务(如linter等)
husky: git 客户端的hook工具,比如 pre-commit 钩子就会在你执行 git commit 的触发。
https://github.com/okonet/lint-staged
npx mrm lint-staged根据package.json自动化生成husky配置
image.png

  1. "lint-staged": {
  2. "*.{ts,vue}": [
  3. "npm run lint",
  4. "npm run lint:prettier",
  5. "npm run stylelint",
  6. "git add"
  7. ],
  8. "*.{vue,js,ts,jsx,tsx}": "eslint --cache --fix",
  9. "*.css": "stylelint --fix"
  10. },

commitlint

https://commitlint.js.org/#/guides-local-setup
用于规范化commit message

  1. # For Windows:
  2. pnpm install --save-dev @commitlint/config-conventional @commitlint/cli
  3. # Configure commitlint to use conventional config
  4. echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js

commitlint提交规范

前端工程化认识 - 图9

commitizen

http://commitizen.github.io/cz-cli/

  1. pnpm install -D commitizen // 安装Commitizen CLI工具
  2. // 初始化
  3. npx commitizen init cz-conventional-changelog --save-dev --save-exact
  4. // 将git commit 换成 git cz 不行就 npx cz

commit信息规范

https://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html

代码规范完整引入配置

  1. // 集成eslint
  2. npx eslint --init
  3. // 安装eslint的prettier插件,用eslint控制prettier
  4. pnpm i prettier eslint-plugin-prettier eslint-config-prettier -D
  5. //配置命令
  6. "lint:prettier":"prettier src/**/*.{html,vue,css,sass,scss,ts,md} --write"
  7. // .eslintrc.js
  8. module.exports = {
  9. "env": {
  10. "browser": true,
  11. "es2021": true
  12. },
  13. "extends": [
  14. // 一些拓展预设配置,通常是最佳实践
  15. 'eslint:recommended',
  16. // https://eslint.bootcss.com/docs/rules/
  17. 'plugin:vue/vue3-strongly-recommended',
  18. // "plugin:vue/essential", vue2版本
  19. 'plugin:@typescript-eslint/recommended',
  20. 'plugin:prettier/recommended',
  21. 'prettier', //放最后
  22. ],
  23. parser: 'vue-eslint-parser', // 解析器 用于将代码变成ast
  24. "parserOptions": {
  25. //解析器的配置项
  26. ecmaVersion: 'latest',
  27. //版本 可以改为esXXXX
  28. parser: '@typescript-eslint/parser',
  29. sourceType: 'module',
  30. },
  31. "plugins": [
  32. "vue",
  33. "@typescript-eslint"
  34. ],
  35. "rules": {
  36. 'no-irregular-whitespace': 'error',
  37. 'prettier/prettier': 'error',
  38. 'arrow-body-style': 'off',
  39. 'prefer-arrow-callback': 'off',
  40. }
  41. }
  42. //.prettierrc.js
  43. // prettier.config.js or .prettierrc.js
  44. module.exports = {
  45. printWidth: 100, // 超过最大值换行
  46. tabWidth: 2, // 缩进数
  47. useTabs: false, // 缩进不使用tab,使用空格
  48. semi: true, // 句尾添加分号
  49. singleQuote: true, // 使用单引号代替双引号
  50. proseWrap: 'preserve', // 默认值。因为使用了一些折行敏感型的渲染器(如GitHub comment)而按照markdown文本样式进行折行
  51. arrowParens: 'avoid', // (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid:省略括号
  52. bracketSpacing: true, // 在对象,数组括号与文字之间加空格 "{ foo: bar }"
  53. // disableLanguages: ['vue'],
  54. // 不格式化vue文件,vue文件的格式化单独设置
  55. vueIndentScriptAndStyle: false,
  56. //是否缩进 Vue 文件中的代码<script>和<style>标签
  57. endOfLine: 'auto', // 结尾是 \n \r \n\r auto
  58. htmlWhitespaceSensitivity: 'ignore',
  59. trailingComma: 'es5', // 在对象或数组最后一个元素后面是否加逗号(在ES5中加尾逗号)
  60. };
  61. //.prettierignore
  62. /dist/*
  63. .json
  64. env.d.ts
  65. .local
  66. .output.js
  67. /node_modules/**
  68. **/*.svg
  69. **/*.sh
  70. /public/*
  71. .md
  72. package.json
  73. .config.json
  74. .config.js
  75. // 引入stylelint
  76. pnpm install --save-dev stylelint stylelint-config-standard
  77. // 结合prettier使用stylelint
  78. pnpm install --save-dev stylelint-config-prettier
  79. // vue文件stylelint预设
  80. pnpm i stylelint-config-recommended-vue
  81. // 引入修复样式顺序插件
  82. pnpm install stylelint-order --save-dev
  83. // .stylelintrc.json
  84. {
  85. "extends": [
  86. "stylelint-config-standard",
  87. "stylelint-config-prettier",
  88. "stylelint-config-recommended-vue"
  89. ],
  90. "plugins": [
  91. "stylelint-order"
  92. ],
  93. "rules": {
  94. "order/order": [
  95. "custom-properties",
  96. "declarations"
  97. ],
  98. "order/properties-order": [
  99. "position",
  100. "top",
  101. "right",
  102. "bottom",
  103. "left",
  104. "z-index",
  105. "display",
  106. "justify-content",
  107. "align-items",
  108. "float",
  109. "clear",
  110. "overflow",
  111. "overflow-x",
  112. "overflow-y",
  113. "margin",
  114. "margin-top",
  115. "margin-right",
  116. "margin-bottom",
  117. "margin-left",
  118. "padding",
  119. "padding-top",
  120. "padding-right",
  121. "padding-bottom",
  122. "padding-left",
  123. "width",
  124. "min-width",
  125. "max-width",
  126. "height",
  127. "min-height",
  128. "max-height",
  129. "font-size",
  130. "font-family",
  131. "font-weight",
  132. "border",
  133. "border-style",
  134. "border-width",
  135. "border-color",
  136. "border-top",
  137. "border-top-style",
  138. "border-top-width",
  139. "border-top-color",
  140. "border-right",
  141. "border-right-style",
  142. "border-right-width",
  143. "border-right-color",
  144. "border-bottom",
  145. "border-bottom-style",
  146. "border-bottom-width",
  147. "border-bottom-color",
  148. "border-left",
  149. "border-left-style",
  150. "border-left-width",
  151. "border-left-color",
  152. "border-radius",
  153. "text-align",
  154. "text-justify",
  155. "text-indent",
  156. "text-overflow",
  157. "text-decoration",
  158. "white-space",
  159. "color",
  160. "background",
  161. "background-position",
  162. "background-repeat",
  163. "background-size",
  164. "background-color",
  165. "background-clip",
  166. "opacity",
  167. "filter",
  168. "list-style",
  169. "outline",
  170. "visibility",
  171. "box-shadow",
  172. "text-shadow",
  173. "resize",
  174. "transition"
  175. ]
  176. }
  177. }
  178. // lint-stage + husky
  179. pnpm install husky -D
  180. npx husky install
  181. // package.json
  182. "scripts": {
  183. "prepare": "husky install" // 在pnpm install 之后自动运行 pnpm husky install
  184. },

git操作

命令

--grep过滤提交历史
git log <last release> HEAD --grep feat

commit信息

type:

  • feat:新功能(feature)
  • fix:修补bug
  • docs:文档(documentation)
  • style: 格式(不影响代码运行的变动)
  • refactor:重构(即不是新增功能,也不是修改bug的代码变动)
  • test:增加测试
  • chore:构建过程或辅助工具的变动

scope用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。
subject是 commit 目的的简短描述,不超过50个字符。

  1. <type>(<scope>): <subject>
  2. // 空一行
  3. <body>
  4. // 空一行
  5. <footer>