从0到1搭建自己的脚手架react

从0到1搭建自己的脚手架react

1.初始化项目

npm init -y

执行初始化命令之后,会出现package.json文件

2.建立项目目录(基础项目目录)

3.下载依赖

react

npm i react react-dom 

下载babel。babel是javascript编辑器,作用如下:

  1. 负责把ES6、ES7等高版本js编译成低版本js,供浏览器运行。
  2. 负责把react语法(jsx)编译成js。
 npm i @babel/core @babel/cli @babel/preset-env @babel/preset-react --save-dev

集成webpack。webpack是一个现代JavaScript应用程序的静态模块打包器,现代前端应用很多都是用webpack打包。webpack-dev-server用来搭建一个本地服务,可以热加载前端项目

npm i webpack webpack-dev-server webpack-cli --save-dev

webpack集成babel还需要babel-loader,加载html文件还需要插件html-webpack-plugin:

npm i babel-loader html-webpack-plugin --save-dev

4.编辑index.html、App.js、index.js

//index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="root">root</div>
</body>
</html>
//App.js
import React from "react";
class App extends React.PureComponent{
    render(){
        return (
            <div>
                App
            </div>
          );
    }
}

export default App
//index.js
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';

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

5.在根目录下添加.babelrc文件、webpack.config.js文件

6.配置.babelrc、webpack.config.js

//.babelrc
{
    "presets": ["@babel/preset-env","@babel/preset-react"]
}
//webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    //webpack入口文件,webpack从这里开始构建依赖图
    entry:{
        main:'./src/index.js'
    },
    //输出文件 ./dist/bundle.js
    output:{
        path: path.resolve(__dirname,'dist'),
        filename:'bundle.js'
    },
    //webpack只能处理js和json文件,加载别的文件需要loader
    module:{
        rules:[
            {
                test:/.m?js/,
                use:'babel-loader',
                exclude:/node_modules/
            }
        ]
    },
    //webpack加载html文件需要html-webpack-plugin插件处理。
    //启动webpack-dev-server的时候,会把打包好的js文件,css文件,html文件放在内存里
    plugins:[
        new HtmlWebpackPlugin({
            template:'./public/index.html'
        })
    ],
    mode:'development'

}

7.当我们配置好上面的项目了,现在我们就可以运行了

现在我们还得配置一个小细节package,json

{
  "name": "react-app-start",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    //--mode=development为开发环境,速度较快,上线可以配置为生产环境,会压缩,优化代码
    //--watch为监听代码变化,只要代码变化,会重新编译
    //build是生产环境的打包
    "serve": "webpack --mode=development --watch",
    "build": "webpack --mode=production"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "webpack": "^5.74.0"
  },
  "devDependencies": {
    "@babel/cli": "^7.19.3",
    "@babel/core": "^7.20.2",
    "@babel/preset-env": "^7.20.2",
    "@babel/preset-react": "^7.18.6",
    "babel-loader": "^9.1.0",
    "html-webpack-plugin": "^5.5.0",
    "webpack-cli": "^4.10.0"
  }
}

这时候就可以执行命令了

npm run serve

打包执行命令

npm run build

8.如果没有报错的话,你就会看见下面的页面

9.至此webpack简易版配置已经完成。接下来配置热加载功能,下载webpack-dev-server:

npm i webpack-dev-server --save-dev

执行命令:

npm run start

项目在3000端口启动,启动后会自动打开浏览器窗口。热加载配置完成,文件修改保存后浏览器直接展示出来。

到此react项目简化版搭建完成。后续继续集成其他工具库即可。

10.react使用ts

ts对比js最大的特点就是多了类型检查。推荐前端语言使用ts。接下来介绍在webpack中配置ts。

安装typescript、ts-loader。typescript是ts编辑器,把ts代码编译成js,ts-loader是让webpack识别.ts/.tsx文件,调用编译器编译,

npm i typescript ts-loader --save-dev

添加ts配置文件,在根目录下添加tsconfig.json:

//tsconfig.json
{
    "compilerOptions": {
        "target": "es5",
        "lib":["es6","dom"],
        "module": "esnext",
        "moduleResolution": "node",
        "jsx":"react",
        "sourceMap": true,
        "strict": true,
        "importHelpers": true,
        "skipLibCheck": true,
        "allowJs": true,
        "allowSyntheticDefaultImports": true
    }
}

