一个完整的的React前端项目配置指南

2019/03/25

不喜欢脚手架配置项目,是因为代码洁癖不想要一行多余的代码,而且定制化也不方便。

其实通用的项目配置起来一点也不麻烦,只要熟悉eslint,babel和webpack就好了。也不喜欢一直重复的创建项目的时候去思考这些问题,所以记录下来自己的配置经验,而且都是通用性的。

.babelrc

想要详细了解babel的使用可以点击这里

工程化的项目少不了babel,babel可以支持es6+的代码,也可以支持还在草案中的特性,只需要针对想要的特性使用相应的plugin即可。

babel7的env更加强大,可以支持任何被纳入规范的特性,所以首先增加env,如果使用react,则需要添加react的preset,这两个preset已经可以满足基本的语法需求了,如果需要用到typescript增加相对应的babel env即可。

但大多数人还会需要用到装饰器,对象属性简写这两个功能,添加对于的插件即可。用来做热更新的react-hot-loader也会要求在babel里加入对应的插件

完备的.babelrc文件如下。

{
"presets": ["@babel/preset-env", "@babel/preset-typescript" , "@babel/preset-react"],
"plugins": [
"react-hot-loader/babel",
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose": true }]
]
}

装饰器和class属性这两个plugin的顺序记得必须装饰器在上,不然可能会出错,这个坑跳了好几次。

需要安装的依赖主要有

react-hot-loader

@babel/preset-env

@babel/preset-react

@babel/plugin-proposal-class-properties

@babel/plugin-proposal-decorators

@babel/polyfill polyfill 会垫在webpack里后边webpack里能看到怎么用,是会编译到代码中的,所以应该在dependencies而不是devDependencies中。

.prettierrc

prettier是一个非常赞的代码美化工具,比如printWidth可以保证一行的代码不超过120个字符,除非是无法中断的大字符串。其他的功能看起来和eslint有几分重复,但两个工具的着手点不一样。一个是代码格式,一个是代码规范。当然规范在一定程度上是包含格式的。但用了肯定没错,因为太好用了。

需要安装prettier作为基础依赖,创建.prettier文件。

{
"eslintIntegration": true,
"stylelintIntegration": true,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 120,
"semi": false,
"useTabs": false
}

.eslintrc.js

配置.eslintrc.js

env指的是代码的环境,比如添加了node环境就可以用process或者__dirname这种全局变量,否则报错。

我一般会把node和浏览器,commonjs和es6都支持了。

extends会有一个基准的配置,recommend会默认支持一些常用的配置,比如不能用console,文件结尾要空行等等。反正用就对了,这些都是最常见的。

parser可以是一个自定义的解析器,这里需要用到babel-eslint,因为一些特性eslint是不知道的,比如proposal中的class属性简写和装饰器,如果不用babel-eslint,eslint就无法知道babel的配置而去报错,当然也可以在eslint中的parserOptions.ecmaFeatures中去管理这些特性,就不需要用babel-eslintle。

parserOptions可以添加一些额外的配置,比如jsx,比如版本,比如sourceType是module,才能用es6module了。

plugin和babel的plugin不一样,和webpack的plugin更加相似,plugin是一套rules的集合。需要用到react和prettier的插件,prettier插件是为了防止和prettier相结合。

rules就是eslint的基本单位,就像babel的基本单位是plugin一样。rules也是优先级最高的就像行内样式一样。每个插件都会带点rules,然后可以自定义这个插件。

module.exports = {
env: {
browser: true,
commonjs: true,
es6: true,
node: true
},
extends: 'eslint:recommended',
parser: 'babel-eslint',
parserOptions: {
ecmaFeatures: {
jsx: true
},
ecmaVersion: 2018,
sourceType: 'module'
},
plugins: ['react', 'prettier'],
rules: {
indent: ['error', 2],
'linebreak-style': ['error', 'unix'],
quotes: ['error', 'single'],
emi: ['error', 'never'],
// react
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error"
}
}

需要安装的依赖有

eslint

babel-eslint

eslint-plugin-react

eslint-plugin-prettier

tslint

tslint让开发更加严谨。是js的超集,tslint以前和eslint是分开的,目前tslint被并入了eslint,可以认为是对eslint的一个增强,提供额外的类型检查功能。所以只需要在eslint的基础上操作就好了。

{
"defaultSeverity": "error",
"compilerOptions": {
"jsx": "preserve",
"experimentalDecorators": true,
"removeComments": true,
"sourceMap": true
},
"jsRules": {},
"rules": {},
"rulesDirectory": []
}

使用typescript需要增加额外的tsconfig.json文件,也需要在.eslintrc.js中使用typescript的parser。

parser: '@typescript-eslint/parser',

需要安装的依赖

@typescript-eslint/parser

@typescript-eslint/typescript-estree

typescript

tslint

