React 移动端组件库搭建---项目搭建
上一篇文章中我们已经实现了一个最简单的框架,接下来我们接着上一篇的成果,继续添加瓦。
配置tslint, eslint
接下来我们开始配置tslint。查看typescript官网,我们会发现,在2019年1月TS官方决定全面采用Eslint作为代码检查的工具。
所以接下来我们只需要在项目中配置eslint就好了,需要注意的是eslint中会搭配typescript-eslint
在项目中安装,eslint的扩展推荐使用alloyTeam的 AlloyTeam的eslint规则
yarn add eslint babel-eslint eslint-config-alloy eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint/eslint-plugin @typescript-eslint/parser --dev
在项目中创建.eslintrc.js
module.exports = {
extends: [
'alloy',
'alloy/react',
'alloy/typescript',
],
plugins: [
"@typescript-eslint",
"react-hooks"
],
env: {
// 这里填入你的项目用到的环境
// 它们预定义了不同环境的全局变量,比如:
//
// browser: true,
// node: true,
// mocha: true,
// jest: true,
// jquery: true
},
globals: {
// 这里填入你的项目需要的全局变量
// false 表示这个全局变量不允许被重新赋值,比如:
//
// myGlobal: false
},
rules: {
semi: ['error', 'never'],
"no-debugger": 'off',
'no-console': 'off',
'no-unused-vars': 'off',
'max-nested-callbacks': 'off',
'react/no-children-prop': 'off',
'typescript/member-ordering': 'off',
'typescript/member-delimiter-style': 'off',
'react/jsx-indent-props': 'off',
'react/no-did-update-set-state': 'off',
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": 'off',
indent: [
'off',
2,
{
SwitchCase: 1,
flatTernaryExpressions: true
}
]
}
}
这样,我们就配置好了代码检测,
在package.json添加新的命令:"lint:page": "eslint src --ext .ts,.tsx"
配置prettier
eslint是我们用来做代码检查的,但是它不包括代码自动格式化我们的错误代码
社区有这么一个工具:prettier,按照教程一步一步配置就好了。
yarn add prettier -D
然后创建prettier.config.js文件
module.exports = {
// 一行最多 100 字符
printWidth: 100,
// 使用 2 个空格缩进
tabWidth: 2,
// 不使用缩进符,而使用空格
useTabs: false,
// 行尾需要有分号
semi: false,
// 使用单引号
singleQuote: true,
// jsx 不使用单引号,而使用双引号
jsxSingleQuote: false,
// 末尾不需要逗号
trailingComma: 'none',
// 大括号内的首尾需要空格
bracketSpacing: true,
// jsx 标签的反尖括号需要换行
jsxBracketSameLine: false,
// 箭头函数,只有一个参数的时候,也需要括号
arrowParens: 'always',
// 每个文件格式化的范围是文件的全部内容
rangeStart: 0,
rangeEnd: Infinity,
// 不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准
proseWrap: 'preserve',
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: 'css',
// 换行符使用 lf
endOfLine: 'lf'
}
在package.json中新增命令:"prettier:page": "prettier --write "src/**/*.{ts,tsx}""
测试方式很简单:在某一个ts文件中写一行超过100字符的字符串,然后运行prettier:page看这个字符串会不会折行就ok了
配置lint-stage 在git commit的时候会执行hook钩子函数,对代码做强制检查
安装husky 与lint-staged yarn add husky lint-staged --dev
更新package.json中的配置
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{ts,tsx}": [
"npm run prettier:page",
"npm run lint:page",
"git add"
]
}
然后在git commit 时就能看到

