create-react-app搭建一个完整的项目

☼ 注:笔者的文章是根据自己当前项目做的笔记,具体应用请参照自己实际项目情况

1、创建应用
npx create-react-app my-app
cd my-app
npm start
2、热加载,src/index.js文件
function render() {
    ReactDOM.render(
        ,
        document.getElementById('root'))
}

render()

if (module.hot) {
    module.hot.accept(() => {
        render()
    })
}
3、配置eslint代码规范

⑴ 在根目录新建.eslintrc.js文件

const pkg = require('./package.json')
const reactVersion = () => {
    if (pkg.dependencies && pkg.dependencies.react) {
        return { version: pkg.dependencies.react.replace(/[^0-9.]/g, '') }
    }
    if (pkg.devDependencies && pkg.devDependencies.react) {
        return { version: pkg.devDependencies.react.replace(/[^0-9.]/g, '') }
    }
}

module.exports = {
    "parser": "babel-eslint",
    // 配置规则
    "rules": {
        "strict": 0,
        "no-console": 0,
        "global-require": 0,
        "jsx-a11y/href-no-hash": 0,
        "react/forbid-prop-types": 0,
        "jsx-a11y/no-static-element-interactions": 0,
        'import/no-dynamic-require': 0,
        "import/no-extraneous-dependencies": 0,
        "max-len": ["error", 240],
        "linebreak-style":0,
        "no-eval": 2,
        "indent": ["error", 4, { "SwitchCase": 1 }],
        "no-tabs": 0,
        "comma-dangle": 0,
        "no-array-index-key": 0,
        "arrow-parens": 0,
        "object-shorthand": 0,
        "react/jsx-filename-extension": 0,
        "react/jsx-indent": 0,
        "react/jsx-indent-props": 0,
        "react/require-default-props": 0,
        "react/no-array-index-key": 0,
        "no-prototype-builtins": 0,
        "no-continue": 0,
        "no-restricted-globals": [0],
        "quotes": ["error", "single"],
        "keyword-spacing": ["error", { "before": true }],
        "no-var": 1,
        "semi": ["error", "never"],
        "key-spacing": ["error", {  "afterColon": true }],
        "comma-spacing": ["error", { "before": false, "after": true }],
        "arrow-spacing": ["error", { "before": true, "after": true }],
        "no-multi-spaces": ["error"],
        "no-trailing-spaces": ["error", { "skipBlankLines": true }],
    },
    "env": {
        "browser": true,
        "node": false
    },
    "plugins": [
        "react",
        "jsx-a11y",
        "import"
    ],
    "globals": {
        "DEBUG": false,
        "NORMAL_SERVER": true,
        "CUSTOMER_FLAG": true,
        "IS_USE_NATIVE_CAMERA": true,
        "TOMCAT_SERVER_SIGN_ADDRESS": true,
        "TOMCAT_SERVER_ACCOUNT_HINT_ADDRESS": true,
        "UPLOAD_IMG_OVER_TIME": true,
        "IS_NEED_CREATE_HISTORY": true,
    },
    'settings': {
        'react': {
            ...reactVersion()
        }
    }
}

⑵ 打开【文件】→【首选项】→【设置】→【用户】或【工作区】→【扩展】→【ESLint】→【setting.json】,添加以下代码

"eslint.validate": [
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact"
],

(3) 在【用户】→【扩展】→【ESLint】把【Auto Fix On Save】勾上,就可以在保存代码时自动修复eslint警告了
⑷ 配置eslint检查忽略的文件路径,在根目录新建.eslintignore文件

# product path
build

# lib path
node_modules
config
scripts

☆ 以上配置步骤针对vscode,并且确保已经安装了【ESLint】插件

4、异步加载组件

见笔者文章《react异步加载组件》

5、配置axios

⑴ 安装

npm install axios --save
npm install qs --save

⑵ 在src目录下新建api目录,在api目录下新建一个axios.js文件用于配置axios拦截器
⑶ 在api目录下新建一个config.js

export const HOST = window.location.origin
// 不同环境
export const apiUrl = HOST.includes('cms') ? 'v1/xxx' : 'c/xxx'