修改webpack配置

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

module.exports = {
    //webpack入口文件,webpack从这里开始构建依赖图
    entry:{
        main:'./src/index.tsx'
    },
    //输出文件 ./dist/bundle.js
    output:{
        path: path.resolve(__dirname,'dist'),
        filename:'bundle.js'
    },
    //webpack只能处理js和json文件,加载别的文件需要loader
    module:{
        rules:[
            {
                test:/.m?js|tsx$/,
                use:'ts-loader',
                exclude:/node_modules/
            }
        ]
    },
    //增加扩展选项,让webpack可以识别.ts/tsx文件
    resolve:{
        extensions:['.ts','.tsx','.js']
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./public/index.html'
        })
    ],
    mode:'development'

}

目前可能会报错

根据提示,我们缺一些依赖

npm i --save-dev @types/react
npm i --save-dev @types/react-dom

这个时候我们还会遇到一个问题

那么这个问题的原因是缺null类型检测

其他人回答说应该添加null检查,但Typescript也有一个非null断言,当您通过添加!运算符添加到语句末尾:

这个时候我们react使用ts的问题就解决了

启动项目,运行成功,ts集成成功了

11.react集成路由

安装路由库

npm install react-router-dom@6

创建项目目录

编辑About.tsx、Home.tsx、index.tsx、App.tsx

//About.tsx
import React from "react";
import { Link } from "react-router-dom";

class About extends React.PureComponent{
    render(){
        return (
            <div>
                this is about<br/>
                <Link to={'/home'}>to home</Link>
            </div>
        )
    }
}

export default About;
//Home.tsx
import React from "react";
import { Link } from "react-router-dom";

class Home extends React.PureComponent{
    render(){
        return (
            <div>
                this is home<br/>
                <Link to={'/about'}>to about</Link>
            </div>
        )
    }
}

export default Home;
//App.tsx
import React from "react";
import { Routes,Route } from "react-router-dom";
import About from "./compents/About";
import Home from "./compents/Home";

class App extends React.PureComponent{
    render(){
        return (
            <div>
                <Routes>
                    <Route path="/" element={<Home />}></Route>
                    <Route path="/home" element={<Home />}></Route>
                    <Route path="/about" element={<About />}></Route>
                </Routes>
            </div>
          );
    }
}

export default App
//index.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
import { BrowserRouter } from 'react-router-dom';

const root = createRoot(document.getElementById('root')!)
root.render(
    <BrowserRouter>
        <App />
    </BrowserRouter>
)

react路由搭建成功

12.react使用redux

对于大型项目来说,数据管理工具也是必不可少的。我们简单介绍redux、react-redux的使用。这里使用的是@reduxjs/toolkit库,相比redux库使用方法有很大区别,想用redux库的请自行查看redux文档。

下载依赖

npm i @reduxjs/toolkit react-redux

创建项目目录

编辑store.ts、countSlice.ts、counter.tsx、index.tsx、App.tsx

//store.ts
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from './countSlice';

export default configureStore({
    reducer:{
        counter:counterReducer
    }
})
//countSlice.ts
import { createSlice } from "@reduxjs/toolkit";

export const counterSlice = createSlice({
    name:'counter',
    initialState:{
        value:0
    },
    reducers:{
        increment:(state) => {
            state.value += 1
        },
        decrement:(state) =>{
            state.value -= 1
        },
        incrementByAmount:(state,action) => {
            state.value += action.payload
        }
    }
})

export const { increment,decrement,incrementByAmount } = counterSlice.actions
export default counterSlice.reducer
//index.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
import store  from './store/store';
import { Provider } from 'react-redux';

const root = createRoot(document.getElementById('root')!)
root.render(
    <BrowserRouter>
    <Provider store={store}>
        <App />
    </Provider>  
    </BrowserRouter>
)
//counter.tsx
import React from "react";
import { useSelector,useDispatch } from "react-redux";
import { decrement,increment } from "../store/countSlice";

function Counter(){
    const count = useSelector((state:any) => state.counter.value)
    const dispatch = useDispatch()
    
    return (
        <div>
            <div>
                <button 
                aria-label="Increment value"
                onClick={() => dispatch(increment())}
                >
                    increment
                </button>
                <span>{count}</span>
                <button
                aria-label="Decrement value"
                onClick={() => dispatch(decrement())}
                >
                    Decrement
                </button>
            </div>
        </div>
    )
}