我们的配置已经生效了。
webpack配置优化
到目前为止,一个能用的项目框架已经搭建起来了,但是在正式的项目中,我们会有一套生产环境,一套开发环境。对应的webpack配置也会分为开发环境配置,和生产环境配置。
接下来我们优化下现有的webpack配置,将它拆分一套基础配置,一套开发环境配置,一套生产环境配置。
先来webpack.base.config.js
const baseConfig = {
entry: [
resolve('src/index.tsx')
],
output: {
filename: '[name].[hash:8].js',
path: resolve('dist')
},
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
loader: [
'babel-loader',
'awesome-typescript-loader'
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: resolve('src/index.html')
}),
new webpack.HotModuleReplacementPlugin()
]
}
我们拆出来的baseConfig,其中只包含了基础的entry和output,而module的rules中包括es-loader和awesome-typescript-loader,当然仅仅这两个loader是肯定不够的,我们项目中经常会用到的file-laoder url-loader等,会在用到的时候再添加到这个配置里。
接下来我们开始配置我们的开发环境webpack配置
const devConfig = merge(baseConfig, {
mode: mode,
devtool:"cheap-module-eval-source-map",
entry: [
'react-hot-loader/patch',
resolve('src/index.tsx')
],
resolve: {
alias: {
'react-dom': '@hot-loader/react-dom'
}
},
module: {
rules: [
{
test: /\.less/,
include: [
resolve('src')
],
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
{ loader: 'less-loader' }
]
}
]
},
devServer: {
port: process.env.PORT || 5678,
publicPath: '',
historyApiFallback: true,
overlay: {
errors: true
},
open: true,
contentBase: resolve('dist'),
hot: true
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
})
在devConfig的配置中,可以看到,我们在入口处添加react hot reload,引入了开发环境的source-map方便查找问题,在alias中添加了react-dom hot reload 的支持,在rules中添加了.less文件的支持,这是应为在开发环境中我们不需要将css代码抽离成不同的文件,但是在实际的项目中,通常我们会根据不同的页面打出不同的css包,再加载到这个页面时才会去请求对应的css。这样做的好处是可以加快首页的加载的速度,减少首页包的体积。
修改package.json的scripts,添加新的命令:
cross-env NODE_ENV=development webpack-dev-server --config ./config/webpack.dev.js --color
然后运行npm run dev

能看到编译成功了,但是我们还是会发现一些问题:
- 每次编译需要的是时间太长,从上图我们看到,我们的第一次编译花费了6835ms,这还是在只引入了react的情况下。这么长的编译时间是需要优化的。
- 编译输出的无用信息太多。
接下来我们针对这两点继续做优化。首先我们来优化输出不友好的问题:
webpack提供了一个配置项叫stats(统计信息)用来输出编译时的信息。
它有一个选项:minimal 只在发生错误或有新的编译时输出。
更新webpack配置:
stats: 'minimal'
然后webpack还有一些在控制输出的插件,我们使用Friendly-errors-webpack-plugin和webpack-dashboard。
Friendly-errors-webpack-plugin 是聚合错误信息,更友好的展示错误信息的不二之选。
webpack-dashboard 则是将更加模块化的展示编译界面。
将这两个插件配置在webpack的plugins中:
new DashboardPlugin(PORT),
new FriendlyErrorsWebpackPlugin({
compilationSuccessInfo: {
messages: [`your application successful start`]
},
clearConsole: true
}),
更新package.json的dev命令:
cross-env NODE_ENV=development webpack-dashboard -- webpack-dev-server --config ./config/webpack.dev.js --color
重新运行 npm run dev

现在的输出就比之前友好多了😝。
然后我们再来考虑下第一次编译时间很长的问题。
首先安装 yarn add speed-measure-webpack-plugin 这个插件能让我们观测到每个loader,每个plugin执行过程中花费的时间
它的使用方法也很简单
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin")
const smp = new SpeedMeasurePlugin()
module.exports = smp.wrap(devConfig)
重新npm run dev

上图发现我们在node_modules文件和ts文件编译过程中花费了较多的时间
接下来我们一步一步优化
resolve: {
extensions: ['.js', '.ts', '.tsx'],
modules: [
resolve('node_modules'),
resolve('src')
]
},
在resolve中配置modules的路径,让webpack减少寻找时间
观察上图我们发现 babel-loader, and awesome-typescript-loader took 3.061 secs 这一步花费了很多了时间,尝试只用一个loader,我们只用awesome-typescript-loader,重新编译,awesome-typescript-loader took 2.64 secs 减少了0.4秒
接下来我们再尝试用thread-loader做一下多核编译尝试
悲催的发现号线awesome-typescript-loader支支持tread-loader
然后我将awesome-typescript-loader 换成了ts-loader。。结果发现ts-loader took 2.071 secs 减少了足足一秒🤣。。。。
整体的时间也从7秒减少到了3.5秒

接下来我们重新配置thread-loader
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
include: [
resolve('src')
],
use: [
{ loader: 'cache-loader' },
{
loader: 'thread-loader',
options: {
works: require('os').cpus().length - 1,
poolTimeout: Infinity
}
},
{
loader: 'ts-loader',
options: {
happyPackMode: true
}
}
]
}
然后重新运行:

到这一步我们的优化基本已经差不多了,当然我们还有很多其他的常规的优化可以做,比如:dll或者externals去掉不需要的编译的包,将我们的react变为通过CDN引入。
完成了开发环境的配置,接下来就是生产环境的配置了
生产环境相对于开发环境就是多了代码压缩,按需引入,已经css抽离。
代码就不贴了。
想要源码的同学可以等我后面的组件开发贴上github地址。