除了这些还需要安装一些@types,什么是type呢,可以认为提前定义好的类型,不然tslint就没办法检查内置环境变量的类型使用是否是正确的,一般情况下会用到es6-shim和react,shim是polyfill的另一种称谓。

@types/es6-shim

@types/react

迁移到typescript上可以参考这里 https://www.dodoblog.cn/blog?id=5c998ec94122ac2a34b2c2fb

webpack.config.js

下边的配置都是基于开发环境的配置,生产环境不需要server和plugin,需要把mode改成production。其他的不变。

作为前端打包工具中最强大的东西。也是相对而言配置项最多的工具,想要系统的用好webpack也是比较难的。

const path = require('path'),
webpack = require('webpack'),
HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
entry: ['@babel/polyfill', 'react-hot-loader/patch', './src/index.jsx'],
output: {
filename: 'main.js',
path: path.join(__dirname, 'dist')
},
mode: 'development',
devServer: {
port: 2019,
hot: true
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.(jsx|tsx|ts|js)?$/,
use: ['babel-loader', { loader: 'eslint-loader', options: { fix: true } }],
exclude: /node_modules/
},
{
test: /\.(png|jpg|jpeg|gif)$/,
use: ['url-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
title: 'just dodo',
favicon: './favicon.ico'
}),
new webpack.HotModuleReplacementPlugin(),
new ForkTsCheckerWebpackPlugin()
],
resolve: {
extensions: ['.js', '.jsx', '.json']
}
}

mode需要设置为development,

entry中设置了三个文件,分别是用来做API兼容的polyfill,代码热更新的react-hot-loader/patch

rules,主要还是配置css,scss,js,jsx,tsx还有其他的静态资源的loader

plugins,上边有三个plugin,一个是html-webpack-plugin是用来打包的时候替换html,第二个是设置支持热更新的,第三个是在ts编译的时候放到打包的时候帮助检查和代码分离的一个插件,不用这个插件react-hot-loader无法鉴别哪个文件被修改了,热更新会报错。

resolve extensions可以让webpack支持更多的引入文件不需要后缀名,默认是没有jsx的。

需要安装的依赖有还有其他的loader相关的插件。

webpack

webpack-cli

webpack-dev-server

html-webpack-plugin

react-hot-loader

配置热更新也是一件很重要的事情,可以让开发效率大大提升。

webpack里配置了hot reload的一些必要的配置,也在babel里配置了相应的plugin。react-hot-loader在升级到4.5之后使用起来比较方便。

只需要在app的根入口文件上用react-hot-loader的hot包裹起来就行了,其他的和平常的一样,切记需要在根文件上,要在provider的外层,不然会遇到一些坑的。

// app.js
import React from 'react'
import { HashRouter as Router, Route } from 'react-router-dom'
import TodosPage from './pages/TodosPage'
import { hot } from 'react-hot-loader/root'
import { Provider } from 'react-redux'
import store from './reducers'

@hot
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<Router>
<Route path="/" component={TodosPage} />
</Router>
</Provider>
)
}
}

// index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'

const root = document.getElementById('root')
ReactDOM.render(<App />, root)

package.json

最后需要加上npm run dev的script,还有上边用到的devDependencies和dependencies。

{
"scripts": {
"dev": "webpack-dev-server --config ./config/webpack.config.js"
},
"dependencies": {
"@babel/polyfill": "^7.4.0",
"@types/es6-shim": "^0.31.39",
"@types/react": "^16.8.8",
"@types/webpack-env": "^1.13.9",
"react": "^16.8.5",
"react-dom": "^16.8.5",
"react-hot-loader": "^4.8.0",
"react-redux": "^6.0.1",
"redux": "^4.0.1"
},
"devDependencies": {
"@babel/core": "^7.4.0",
"@babel/plugin-proposal-class-properties": "^7.4.0",
"@babel/plugin-proposal-decorators": "^7.4.0",
"@babel/preset-env": "^7.4.2",
"@babel/preset-react": "^7.0.0",
"@typescript-eslint/parser": "^1.5.0",
"@typescript-eslint/typescript-estree": "^1.5.0",
"babel-eslint": "^10.0.1",
"babel-loader": "^8.0.5",
"css-loader": "^2.1.1",
"eslint": "^5.15.3",
"eslint-loader": "^2.1.2",
"eslint-plugin-prettier": "^3.0.1",
"eslint-plugin-react": "^7.12.4",
"html-webpack-plugin": "^3.2.0",
"node-sass": "^4.11.0",
"prettier": "^1.16.4",
"react-hot-loader": "^4.8.0",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"ts-loader": "^5.3.3",
"tslint": "^5.14.0",
"typescript": "^3.3.4000",
"url-loader": "^1.1.2",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1"
}
}

其他

.gitignore

yarn.lock

嗨,请先登录

加载中...
(๑>ω<๑) 又是元气满满的一天哟