export default Counter;
//App.tsx
import React from "react";
import { Routes,Route } from "react-router-dom";
import About from "./compents/About";
import Home from "./compents/Home";
import Counter from "./compents/Counter";

class App extends React.PureComponent{
    render(){
        return (
            <div>
                <Routes>
                    <Route path="/" element={<Home />}></Route>
                    <Route path="/home" element={<Home />}></Route>
                    <Route path="/about" element={<About />}></Route>
                    <Route path="/counter" element={<Counter />}></Route>
                </Routes>
            </div>
          );
    }
}

export default App

当我执行命令进入counter组件点击功能按钮就发现redux使用成功了

npm run start

13.集成UI库

这里使用的是antd第三方库

安装ui库

npm i antd

使用antd还需要引用其样式文件,因此还需要下载css-loader、style-loader。

npm i style-loader css-loader -D

修改webpack配置

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

module.exports = {
    //webpack入口文件,webpack从这里开始构建依赖图
    entry:{
        main:'./src/index.tsx'
    },
    //输出文件 ./dist/bundle.js
    output:{
        path: path.resolve(__dirname,'dist'),
        filename:'bundle.js'
    },
    //webpack只能处理js和json文件,加载别的文件需要loader
    module:{
        rules:[
            {
                test:/.j|tsx$/,
                use:'ts-loader',
                exclude:/node_modules/
            },
            {
                test:/.css$/,
                use:['style-loader','css-loader']
            }
        ]
    },
    //增加扩展选项,让webpack可以识别.ts/tsx文件
    resolve:{
        extensions:['.ts','.tsx','.js']
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./public/index.html'
        })
    ],
    mode:'development'
}

使用antd的话直接引入使用就可以了

//Home.tsx
import React from "react";
import { Link } from "react-router-dom";
import { Button } from "antd";

class Home extends React.PureComponent{
    render(){
        return (
            <div>
                this is home<br/>
                <Link to={'/about'}>
                    <Button type={'primary'}>to about</Button>
                </Link>
                <Link to={'/counter'}>
                    <Button type={'primary'}>to counter</Button> 
                </Link>
            </div>
        )
    }
}

export default Home;

14.跨域问题

修改webpack.config.js使用proxy

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

module.exports = {
    //webpack入口文件,webpack从这里开始构建依赖图
    entry:{
        main:'./src/index.tsx'
    },
    //输出文件 ./dist/bundle.js
    output:{
        path: path.resolve(__dirname,'dist'),
        filename:'bundle.js'
    },
    //webpack只能处理js和json文件,加载别的文件需要loader
    module:{
        rules:[
            {
                test:/.j|tsx$/,
                use:'ts-loader',
                exclude:/node_modules/
            },
            {
                test:/.css$/,
                use:['style-loader','css-loader']
            }
        ]
    },
    //增加扩展选项,让webpack可以识别.ts/tsx文件
    resolve:{
        extensions:['.ts','.tsx','.js']
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./public/index.html'
        })
    ],
    mode:'development',
    devServer:{
        proxy:{
            '/api':'http://localhost:8080',
        },
        client:{
            progress:true
        }
    }

}

配置后,前端请求就会被代理到8080端口,解决跨域问题

15.集成ESLint和prettier

安装ESLint

//本地安装
npm install eslint --save-dev
//全局安装
npm install -g eslint

运行eslint –init,选择工程使用了react,自动生成.eslintrc.js文件

eslint --init

安装prettier

//本地
npm i -D --save-exact prettier
//全局
npm i --global prettier

安装eslint-config-prettier插件(禁用 eslint 风格校验)

npm i -D eslint-config-prettier

安装eslint-plugin-prettier插件(使eslint采用prettier的风格校验)

npm i -D eslint-plugin-prettier

配置eslintrc.js文件