⑷ 把项目中需要用到的接口按模块划分,分别新建一个js文件

import axios from '../axios'
import { apiUrl } from '../config'

export default {
    /***
     * 登录检查
     * @method post
     * @return  JSON  data :{"username":account,"password":devpasword};
     *  */
    loginCheck: data => axios.post(apiUrl+'/common/admin/loginCheck.do', data),

    /***
     * 登录
     * @method post
     * @return  JSON  data :{};
     *  */
    login: data => axios.get(apiUrl+'/admin/login.do', data),
}
6、配置proxy跨域代理

见笔者文章《create-react-app和vue-cli配置跨域代理》

7、代理到本地mock数据

⑴ 在config文件夹下新建一个mock.js(名字无所谓,自己起)

const glob = require('glob')
const fs = require('fs')

const files = glob.sync('mock/**/*.json')

module.exports = function (app) {
    files.forEach(file => {
        let data = fs.readFileSync('./' + file, 'utf8')
        app.all(file.slice(4, -5), (req, res) => {
            console.log('req', req.originalUrl)
            res.setHeader('Access-Control-Allow-Origin', '*')
            res.setHeader('Access-Control-Allow-Methods', 'DELETE,GET,HEAD,POST,PUT,OPTIONS,TRACE')
            res.setHeader("Access-Control-Allow-Headers", "X-Custom-Header,accept, Content-Type")
            res.setHeader('Access-Control-Allow-Credentials', 'true')
            res.setHeader('Content-Type', 'application/json;charset=UTF-8')
            res.status(200).send(data)
        })
    })
}

⑵ 在webpackDevServer.config.js文件中,找到before函数,引入mock.js

before(app, server) {
    // 当使用mock数据的时候打开
    require('./mock.js')(app)
}

⑶ 在项目的根目录下【注意是根目录,不是src目录】,新建一个mock文件夹,然后在mock文件夹下按照接口地址新建一个json文件,把模拟的数据写在json文件里即可,例如:

接口地址为:'/clife-estate-api-web-admin/estate/menuMgr/queryMenuResource.do'
文件目录为:'mock/clife-estate-api-web-admin/estate/menuMgr/queryMenuResource.do.json'
数据内容为:
{
    "data": {
        "record": [],
        "totalRows": 0
    },
    "code": 0
}

⑷ 每次添加mock数据后,重新启动项目, 项目启动默认是走mock数据,如果没有mock数据的就走后台接口

8、配置mobx

见笔者文章《create-react-app中配置less和mobx》
⑴ 在src目录下新建一个store目录,在store目录下按大模块划分文件夹,再按小模块分别新建一个文件用来处理接口

import merchantMng from '@/api/merchantMng'
import {observable, action, computed} from 'mobx'
import {dateFormat} from '@/utils/date'

export default class MerchantMng {
    @observable totalRows = 0
    @observable merchantList = []

    // 商户管理--查询
    @action queryMerchant = async (params) => {
        const data = await merchantMng.queryMerchant(params)
        try {
            this.merchantList = data.data.record
            this.totalRows = data.data.totalRows
        } catch (e) {
            console.log(e)
        }
    }

    @computed get merchantData() {
        try {
            return this.merchantList.map((item, index) => {
                return {
                    ...item,
                    createTime: dateFormat(item.createTime, 'yyyy-MM-dd HH:mm:ss')
                }
            })
        } catch (e) {
            return []
        }
    }

    // 商户管理--新增
    @action addMerchant = async (params) => {
        return await merchantMng.addMerchant(params)
    }
}

新建一个index.js

import MerchantMng from './merchantMng'

class Community {
    constructor() {
        this.MerchantMng = new MerchantMng()
    }
}

export default Community

⑵ 在store目录下新建index.js

import Community from './community'

class RootStore {
    constructor() {
        this.Community = new Community()
    }
}

const rootStore = new RootStore()

export default rootStore

⑶ 把store注入全局

