Why?
- 提升开发效率
- 降低开发难度
- 提升产品质量
- 降低企业成本
简单划分
5个部分:开发、构建、部署、性能、规范化



图片来源:
开发
模块化发展
一、无模块化标准阶段
1. 文件划分
通过手动管理script标签顺序的方式,变量定义在全局调试困难
2. 命名空间
每个文件导出一个对象,该文件中变量和方法都定义在该对象中,解决全局命名冲突
3. IIFE(立即执行函数)
4. prototype时期
二、模块化标准阶段
1. CJS
node中使用,同步,导出的变量可修改
主要用于服务器端
也可以用在浏览器端,但是需要browserify等工具编译。
2. AMD
和CJS同一时期出现的,RequireJS , AMD是其模块化规范,其最大的优势就是支持各种插件。
它是异步加载的,主要用在浏览器端。
3. CMD UMD
4. ESM
ES6引入
在node端使用CJS和EJS:总结为一句话:.mjs文件总是以 ES6 模块加载,.cjs文件总是以 CommonJS 模块加载,.js文件的加载取决于package.json里面type字段的设置。
特点:双端支持、异步、可以静态分析、导出变量为引用无法修改(但是调用导出的修改方法可以修改)
CJS与ESM的区别
- 使用方式不同:CJS使用require和module.exports进行导入导出,ESM使用import 和export 导入导出。ESM在浏览器端要将script标签的type=”module”,且文件后缀名需要为mjs
- CJS是运行时加载,ESM是编译时输出接口,因此可以进行静态分析从而进行treeshaking等操作。
- CJS输出值拷贝,ESM输出值引用(该引用只读)
- 循环引用时表现不同
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发生什么?
- 构建依赖树
- 解析包版本号
- 下载对应的tar包到本地镜像(unix或类unix系统下的压缩包文件,理解为一个打包了的文件就好,需要解压)
- 将tar包解压到本地缓存。
- 将包从缓存拷贝到项目的node_modules文件夹中。
npm 1 / 2中包的管理呈现嵌套结构
导致3个问题:
- 依赖过深,文件名过长
- 重复安装,占用空间(每个包的依赖都放在自己的node_modules中)
- 模块示例不共享(由第二个问题引出)
npm3 / yarn
扁平化管理,解决嵌套层级深、包重复安装(node中require会一直往上级的node_modules中找,找到就不再安装)问题
又有新问题:
- 幻影依赖Phantom :package.json中未声明的包(一些依赖自己依赖的包)可以直接使用
- 分身依赖Doppelgangers :node_modules安装的不稳定性,不同包依赖不同版本的同一包时产生,见下图
- 平铺算法耗时

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中声明的包。
扁平化+网状结构
扁平:项目直接依赖,软链接
网状:真实的硬链接
对比pnpm 与 yarn / npm
yarn / npm 缺点:
- 幻影依赖
- 分身依赖
- 平铺算法耗时速度慢
pnpm优点:
概括为严格高效快速
- 严格: 解决幻影依赖,只允许使用package.json中声明过的包
- 高效:安装的packages放在一个任何文件夹都可以访问的文件夹里,通过硬链接的方式链接到各个node_modules中,节省了磁盘空间。
- 有了以上特点,安装更快。
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” 指定文件扩展名和自动修复
npx eslint --init // 如果未安装会提示安装
规则:https://eslint.bootcss.com/docs/rules/
插件可能有对应的规则集可以用于extends
eslint插件eslint-plugin-vuehttps://eslint.vuejs.org/user-guide/#usage
module.exports = {"env": {"browser": true,"es2021": true,"node": true},// 继承eslint推荐的规则集,vue基本的规则集,typescript的规则集"extends": ["eslint:recommended","plugin:vue/vue3-recommended","plugin:@typescript-eslint/recommended","./.eslintrc-auto-import.json"],// 新增,解析vue文件中的template"parser": "vue-eslint-parser",// 支持ts的最新语法"parserOptions": {"ecmaVersion": "latest",// 解析vue文件中的script"parser": "@typescript-eslint/parser","sourceType": "module"},// 添加vue和@typescript-eslint插件,增强eslint的能力"plugins": ["vue","@typescript-eslint"],"rules": {"vue/multi-word-component-names": 0,"@typescript-eslint/no-var-requires": 0}}// .vite.config.js// 配合自动导入使用// 配置eslint解析规则,防止报错eslintrc: {enabled: true, // 设置为true自动生成filepath: './.eslintrc-auto-import.json', // Default `./.eslintrc-auto-import.json`globalsPropValue: true, // Default `true`, (true | false | 'readonly' | 'readable' | 'writable' | 'writeable')},
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: 只给必要的配置项,其他的按我说的来!
配置
module.exports = {printWidth: 100, // 超过最大值换行tabWidth: 2, // 缩进数useTabs: false, // 缩进不使用tab,使用空格semi: false, // 句尾添加分号singleQuote: true, // 使用单引号代替双引号proseWrap: 'preserve', // 默认值。因为使用了一些折行敏感型的渲染器(如GitHub comment)而按照markdown文本样式进行折行arrowParens: 'avoid', // (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid:省略括号bracketSpacing: true, // 在对象,数组括号与文字之间加空格 "{ foo: bar }"// disableLanguages: ['vue'],// 不格式化vue文件,vue文件的格式化单独设置// vueIndentScriptAndStyle: true,//是否缩进 Vue 文件中的代码<script>和<style>标签endOfLine: 'auto', // 结尾是 \n \r \n\r autohtmlWhitespaceSensitivity: 'ignore',trailingComma: 'es5', // 在对象或数组最后一个元素后面是否加逗号(在ES5中加尾逗号)}// prettierignore/dist/*.jsonenv.d.ts.local.output.js/node_modules/****/*.svg**/*.sh/public/*.mdpackage.json.config.json.config.js.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
// .stylelintrc.json{"extends": ["stylelint-config-standard","stylelint-config-prettier","stylelint-config-recommended-vue"],"customSyntax": "postcss-less","plugins": ["stylelint-order"],"rules": {"order/order": ["custom-properties","declarations"],"order/properties-order": ["position","top","right","bottom","left","z-index","display","justify-content","align-items","float","clear","overflow","overflow-x","overflow-y","margin","margin-top","margin-right","margin-bottom","margin-left","padding","padding-top","padding-right","padding-bottom","padding-left","width","min-width","max-width","height","min-height","max-height","font-size","font-family","font-weight","border","border-style","border-width","border-color","border-top","border-top-style","border-top-width","border-top-color","border-right","border-right-style","border-right-width","border-right-color","border-bottom","border-bottom-style","border-bottom-width","border-bottom-color","border-left","border-left-style","border-left-width","border-left-color","border-radius","text-align","text-justify","text-indent","text-overflow","text-decoration","white-space","color","background","background-position","background-repeat","background-size","background-color","background-clip","opacity","filter","list-style","outline","visibility","box-shadow","text-shadow","resize","transition"]}}
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-stagednpx mrm lint-staged根据package.json自动化生成husky配置
"lint-staged": {"*.{ts,vue}": ["npm run lint","npm run lint:prettier","npm run stylelint","git add"],"*.{vue,js,ts,jsx,tsx}": "eslint --cache --fix","*.css": "stylelint --fix"},
commitlint
https://commitlint.js.org/#/guides-local-setup
用于规范化commit message
# For Windows:pnpm install --save-dev @commitlint/config-conventional @commitlint/cli# Configure commitlint to use conventional configecho "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
commitlint提交规范

commitizen
http://commitizen.github.io/cz-cli/
pnpm install -D commitizen // 安装Commitizen CLI工具// 初始化npx commitizen init cz-conventional-changelog --save-dev --save-exact// 将git commit 换成 git cz 不行就 npx cz
commit信息规范
https://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html
代码规范完整引入配置
// 集成eslintnpx eslint --init// 安装eslint的prettier插件,用eslint控制prettierpnpm i prettier eslint-plugin-prettier eslint-config-prettier -D//配置命令"lint:prettier":"prettier src/**/*.{html,vue,css,sass,scss,ts,md} --write"// .eslintrc.jsmodule.exports = {"env": {"browser": true,"es2021": true},"extends": [// 一些拓展预设配置,通常是最佳实践'eslint:recommended',// https://eslint.bootcss.com/docs/rules/'plugin:vue/vue3-strongly-recommended',// "plugin:vue/essential", vue2版本'plugin:@typescript-eslint/recommended','plugin:prettier/recommended','prettier', //放最后],parser: 'vue-eslint-parser', // 解析器 用于将代码变成ast"parserOptions": {//解析器的配置项ecmaVersion: 'latest',//版本 可以改为esXXXXparser: '@typescript-eslint/parser',sourceType: 'module',},"plugins": ["vue","@typescript-eslint"],"rules": {'no-irregular-whitespace': 'error','prettier/prettier': 'error','arrow-body-style': 'off','prefer-arrow-callback': 'off',}}//.prettierrc.js// prettier.config.js or .prettierrc.jsmodule.exports = {printWidth: 100, // 超过最大值换行tabWidth: 2, // 缩进数useTabs: false, // 缩进不使用tab,使用空格semi: true, // 句尾添加分号singleQuote: true, // 使用单引号代替双引号proseWrap: 'preserve', // 默认值。因为使用了一些折行敏感型的渲染器(如GitHub comment)而按照markdown文本样式进行折行arrowParens: 'avoid', // (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid:省略括号bracketSpacing: true, // 在对象,数组括号与文字之间加空格 "{ foo: bar }"// disableLanguages: ['vue'],// 不格式化vue文件,vue文件的格式化单独设置vueIndentScriptAndStyle: false,//是否缩进 Vue 文件中的代码<script>和<style>标签endOfLine: 'auto', // 结尾是 \n \r \n\r autohtmlWhitespaceSensitivity: 'ignore',trailingComma: 'es5', // 在对象或数组最后一个元素后面是否加逗号(在ES5中加尾逗号)};//.prettierignore/dist/*.jsonenv.d.ts.local.output.js/node_modules/****/*.svg**/*.sh/public/*.mdpackage.json.config.json.config.js// 引入stylelintpnpm install --save-dev stylelint stylelint-config-standard// 结合prettier使用stylelintpnpm install --save-dev stylelint-config-prettier// vue文件stylelint预设pnpm i stylelint-config-recommended-vue// 引入修复样式顺序插件pnpm install stylelint-order --save-dev// .stylelintrc.json{"extends": ["stylelint-config-standard","stylelint-config-prettier","stylelint-config-recommended-vue"],"plugins": ["stylelint-order"],"rules": {"order/order": ["custom-properties","declarations"],"order/properties-order": ["position","top","right","bottom","left","z-index","display","justify-content","align-items","float","clear","overflow","overflow-x","overflow-y","margin","margin-top","margin-right","margin-bottom","margin-left","padding","padding-top","padding-right","padding-bottom","padding-left","width","min-width","max-width","height","min-height","max-height","font-size","font-family","font-weight","border","border-style","border-width","border-color","border-top","border-top-style","border-top-width","border-top-color","border-right","border-right-style","border-right-width","border-right-color","border-bottom","border-bottom-style","border-bottom-width","border-bottom-color","border-left","border-left-style","border-left-width","border-left-color","border-radius","text-align","text-justify","text-indent","text-overflow","text-decoration","white-space","color","background","background-position","background-repeat","background-size","background-color","background-clip","opacity","filter","list-style","outline","visibility","box-shadow","text-shadow","resize","transition"]}}// lint-stage + huskypnpm install husky -Dnpx husky install// package.json"scripts": {"prepare": "husky install" // 在pnpm install 之后自动运行 pnpm husky install},
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个字符。
<type>(<scope>): <subject>// 空一行<body>// 空一行<footer>
