从零到一搭建简单的纯前端项目并部署(基于React18)

327 阅读5分钟

本框架基于node.js, react18,antd,react-router,redux,axios,http-proxy-middleware,webpack,nginx等内容实现

一、环境搭建

1、安装node.js

官网地址:Node.js--推荐版本^18.17.0 || >=20.5.0

2、安装webpack

npm install -g webpack

3、安装create-react-app

npm install -g create-react-app

4、创建项目

create-react-app create-react-app // 创建名为create-react-app的项目,后面的create-react-app为项目名称,可自行调整
cd create-react-app // 进入项目文件夹

5、工程启动

npm run start // 启动本地server用于开发

二、框架结构

|- node_modules // 项目依赖包
|- public // 一般用于存放静态文件,打包时会被直接复制到输出目录(./buidle)
|- src // 项目源代码
  |  |- containers // 页面视图文件夹
          |  |- Test
                  |  |- test.js
                  |  |- TestComponent.jsx
                  |  |- TestPage.jsx
  |  |- redux // redux文件夹
          |  |- store.js
  |  |- router // 路由配置文件夹
          |  |- router.js // 路由文件配置
  |  |- setupProxy.js // 代理请求配置文件
  |  |- App.js // 入口文件
  |  |- App.css
  |  |- index.js //注册路由与服务
  |  |- index.css
|- package.json // 包管理代码
|- package-lock.json// 包版本锁定代码
|- webpack.config.js// webpack打包
|- .gitignore // Git忽略文件

三、集成和配置

1、React Router(路由配置管理)

React Router 是一个基于 React 之上的强大路由库,它可以让你向应用中快速地添加视图和数据流,同时保持页面与 URL 间的同步。 React Router 是一个基于 React 之上的强大路由库,它可以让你向应用中快速地添加视图和数据流,同时保持页面与 URL 间的同步。

1.1、安装react-router

npm install react-router@4.3.1 --save

1.2、安装moment和antd(配置全局语言,使用antd UI库)

npm install moment@2.29.4 --save
npm install antd@5.8.4 --save

1.3、在containers文件夹下创建一个测试界面Test.jsx

import React, {Component} from "react";

class Test extends Component {
    render() {
        return <div>test界面</div>;
    }
}

export default Test

1.4、创建路由router.js(文件位置参照框架结构)

import React from "react";

const Test = React.lazy(() => import( "../containers/Test.jsx"));

let routes = [
    {
        path: "/test",
        element: <Test/>,
    }
];

export default routes;

1.5、修改APP.js文件

import './App.css';
import React from 'react';

import { BrowserRouter, Route, Routes} from "react-router-dom"
import routes from "./router/router.js";

// 默认语言为 en-US,如果需要设置其他语言,需要在入口文件全局设置 locale
import moment from 'moment';
import 'moment/locale/zh-cn';
import locale from 'antd/lib/locale/zh_CN';
import { ConfigProvider } from 'antd';

function App() {
    return (
        <ConfigProvider locale={locale}>
            <React.Suspense className="App">
                <BrowserRouter>
                    <Routes>
                        {
                            routes.map((route, key) => {
                                return <Route key={key} exact path={route.path} element={route.element}/>
                            })
                        }
                    </Routes>
                </BrowserRouter>
            </React.Suspense>
        </ConfigProvider>
    );
}

export default App;

1.6、访问 http://localhost:3000/test 即可展示测试界面

image.png

2、redux(数据管理)

2.1、安装Redux相关依赖

npm install react-redux@8.0.2 --save
npm install reduxjs/toolkit@1.9.5 --save
npm install redux-observable@2.0.0 --save

2.2、完善测试界面结构

image.png