// src/index.jsx文件
import { Provider } from 'mobx-react'
import rootStore from './store'
function render() {
    ReactDOM.render(
        
            
        ,
        document.getElementById('root'))
}
render()

if (module.hot) {
    module.hot.accept(() => {
        render()
    })
}

⑷ 在页面中调用接口

import React, { Component } from 'react'
import { observer, inject } from 'mobx-react'

@inject('Community') // 给组件注入其需要的 store(利用 React context 机制)
@observer // 监听store的变化, 同时更新视图的变化
class MerchantManage extends Component {
    /**
     * 查询商户
     * @param {Number} pageIndex 当前页码
     * @param {Object} carParkMerchant 参数对象
     */
    queryMerchant = (pageIndex = 1, carParkMerchant = {}) => {
        const { MerchantMng } = this.props.Community
        const params = {
            // post和get请求都把参数写在param里
            param: {
                data: {
                    carParkMerchant,
                    pager: {
                        pageRows: 10,
                        pageIndex,
                        paged: true
                    },
                    orderBy: {
                        orderColumn: 't.createTime',
                        orderType: 'desc'
                    }
                }
            }
            // headers: { 'content-type': 'application/json' } 请求头需要传参写在这里
        }
        MerchantMng.queryMerchant(params).then(() => {
            this.setState({
                tbodyData: MerchantMng.merchantData,
                totalRows: MerchantMng.totalRows,
                currentPage: pageIndex
            })
        })
    }
}
9、配置rem

⑴ 在public/index.html添加以下代码


⑵ 在App.scss中设置html字体大小

html {
  font-size: 100px;
}
10、配置px2rem

⑴ 安装

npm install postcss-px2rem-exclude --save

⑵ 在webpack.config.dev.js和webpack.config.prod.js的"getStyleLoaders"方法中添加以下代码

{
  // Options for PostCSS as we reference these options twice
  // Adds vendor prefixing based on your specified browser support in
  // package.json
  loader: require.resolve('postcss-loader'),
  options: {
    // Necessary for external CSS imports to work
    // https://github.com/facebook/create-react-app/issues/2677
    ident: 'postcss',
    plugins: () => [
      require('postcss-flexbugs-fixes'),
      require('postcss-preset-env')({
        autoprefixer: {
          flexbox: 'no-2009',
        },
        stage: 3,
      }),
      // 配置px2rem
      require('postcss-px2rem-exclude')({
        remUnit: 100,
        exclude: /node_modules/i,
      })
    ],
    sourceMap: shouldUseSourceMap,
  },
},
11、引入阿里iconfont

⑴ 在src文件夹下新建一个assets文件夹,再新建一个iconfont文件夹,把阿里图库生成的文件放到文件夹下
⑵ 在App.jsx中引入

import './assets/iconfont/iconfont.css'
12、引入antd,配置按需加载

⑴ 安装

npm install antd --save
npm i babel-plugin-import --save

⑵ 在webpack.config.dev.js和webpack.config.prod.js中找到"oneOf",在"customize"下方的"plugins"中添加以下代码

["import", {
  "libraryName": "antd",
  "libraryDirectory": "es",
  "style": "css"
}]

⑶ 使用组件

import { Layout } from 'antd'
13、去除build生成的.map文件

打开文件webpack.config.prod.js,搜索"shouldUseSourceMap",找到第一个结果,注释掉这一行,另起一行把它的值改为false

// const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
const shouldUseSourceMap = false;
14、打包后首页空白
// package.json中添加
"homepage": "."
15、浏览器es6兼容

⑴ 安装babel-polyfill

npm install --save-dev babel-polyfill

⑵ 在src/index.js引用

import 'babel-polyfill'
16、其他目录结构

⑴ 在src目录下新建一个pages目录,用来存放开发的页面
⑵ 在src目录下新建一个components目录,用来存放封装的组件
⑶ 在src目录下新建一个static目录,用来存放本地媒体资源文件
⑷ 在src目录下新建一个utils目录,用来存放封装的公共方法,项目中常用的公共方法可参考笔者文章《封装项目中常用的工具函数》

你可能感兴趣的:(create-react-app搭建一个完整的项目)