[译]基于create-react-app打造代码规范化的React项目

2,468 阅读5分钟
原文链接: dumengjie.github.io
原文链接:medium.com/stephenkoo/…

原文标题:Set up create-react-app with: Redux, React Router, Redux Thunk, Prettier, SCSS, Airbnb eslint, Standard stylelint, and CSS modules —— A (very) opinionated guide on setting up Create React App

原文作者:Stephen Koo 翻译:杜梦杰

前言:之前团队内经过讨论和沟通,确定了前端开发规范。规范的执行要由上到下,软硬兼施,除了要求成员们要有自觉性,最好在项目中配置代码规范化/格式化工具。我在配置这些工具时,踩了不少坑,后来有幸看到这篇文章。从头到尾,轻松地将所有工具配置好。本人对于这种规范化的项目比较推崇,拒绝杂乱无章的代码风格,之后的工作中会一直沿用,也推荐大家使用。Keep your code clean!

这是一篇在create-react-app中配置流行包的参考指南。

为了正确的安装这些包,我花了数小时来阅读文档和相关文章,写这篇文章的目的是节省大家的时间。

本指南假定您已经安装了brewnvmyarn。(译者注:原作者使用的是yarn,我在注释中写明了对应的npm命令)

0、安装Create React App

yarn global add create-react-app
// npm install create-react-app -g
create-react-app your-project-name
cd react-base
git init

1、配置SCSS

yarn add node-sass-chokidar npm-run-all
// npm install node-sass-chokidar npm-run-all --save-dev

package.json中添加:

"scripts": {
+    "build-css": "node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/",
+    "watch-css": "npm run build-css && node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/ --watch --recursive",
+    "start-js": "react-scripts start",
+    "start": "npm-run-all -p watch-css start-js",
+    "build": "npm run build-css && react-scripts build",
     "test": "react-scripts test --env=jsdom",

src/App.css 重命名为 src/App.scss

.gitignore中添加:

+# build products
+src/**/*.css

2、配置Prettier

yarn add husky lint-staged prettier
// npm install husky lint-staged prettier --save-dev

新建.prettierrc文件:

{
  'singleQuote': true,
  'trailingComma': 'es5',
}

package.json中添加:

+"lint-staged": {
+  "src/**/*.{js,jsx,json,scss,css}": [
+    "prettier --config .prettierrc --write",
+    "git add"
+  ]
+},
"scripts": {
+    "precommit": "lint-staged",
     "build-css": "node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/",

使用如下命令格式化整个项目:

./node_modules/.bin/prettier --config .prettierrc --write "src/**/*.{js,jsx,scss,css}"

编辑器中整合Prettier。(译者注:非常推荐安装编辑器插件,1+1>2)

3、配置eslint和eslint-config-airbnb

查看并安装eslint-config中的所有依赖:

npm info "eslint-config-airbnb@latest" peerDependencies

可以这样安装(Linux/OSX用户):

(
  export PKG=eslint-config-airbnb;
  npm info "$PKG@latest" peerDependencies --json | command sed 's/[\{\},]//g ; s/: /@/g' | xargs yarn add --dev "$PKG@latest"
)

或(Windows用户):

npm install -g install-peerdeps
install-peerdeps --dev eslint-config-airbnb

新建.eslintrc.js

module.exports = {
  'env': {
    'browser': true,
    'jest': true,
    'es6': true,
    'node': true,
  },
  'extends': [
    'airbnb',
    'prettier',
  ],
  'plugins': [
    'prettier',
  ],
  'rules': {
    'prettier/prettier': ['error', {
      'singleQuote': true,
      'trailingComma': 'es5'
    }],
  },
  'parserOptions': {
    'ecmaFeatures': {
      'jsx': true,
    }
  }
}

src/registerServiceWorker.js文件开头处添加:

+ /* eslint-disable no-console, no-param-reassign, no-use-before-define */
// In production, we register a service worker to serve assets from local cache.

检查现有代码

自动修复一些eslint问题:

node_modules/.bin/eslint --ext=js --ext=jsx --fix .

修改src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(React.createElement(App), document.getElementById('root'));
registerServiceWorker();

src/App.js 重命名为 src/App.jsx并修改:

import React from 'react';
import logo from './logo.svg';
import './App.css';
const App = () => (
  <div className="App">
    <div className="App-header">
      <img src={logo} className="App-logo" alt="logo" />
      <h2>Welcome to React</h2>
    </div>
    <p className="App-intro">
      To get started, edit <code>src/App.js</code> and save to reload.
    </p>
  </div>
);
export default App;

src/App.test.js 重命名为 src/App.test.jsx并修改:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
  const div = document.createElement('div');
  ReactDOM.render(<App />, div);
});