TestPage.jsx为先前的Test.jsx(*因为结构变化,不要忘记修改一下路由中的界面地址

-test.js               //变量,方法,函数等
-TestComponent.jsx     //界面组件内容
-TestPage.jsx          //主界面,结合redux完成数据通信

test.js

import React from "react";

const UPDATE_DATA = "test/UPDATE_DATA";//更新状态
const TOGGLE_LOADING = "test/TOGGLE_LOADING";//加载标志

// reducer
export const testData = (state = {
    userId: "111", //用户id
    userName: "222", //用户name

}, action) => {
    switch (action.type) {
        case UPDATE_DATA:
            return {
                ...state,
                [action.data.name]: action.data.value
            };
        case TOGGLE_LOADING:
            return {
                ...state,
                loading: action.data
            };
        default:
            return state;
    }
};

/**
 * 加载标志变更
 */
export const toggleLoading = (show) => {
    return {
        type: TOGGLE_LOADING,
        data: show
    }
};

/**
 * 赋值变更
 */
export const updateData = (data) => {
    return {
        type: UPDATE_DATA,
        data: data
    }
};

TestComponent.jsx

import React from "react";

class TestComponent extends React.Component {

    render() {
        return (
            <div>测试界面
                <div>变量1:{this.props.userId}</div>
                <div>变量2:{this.props.userName}</div>
            </div>
        );
    }
}

export default TestComponent;

TestPage.jsx

import React, {Component} from "react";
import {connect} from "react-redux";
import TestComponent from "./TestComponent";
import {updateData} from "./test";

class TestPage extends Component {

    render() {
        return <TestComponent {...this.props} />;
    }
}

const mapStateToProps = (state) => {
    return {
        ...state.testData,
    }
};

//调用js中的方法
const mapDispatchToProps = (dispatch) => {
    return {
        dispatch,
        update(data) {
            dispatch(updateData(data))
        },
    }
};

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(TestPage)

2.3、创建通信store.js(文件位置参照框架结构)

import {configureStore} from '@reduxjs/toolkit';
import {createEpicMiddleware} from 'redux-observable';

import {testData} from "../containers/Test/test";

const epicMiddleware = createEpicMiddleware();

export const store = configureStore({
    reducer: {
        testData,
    },
    middleware: (getDefaultMiddleware) => {
        return getDefaultMiddleware().concat(epicMiddleware)
    }
});

2.4、修改index.js文件

import React from 'react';
import ReactDOM from 'react-dom/client';
import {store} from './redux/store';
import {Provider} from 'react-redux';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <React.StrictMode>
        <Provider store={store}>
            <App/>
        </Provider>
    </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

3、axios

添加接口请求库

3.1、安装依赖

npm install axios

3.2、代理

npm install http-proxy-middleware

创建代理setupProxy.js(文件位置参照框架结构)

const {createProxyMiddleware} = require('http-proxy-middleware')

module.exports = function (app) {
    app.use(
        createProxyMiddleware('/app',
        {
            target: 'http://127.0.0.1:8221/', //请求转发给谁(能返回数据的服务器地址)
            changeOrigin: true,  //控制服务器收到的响应头中Host字段的值
            pathRewrite: {'^/app': ''} //重写请求路径,保证交给后台服务器是正常地请求地址(必须配置)
        }),
    )
};

3.3、请求

axios({
    method: "POST",
    url: `/app/processTaskRecord/planListMain`,
    tentType: "application/json",
    withCredentials: true,
    data: data,
}).then(
    response => {
        if (response.status === 200) {
            if (response.data && !!response.data.totalElements) {
                message.success({content: "查询成功", key: "query", duration: 1});
                dispatch(updateData({name: "list", value: response.data.content}));
            } else {
                message.warning({content: "未查询到数据", key: "query", duration: 3});
                dispatch(updateData({name: "list", value: []}));
            }
        }
    }
).catch(err => {
    message.error({content: "查询数据失败", key: "query", duration: 3});
});

四、打包

1、webpack

1.1、引入打包命令的协议

npm install webpack -D
npm install webpack-cli -D
npm install html-webpack-plugin

1.2、配置babel和加载器

npm i babel-loader @babel/core @babel/preset-react -D
// 配置加载器
npm install style-loader css-loader file-loader

1.3、创建webpack.config.js文件(文件位置参照框架结构)

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
    mode: "development",
    //入口
    entry: {
        main: "./src/index.js",
    },
    //出口
    output: {
        path: path.resolve(__dirname, "dist"),
        //js的文件名称
        filename: 'main.js',
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, "public/index.html"),
            //文件名称
            filename: 'index.html',
        }),
    ],
    module: {
        rules: [
            {
                test: /.(js|jsx)$/,
                exclude: /node_modules/,
                loader: "babel-loader",
                //预设执行处理
                options: {
                    presets: ["@babel/preset-react"],
                },
            },
            {
                test: /.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /.(gif|png|svg|jpeg)$/,
                use: ["file-loader"]
            }
        ],
    },
    resolve: {
        extensions: [".js", ".css", ".jsx"]//导入文件时可以省略文件后缀名
    }
};

1.4、运行打包命令

webpack

会在根节点下生成一个文件夹dist,包含一个index.html和main.js文件(也会包含其他资源文件),这样说明初步就配置成功。

五、项目部署

1、Nginx

1.1、下载Nginx,使用Nginx进行项目部署

image.png

我下载的是windows稳定版的,可自行选择想用的版本

1.2、修改Nginx配置

找到conf文件夹下的nginx.conf配置文件,修改server部分配置

  • listen为端口号,默认为80端口;
  • root后文件夹修改为dist,默认为 html;
server {
        #listen       80;
        listen       8099;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root    dist;
            index  index.html index.htm;
        }
    }

因为开发程序时,是运行在node环境中,此时使用的是http-proxy-middleware进行代理请求,但是打包部署后并非运行在node环境中,此时需要在Nginx上配置代理,此时是Nginx服务代理请求,需在server中添加代理。

 location /app/ {
   proxy_pass  http://127.0.0.1:8221/;
 }

1.3、将之前打包好的dist文件夹整体复制到Nginx根目录下,启动Nginx服务 访问http://localhost:8099/ 即可