web-vitals构建小结
web-vitals
是一个用于测量前端性能的库,它提供了一些常用的性能指标,如FCP、LCP、FID、CLS等。 项目地址
让我们看下GoogleChrome开发团队如何构建一个库
用到构建的包前置
- typescript用于ts文件编译
- rollup用于打包成esm、umd、iife文件 rollupjs
- npm-run-all用于串并行执行脚本指令 npm-run-all
- eslint用于质量和规范性检查 eslint
- prettier用于代码格式化 prettier
- husky能使你的提交变得更好 🐶 汪! husky
以下代码是参照web-vitals写的一个demo构建项目,去除了业务代码逻辑 仓库
dev
dev调试,run-p并行执行指令
- dev 在这没做测试的脚本,实则watch文件变化执行编译
// package.json
"scripts": {
"dev": "run-p watch",
"watch": "run-p watch:*",
"watch:ts": "tsc -b -w",
"watch:js": "rollup -c -w",
"clean": "rimraf dist tsconfig.tsbuildinfo",
},
buiid
buiid流程,run-s串行执行每一步指令
- clean 清除上次打包的文件
- tsc编译ts文件
- rollup根据上面编译出来的文件再打包成esm、umd、iife文件
// package.json
"scripts": {
"build:ts": "tsc -b",
"build:js": "rollup -c",
"build": "run-s clean build:ts build:js",
"clean": "rimraf dist tsconfig.tsbuildinfo",
},
// tsconfig.json
{
"compilerOptions": {
"composite": true, // 启用复合项目模式。在这种模式下,TypeScript 编译器会生成一个 .tsbuildinfo 文件,记录项目中每个文件的编译状态。这有助于在构建过程中提高性能,因为它允许编译器只重新编译自上次构建以来已更改的文件。
"declaration": true, // 生成 TypeScript 类型声明文件(.d.ts),这些文件包含了类型的信息,可以被其他 TypeScript 文件导入和使用。
"lib": ["es2017", "DOM"], // 指定编译器包含哪些 ECMAScript 标准库。"es2017" 表示包含 ECMAScript 2017(ES8)的特性,"DOM" 表示包含 Web DOM API。
"module": "nodenext", // 指定模块系统的目标格式。"nodenext" 表示使用 Node.js 的下一个主版本模块系统。
"moduleResolution": "nodenext", // 指定模块解析策略。"nodenext" 表示使用 Node.js 的下一个主版本的解析策略。
"noFallthroughCasesInSwitch": true, // 在 switch 语句中,如果没有 explicit fallthrough(即没有 break)时,编译器会报错。
"noImplicitReturns": true, // 如果函数的每个分支路径都有返回值,则编译器不会隐式地返回 undefined。
"noUnusedLocals": true, // 报告未使用的局部变量。
"noUnusedParameters": true, // 报告未使用的函数参数。
"outDir": "./dist/modules", // 指定输出目录,编译后的 JavaScript 文件将被放置在这个目录下。
"preserveConstEnums": true, // 保持 const 枚举的值不变。
"rootDir": "./src", // 指定项目的根目录,编译器将从这个目录开始编译项目。
"strict": true, // 启用所有严格类型检查选项,包括严格的 null 检查、严格的布尔类型检查等。
"target": "esnext" // 指定 ECMAScript 目标版本。"esnext" 表示使用最新的 ECMAScript 草案版本。
},
"include": ["src/*.ts"], // 指定编译器应该包含的文件和目录。这里表示包含 src 目录下的所有 TypeScript 文件。
"exclude": [] // 指定编译器应该排除的文件和目录。空数组表示不排除任何文件或目录。
}
// rollup.config.js
import babel from '@rollup/plugin-babel';
import terser from '@rollup/plugin-terser';
const configurePlugins = ({module}) => {
return [
babel({
babelHelpers: 'bundled', // 使用_bundled_模式来嵌入Babel的辅助函数,避免在每个文件中重复引入
presets: [
[
'@babel/preset-env', // 使用@babel/preset-env预设来转译代码,使其兼容目标浏览器环境
{
targets: {
browsers: ['ie 11'], // 指定浏览器兼容性目标,这里指定了对IE 11的支持
},
},
],
],
]),
terser({
module, // 指示Terser插件是否在压缩模块代码时应用特定的优化
mangle: true, // 是否启用变量名和函数名的压缩
compress: true, // 是否启用代码的逻辑压缩,移除无用的代码和简化表达式
}),
];
};
const configs = [
{
input: 'dist/modules/index.js', // 指定输入文件的路径
output: {
format: 'esm', // 指定输出模块的格式为ES模块
file: './dist/web-vitals.js', // 指定输出文件的路径
},
plugins: configurePlugins({module: true}), // 应用配置好的插件数组,传入{module: true}表示压缩模块化代码
},
{
input: 'dist/modules/index.js', // 指定输入文件的路径
output: {
format: 'umd', // 指定输出模块的格式为通用模块定义
file: `./dist/web-vitals.umd.cjs`, // 指定输出文件的路径
name: 'webVitals', // 指定全局变量的名称
},
plugins: configurePlugins({module: false}), // 应用配置好的插件数组,传入{module: false}表示不压缩模块化代码
},
{
input: 'dist/modules/index.js', // 指定输入文件的路径
output: {
format: 'iife', // 指定输出模块的格式为立即执行函数表达式
file: './dist/web-vitals.iife.js', // 指定输出文件的路径
name: 'webVitals', // 指定全局变量的名称
},
plugins: configurePlugins({module: false}), // 应用配置好的插件数组,传入{module: false}表示不压缩模块化代码
},
];
export default configs;
eslint
ESLint 是一个可配置的 JavaScript 检查器。它可以帮助你发现并修复 JavaScript 代码中的问题。问题可以指潜在的运行时漏洞、未使用最佳实践、风格问题等。
// .eslintrc
{
"env": {
"browser": true, // 指定代码运行环境为浏览器
"es6": true, // 指定代码使用 ECMAScript 2015 (ES6) 规范
"node": true, // 指定代码运行环境为 Node.js
"mocha": true // 指定代码使用 Mocha 测试框架
},
"parserOptions": {
"sourceType": "module", // 指定代码为 ES6 模块
"ecmaVersion": "latest" // 使用最新的 ECMAScript 版本
},
"overrides": [
{
"files": "wdio.conf.js", // 指定覆盖的文件为 wdio.conf.js
"extends": ["eslint:recommended"], // 继承 ESLint 推荐的规则集
"rules": {
"max-len": "off" // 关闭代码行长度的规则
}
},
{
"files": "src/*.ts", // 指定覆盖的文件为 src 目录下的所有 TypeScript 文件
"parser": "@typescript-eslint/parser", // 使用 @typescript-eslint/parser 解析 TypeScript 代码
"extends": ["plugin:@typescript-eslint/recommended"], // 继承 @typescript-eslint/recommended 规则集
"rules": {
"@typescript-eslint/no-non-null-assertion": "off", // 关闭非空断言的规则
"@typescript-eslint/no-use-before-define": 2, // 开启变量在使用前定义的规则
"@typescript-eslint/explicit-function-return-type": "off", // 关闭函数返回类型显式声明的规则
"@typescript-eslint/explicit-module-boundary-types": "off", // 关闭模块边界类型显式声明的规则
"@typescript-eslint/ban-ts-comment": "off", // 关闭 @ts- 评论的规则
"@typescript-eslint/camelcase": "off", // 关闭驼峰命名的规则
"comma-dangle": ["error", "always-multiline"], // 确保对象字面量属性的逗号在多行时正确悬挂
"indent": ["error", 2], // 确保代码块的缩进为 2 个空格
"node/no-missing-import": "off", // 关闭 Node.js 环境中缺少导入的规则
"node/no-unsupported-features/es-syntax": "off", // 关闭 Node.js 环境中不支持的 ES 语法的规则
"node/no-missing-require": "off", // 关闭 Node.js 环境中缺少 require 的规则
"node/shebang": "off", // 关闭 Node.js 环境中 shebang 的规则
"no-dupe-class-members": "off", // 关闭类成员重复的规则
"prefer-spread": "off", // 关闭使用扩展运算符的规则
"space-before-function-paren": [ // 确保函数圆括号前的空格正确
"error",
{
"anonymous": "always", // 匿名函数圆括号前总是有空格
"named": "never", // 具名函数圆括号前没有空格
"asyncArrow": "always" // 异步箭头函数圆括号前总是有空格
}
]
},
"parserOptions": {
"ecmaVersion": 2018, // 使用 ECMAScript 2018 版本
"sourceType": "module" // 指定代码为 ES6 模块
}
}
]
}
prettier
代码格式化工具
// package.json
{
"prettier": {
"arrowParens": "always", // 总是在箭头函数参数周围添加括号
"bracketSpacing": false, // 在对象字面量括号内不添加空格
"quoteProps": "preserve", // 保持对象属性的引号不变,除非它们需要被添加以满足语法要求
"singleQuote": true // 使用单引号而不是双引号
}
}
husky
在提交或推送时,自动化 检查提交信息、检查代码 和 运行测试。(母鸡典改,试了好多次才触发到pre-commit这个hooks)
- 使用 prepare 来进行 husky install生成.husky目录
- .husky目录下配置pre-commit
- 配置lint-staged 对暂存区中的文件执行指定的脚本
// package.json
"husky": {
"hooks": {
"pre-commit": "npm run lint"
}
},
以上基本能了解到库的打包流程,如需用到更多测试脚本和发包脚本可以看web-vitals的实现