一 ESLint
行业里优秀的ESLint规范实践 Airbnb:eslint-config-airbnb/eslint-config-airbnb-base 腾讯:
- alloyteam团队:eslint-config-alloy
- ivweb团队:eslint-config-ivweb
01 ESLint 如何落地
- 和CI/CD系统集成
- 和webpack集成
npm i -D eslint eslint-plugin-import eslint-plugin-react eslint-plugin-jsx-a11y
npm i -D eslint-loader
npm i -D eslint-config-airbnb
.eslintrc.js
module.exports = {
"parser":"babel-eslint",
"extends": "airbnb",
"env":{
"browser": true,
"node":true
},
"rules":{
"semi":"error"
}
}
方案一:webpack与CI/CD集成
本地开发阶段增加precommit钩子 安装husky npm i husky -S 增加npm script,通过lint-staged 增量检查修改的文件
"scripts":{
"precommit": "lint-staged"
},
"lint-staged":{
"linters":{
"*.{js,scss}":["eslint --fix", "git add"]
}
}
方案二:webpack与ESLint集成
使用eslint-loader,构建时检查JS规范
module.exports={
module:{
rules:[
{
test:/\.js$/,
exclude:/node_modules/,
use:[
"babel-loader",
"eslint-loader"
]
}
]
}
}
02 EsLint
npx eslint --init
npx eslint src
.eslintrc.js
module.exports = {
"extends": "airbnb", // 使用airbnb规范
"parser": "babel-eslint", // 解析器
"rules": {
"...": 0, // 忽略某个规范
},
"globals": {
document: false // 禁止全局变量被覆盖
}
}
03 VScode可安装ESLint插件, ESlint
04 无ESlint插件时,可使用webpack插件
npm i eslint-loader -S webpack.config.js
{
devServer: {
everlay: true, // 打包出错时,在浏览器提示
},
rules: [{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'eslint-loader', // 用eslint-loader验证
options: {
fix: true, // 浅显的错误自动修复
cach: true, // 优化打包速度
force: 'pre' // 强制eslint先执行,即使写在babel-loader前面
}
},
'babel-loader'
]
}]
}
05 git 钩子 eslint src
StyleLint
检测CSS使用StyleLint npm i -D stylelint
三 PWA打包配置 Progressive Web Application
将dist目录上传到服务器 package.json模拟
{
"scripts":{
"start": "http-server dist"
}
}
PWA 第一次访问成功,第二次如服务挂掉,将访问缓存 npm i workbox-webpack-plugin -S webpack.prod.js
const WorkboxPlugin = require('workbox-webpack-plugin')
module.exports = {
plugins: [
new WorkboxPlugin.GennerateSw({
clientsClaim: true,
skipWaiting: true
})
]
}
src/index.js
if('serviceWorker' in navigator) {
window.addEventListener('load',()=>{
navigator.serviceWorker.register('./service-worker.js').then(registration =>{
console.log('service-worker registed')
}).catch(error => {
console.error(error)
})
})
}
三 最佳实践
01 使用NPM Scripts 来管理开发命令
- npm start :相当于 npm run start ,用于开发命令,快速启动本地开发服务;
- npm run build :用于生产环境打包;
- 其他命令,类似 npm run test/lint 等,根据相关的需要添加即可
在 中使用cross-env来区分环境。
"scripts": {
"start": "cross-env NODE_ENV=development webpack --config webpack.config.dev.js --mode development",
"build": "cross-env NODE_ENV=production webpack --config webpack.config.prod.js --mode producation",
"analyzer": "cross-env NODE_ENV=production webpack --config webpack.config.analyzer.js --mode producation",
"lint": "lint-staged"
}
02 webpack区分多环境配置
- 通用配置 webpack.config.base.js
- 开发环境配置 webpack.config.dev.js
- 生产环境配置 webpack.config.prod.js
通用配置如entry / loader /plugin等,但是有些需要根据cross-env传入NODE_ENV环境变量进行相关的配置,例如: NODE_ENV=development的时候使用style-loader,而production的时候使用mini-css-extract-plugin的loader将生产环境的CSS生成单独的CSS文件 webpack.config.base.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const isProduction = process.env.NODE_ENV === 'production';
module.exports = {
// ...
module: {
rules: [{
test: /\.css?$/,
use: [
{loader: isProduction ? MiniCssExtractPlugin.loader : 'style-loader'},
{
loader: 'css-loader',
options: {
importLoaders: 1,
sourceMap: !isProduction
}
},
{
loader: 'postcss-loader',
options: {
sourceMap: !isProduction
}
}
]
}]
}
// ...
};
开发环境主要是devServer / API mock等相关配置,这部分注重的是效率,所有打包速度优化也是很重要的
生产环境注重的是线上最优打包配置,包括splitChunks,压缩资源、CDN(在output配置)等相关配置,还可在terser-webpack-plugin中强制去除一些忘记删除的调试信息如debugger / alert
生产不建议生成sourcemap
使用webpack-merge管理配置文件关系
03 合理使用 splitChunks
一定也把握力度,太细不能充分利用HTTP cache,太粗又会导致加载速度慢,这个度一般可按照下面三个原则来拆分代码:
- 变更频次
- 页面 Router
- 动静分离
变更频次
代码按照变更频次来使用 进行拆分,即将这些不经常修改的通用框架和库放到一起作为 代码, 然后把业务代码按照页面间公共部分和私有部分进行拆分
页面 Router
不经常变动的框架和库代码拆分完之后,剩下的是业务代码,业务代码可以根据不同的页面之间公共代码拆分到一起,这样可以保证访问一个页面就可以将框架代码和公共代码缓存到浏览器中,再访问第二个页面就不会增加框架代码和公共代码页面请求了。
动静分离
动静分离指的是页面内使用频次不高或者需要动态异步加载(使用import()或者require.ensure())的模块代码可以单独拆分到各自的chunks,这样保证了页面首屏展现速度,还记得之前介绍过的一个Case 是页面的播放器代码不经常用吗,那就是根据这个原则来拆分代码的。
另外类似 Vue、React 这类单页应用,页面Router之间的代码也是可以异步加载的,整个页面第一个入口就将大框架和当前页面的代码加载进来了,等点击跳到二级页面的时候只需要动态加载对应Router的代码即可。
Lodash使用lodash-es版本,并且按模块使用;