4、配置stylelint和stylelint-config-standard

yarn add stylelint stylelint-config-standard --dev
// npm install stylelint-config-standard --save-dev

新建.stylelintrc

{
  'extends': 'stylelint-config-standard',
}

5、配置eslint和stylelint命令

修改package.json

"lint-staged": {
 + "src/**/*.{js,jsx,json}": [
 +   "eslint --fix",
 +   "prettier --config .prettierrc --write",
 +   "git add"
 + ],
 + "src/**/*.{scss,css}": [
 +   "stylelint --config=.stylelintrc --fix",
 +   "prettier --config .prettierrc --write",
 +   "git add"
 + ]
  },
  "scripts": {
    "precommit": "lint-staged",
    "build-css": "node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/",
    "watch-css": "npm run build-css && node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/ --watch --recursive",
    "start-js": "react-scripts start",
    "start": "npm-run-all -p watch-css start-js",
    "build": "npm run build-css && react-scripts build",
+   "test:lint:js": "eslint --ext=js --ext=jsx .",
+   "test:lint:scss": "stylelint --config=.stylelintrc '**/*.scss'",
+   "test:lint": "run-s test:lint:**",
+   "test:unit": "react-scripts test --env=jsdom",
+   "test": "run-s test:**",
    "eject": "react-scripts eject",
    "eslint-check": "eslint --print-config .eslintrc.js | eslint-config-prettier-check"
  },

6、配置Redux、React Router和Redux Thunk

yarn add redux react-redux react-router-dom react-router-redux@next redux-thunk
// npm install react-redux react-router-dom react-router-redux@next redux-thunk --save

7、配置CSS Modules

  • 警告:本操作需要暴露(eject)create-react-app的配置
  • nulogycss-loader中的相关内容
yarn eject
// npm eject
yarn install
// npm install

修改config/webpack.config.dev.js

{
  loader: require.resolve('css-loader'),
  options: {
    importLoaders: 1,
+   modules: true,
+   localIdentName: "[name]__[local]--[hash:base64:5]"
  },
},

修改config/webpack.config.prod.js

{
  loader: require.resolve('css-loader'),
  options: {
    importLoaders: 1,
+   modules: true,
    minimize: true,
    sourceMap: true,
   },
},

修正现有CSS路径

删除css/scss文件类名中的 ‘-’ 。

修改 src/App.jsx

import React from 'react';
import logo from './logo.svg';
import styles from './App.css';
const App = () => (
  <div className={styles.App}>
    <div className={styles.header}>
      <img src={logo} className={styles.logo} alt='logo' />
      <h2>Welcome to React</h2>
    </div>
    <p className={styles.intro}>
      To get started, edit <code>src/App.js</code> and save to reload.
    </p>
  </div>
);
export default App;

最终成果

最终成果在下面两个Github仓库中:

其他一些有用的包

你可能会用到下面的一些包:

下面列出了create-react-app已使用的包(eject后可以看到)做参考,不要重复安装:

“autoprefixer”: “7.1.2”,
“babel-core”: “6.25.0”,
“babel-eslint”: “7.2.3”,
“babel-jest”: “20.0.3”,
“babel-loader”: “7.1.1”,
“babel-preset-react-app”: “^3.0.2”,
“babel-runtime”: “6.26.0”,
“case-sensitive-paths-webpack-plugin”: “2.1.1”,
“chalk”: “1.1.3”,
“css-loader”: “0.28.4”,
“dotenv”: “4.0.0”,
“eslint”: “4.4.1”,
“eslint-config-react-app”: “².0.0”,
“eslint-loader”: “1.9.0”,
“eslint-plugin-flowtype”: “2.35.0”,
“eslint-plugin-import”: “2.7.0”,
“eslint-plugin-jsx-a11y”: “5.1.1”,
“eslint-plugin-react”: “7.1.0”,
“extract-text-webpack-plugin”: “3.0.0”,
“file-loader”: “0.11.2”,
“fs-extra”: “3.0.1”,
“html-webpack-plugin”: “2.29.0”,
“jest”: “20.0.4”,
“object-assign”: “4.1.1”,
“postcss-flexbugs-fixes”: “3.2.0”,
“postcss-loader”: “2.0.6”,
“promise”: “8.0.1”,
“react”: “^15.6.1”,
“react-dev-utils”: “⁴.0.1”,
“react-dom”: “^15.6.1”,
“style-loader”: “0.18.2”,
“sw-precache-webpack-plugin”: “0.11.4”,
“url-loader”: “0.5.9”,
“webpack”: “3.5.1”,
“webpack-dev-server”: “2.7.1”,
“webpack-manifest-plugin”: “1.2.1”,
“whatwg-fetch”: “2.0.3”