// eslint-disable-next-line no-undef
module.exports = {
    "env": {
        "browser": true,
        "es2021": true,
        "jest":true
    },
    "extends": [
        "eslint:recommended",
        "plugin:react/recommended",
        "plugin:@typescript-eslint/recommended"
    ],
    "overrides": [
    ],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "ecmaVersion": "latest"
    },
    "plugins": [
        "react",
        "@typescript-eslint"
    ],
    "rules": {
    "no-cond-assign": 2,
    "no-console": [
      "error", {
        "allow": ["log", "warn", "error", "info"]
      }
    ],
    // 禁止 function 定义中出现重名参数
    "no-dupe-args": 2,
    // 禁止对象字面量中出现重复的 key
    "no-dupe-keys": 2,
    // 禁止重复的 case 标签
    "no-duplicate-case": 2,
    // 禁止对 catch 子句的参数重新赋值
    "no-ex-assign": 2,
    // 禁止不必要的布尔转换
    "no-extra-boolean-cast": 2,
    // 禁止不必要的括号 //(a * b) + c;//报错
    "no-extra-parens": 0,
    // 禁止 catch 子句的参数与外层作用域中的变量同名
    "no-catch-shadow": 0,
    // 不允许标签与变量同名
    "no-label-var": 2,
    // 禁用特定的全局变量
    "no-restricted-globals": 2,
    // 禁止覆盖受限制的标识符
    "no-shadow-restricted-names": 2,
    // 禁止将变量初始化为 undefined
    
    // 强制使用一致的换行风格
    "linebreak-style": [2, "unix"],
    //在JSX中强制布尔属性符号
    "react/jsx-boolean-value": 2,
    //在JSX中验证右括号位置
    // "react/jsx-closing-bracket-location": 1,
    //在JSX属性和表达式中加强或禁止大括号内的空格。
    "react/jsx-curly-spacing": [2, {
      "when": "never",
      "children": true
    }],
    //在数组或迭代器中验证JSX具有key属性
    "react/jsx-key": 2,
    // 限制JSX中单行上的props的最大数量
    "react/jsx-max-props-per-line": [1, {
      "maximum": 5
    }],
    //防止在JSX中重复的props
    "react/jsx-no-duplicate-props": 2,
    //  //防止使用未包装的JSX字符串
    // "react/jsx-no-literals": 0,
    //在JSX中禁止未声明的变量
    "react/jsx-no-undef": 2,
    //为用户定义的JSX组件强制使用PascalCase
    "react/jsx-pascal-case": 0,
    //防止反应被错误地标记为未使用
    "react/jsx-uses-react": 2,
    //防止在JSX中使用的变量被错误地标记为未使用
    "react/jsx-uses-vars": 2,
    //防止在componentDidMount中使用setState
    "react/no-did-mount-set-state": 2,
    //防止在componentDidUpdate中使用setState
    "react/no-did-update-set-state": 2,
    //防止使用未知的DOM属性
    "react/no-unknown-property": 2,
    //为React组件强制执行ES5或ES6类
    "react/prefer-es6-class": 2,
    //防止在React组件定义中丢失props验证
    // "react/prop-types": 1,
    //使用JSX时防止丢失React
    "react/react-in-jsx-scope": 2,
    //防止没有children的组件的额外结束标签
    "react/self-closing-comp": 0,
    //禁止不必要的bool转换
    // "no-extra-boolean-cast": 0,
    //防止在数组中遍历中使用数组key做索引
    // "react/no-array-index-key": 0,
    //不使用弃用的方法
    "react/no-deprecated": 2,
    //在JSX属性中强制或禁止等号周围的空格
    "react/jsx-equals-spacing": 2,
    "react/jsx-filename-extension": [2, {
      "extensions": [".js", ".jsx"]
    }],
    // 禁止未使用的变量
    "no-unused-vars": 0,
    }
}

当我们代码被eslint检测到不符合规则的代码就会提示,根据eslint指示修改就可以

在根目录下创建.prettierrc 或 prettier.config.js文件

module.exports = {
    endOfLine: 'auto', // 不检测检测文件每行结束的格式
    semi: true, // 使用分号, 默认true
    singleQuote: true // 使用单引号, 默认false(在jsx中配置无效, 默认都是双引号)
 }

安装vscode插件:Prettier ESLint

该插件会根据工程根目录下的eslintrc.js和prettier.config.js文件格式化代码。可以进一步设置为vscode默认formater和自动格式化。

Prettier配置常用的参数可以根据团队需求制定

该文章只是配置简单的react脚手架,核心流程和方法是如此,其他具体需求可以根据团队客制化定制

参考链接:

[antd官网]: “https://ant.design/docs/react/introduce-cn
[ESLint中文文档]: “https://eslint.bootcss.com
[Prettier中文网]: “https://www.prettier.cn

源码仓库地址:

https://github.com/mengfeng/react-app-start.git

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2022-2023 alan_mf
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信