都 2022 年了,手动搭建 React 开发环境很难吗?

应用开发2025-11-05 09:42:4134

工厂流水线生产的都年搭建东西用久了,总想着自己手工是手动否也能做出来,就如同工艺品和艺术品一般,发环虽然效果相似,境难但艺术品往往比工艺品更有韵味。都年搭建

作为一名前端工程师,手动总是发环用一些脚手架来快速搭建新项目的基本结构,因此今天尝试着一步步搭建一个 React 的境难项目环境,看看需要处理哪些问题,都年搭建查漏补缺!

一、手动需求分析 

首先分析我们的发环诉求:

应用级别的项目,是境难需要支持打包构建。需要考虑兼容性,都年搭建支持代码 pollyfill。手动支持 React 框架下的发环开发环境。支持代码类型提示。支持前端路由。支持前端状态管理。代码规范、自动格式化、Git 提交规范。基础的 UI 组件库。

针对上面的诉求,云服务器其实也是绝大部分项目都会需要,因此也有了常见的解决方案:

Webpack 5。Babel。React 17、React-dom。TypeScript。React-router-dom v6。Redux、React-redux。ESlint、Prettier、Lint-staged、Husky、@commitlint。Arco Design。

二、项目打包构建

因为是 2022 年了,所以我们的项目所有依赖项全部用最新的工具库版本,搞起来!

首先是把项目的基本构建能力搭建好,让项目先跑起来!

1、 初始化 package.json

mkdir webpack-react

cd webpack-react

npm init --y

git init

然后稍微改改 package.json 文件如下:

{

"name": "webpack-react",

"private": true,

"version": "0.1.0",

"description": "一个基于 Webpack 构建的 React开发环境",

"main": "index.js",

"scripts": {

"dev": "",

"build": "",

"preinstall": "npx only-allow yarn"

},

"keywords": [],

"author": "DYBOY",

"license": "ISC"

}

由于没有安装一些三方库,所以该文件还比较“简陋”,所以接下来逐个安装模块,配置环境!

2、安装配置 React 和 Typescript

根据需求,免费信息发布网我们先安装一些必要的模块。

首先是 React 的基本模块。

yarn add react react-dom

yarn add @types/react @types/react-dom

然后是 TypeScript 类型模块。

yarn add typescript -D

有了 TypeScript,就可以直接通过 TS 生成一个 tsconfig.json 的配置文件

yarn tsc --init

根据需要,稍微改改后如下:

// tsconfig.json

{

"compilerOptions": {

"target": "ES2015",

"lib": ["DOM", "ES2015"],

"jsx": "react-jsx",

"experimentalDecorators": true,

"emitDecoratorMetadata": true,

"module": "ESNext",

"rootDir": "./src",

"moduleResolution": "node",

"baseUrl": ".",

"paths": {

"@/*": ["src/*"]

},

"resolveJsonModule": true,

"allowJs": true,

"outDir": "./dist",

"removeComments": true,

"isolatedModules": true,

"allowSyntheticDefaultImports": true,

"esModuleInterop": true,

"forceConsistentCasingInFileNames": true,

"strict": true,

"skipLibCheck": true

},

"include": ["src/"]

}

*关于 tsconfig.json 文件的配置解析可以参阅:《会写 TypeScript 但你真的会 TS 编译配置吗?[1]》。

此时可以创建文件和文件夹,有一个初步的项目结构。

项目结构

其中:

dist/:是用于存储打包的文件。public/: 是用于存放打包的模板入口 HTML 文件。src/:是用于开发人员主要编码的文件夹。.gitignore:用于配置 Git 忽略哪些文件或文件夹。tsconfig.json: TypeScript 的项目配置文件。yarn.lock:依赖模块的版本信息,用于保证开发环境一致性。

此时就可以简单的写支持 TS 和 React 的IT技术网应用了。

3、 Webpack 相关

因为是一个项目,我们需要通过构建工具,帮助我们快速的实现打包,以及开发环境下的预览,因此第二步就是安装和配置 Webpack。

yarn add webpack webpack-cli webpack-dev-server webpack-merge -D

后两个模块分别是用于开启开发时的本地 HTTP 服务,和用于 Merge webpack 配置的工具函数。

(1) Webpack 配置文件结构

首先,先完善 package.json 中的 scripts(开发指令和构建指令):

+ "dev": "cross-env NODE_ENV=development webpack serve -c scripts/webpack.dev.js",

+ "build": "yarn ts:checker && cross-env NODE_ENV=production webpack -c scripts/webpack.prod.js",

+ "ts:checker": "tsc --noEmit",

同时安装一下 cross-env,该模块主要是用于支持在不同的操作系统下保证环境变量正确。

yarn add cross-env -D

通过指令,我们需要三个 Webpack 的配置文件:

(2) webpack.common.js 通用配置

这是公共的 Webpack 配置,主要配置了如下几个地方。

const path = require("path");

const chalk = require("chalk");

const webpack = require("webpack");

const HtmlWebpackPlugin = require("html-webpack-plugin");

const ProgressBarPlugin = require("progress-bar-webpack-plugin");

const pkgJSON = require("../package.json");

console.log("process.env.NODE_ENV: ", process.env.NODE_ENV);

module.exports = {

entry: path.resolve(__dirname, "../src/index.tsx",

output: {

filename: "[name].[hash:8].js",

path: path.resolve(__dirname, "../dist"),

publicPath: "/",

clean: true,

},

resolve: {

extensions: [".ts", ".tsx", ".js"],

alias: {

"@": path.resolve(__dirname, "../src"),

},

},

module: {

rules: [

{

test: /.tsx?$/,

use: ["ts-loader"],

exclude: /node_modules/,

},

{

test: /\.(jpe?g|png|svg|gif)$/i,

type: "asset",

parser: {

dataUrlCondition: {

maxSize: 25 * 1024, // 25kb

},

},

generator: {

filename: "assets/imgs/[name].[hash:8][ext]",

},

},

],

},

plugins: [

new webpack.DefinePlugin({

// 定义在代码中可以替换的一些常量

__DEV__: process.env.NODE_ENV === "development",

}),

new HtmlWebpackPlugin({

template: path.resolve(__dirname, "../public/index.html"),

title: pkgJSON.name,

meta: {

description: {

type: "description",

content: pkgJSON.description,

},

},

minify: "auto",

}),

new ProgressBarPlugin({

format: ` :msg [:bar] ${chalk.green.bold(":percent")} (:elapsed s)`,

}),

],

};

个人有一个观点,开发环境和构建环境应该在配置上相似性需要寻找平衡,开发环境寻求的是热更新快,构建环境寻求的是兼容性好,且尽可能和开发环境看到效果相同!

针对缺失的模块还需要安装到开发依赖中:

# 支持 ts 和 tsx 文件的处理

yarn add ts-loader -D

# 美化终端输出,安装特定版本是为了处理模块化包的问题

yarn add chalk@4.1.2 -D

# 将 /public/index.html 作为模板入口文件打包

yarn add html-webpack-plugin -D

# 美化 webpack 编译时候的进度条

yarn add progress-bar-webpack-plugin -D(3) webpack.dev.js 开发配置

然后再配置下开发环境下的 Webpack 配置,主要是支持热更新、本地预览功能,以及一些和生产环境差异的配置。

const { merge } = require("webpack-merge");

const common = require("./webpack.common.js");

module.exports = merge(common, {

mode: "development", // 开发模式

devServer: {

hot: true, // 热更新

open: true, // 编译完自动打开浏览器

compress: false, // 关闭gzip压缩

port: 7878, // 开启端口号

historyApiFallback: true, // 支持 history 路由重定向到 index.html 文件

},

module: {

// 插件的执行顺序从右到左

rules: [

{

test: /\.(css|scss|sass)$/,

use: [

"style-loader",

"css-loader",

{

loader: "postcss-loader",

options: {

postcssOptions: {

plugins: [["autoprefixer"]],

},

},

},

"sass-loader",

],

// 排除 node_modules 目录

exclude: /node_modules/,

},

],

},

stats: "errors-only", // Webpack 在编译的时候只输出错误日志,终端更清爽

});

这里增加了对 scss/css 文件的处理,因此还需要安装相关的模块:

# style-loader 将 css 注入到 HTML 的内联样式

# css-loader 用于加载 CSS 文件,转化 CSS 为 CommonJS

yarn add style-loader css-loader -D

# postcss 用于处理 CSS 兼容性

# autoprefixer 用于自动根据兼容需求增加 CSS 属性的前缀

yarn add postcss postcss-loader autoprefixer -D

# sass 主要是用于支持 “CSS 编程”

# sass-loader 会将 .scss 后缀文件编译成 CSS

yarn add sass sass-loader -D

讲到了 CSS 自动前缀处理兼容性,因此可以将需要兼容浏览器版本的配置放到 package.json -> browserslist 属性下:

{

...

"browserslist": {

"production": [

">0.2%",

"not dead",

"not op_mini all"

],

"development": [

"defaults",

"not ie < 11",

"last 2 versions",

"> 1%",

"iOS 9",

"last 3 iOS versions"

]

}

...

}(4) webpack.prod.js 生产配置

针对 Webpack 的构建环境下(mode: "production")的配置,实际上在 Webpack 5 版本中默认就集成了很多优化,更多自定义诉求可以参考:Webpack Optimization[2] 配置。

const { merge } = require("webpack-merge");

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

const common = require("./webpack.common.js");

module.exports = merge(common, {

mode: "production",

optimization: {

minimize: true,

minimizer: [

"...",

new TerserPlugin({

terserOptions: {

format: {

comments: false,

},

},

extractComments: false,

}),

],

},

module: {

rules: [

{

test: /\.(css|scss|sass)$/,

use: [

MiniCssExtractPlugin.loader,

"css-loader",

{

loader: "postcss-loader",

options: {

postcssOptions: {

plugins: [["autoprefixer"]],

},

},

},

"sass-loader",

],

exclude: /node_modules/,

},

],

},

plugins: [

new MiniCssExtractPlugin({

filename: "assets/css/[hash:8].css",

}),

],

});

需要安装依赖:

# 用于将 CSS 导出到单独文件

yarn add mini-css-extract-plugin -D

# 用于做源代码压缩

yarn add terser-webpack-plugin -D

(5) 开发&构建

弄好了上面的 Webpack 配置,就可以实际的开发了。

/src/index.tsx 文件如下:

执行:yarn dev,会自动打开浏览器页面:http://localhost:7878/。

执行:yarn build,会将项目编译打包输出到 ./dist/ 文件夹下。

4、 Bable 处理兼容性

我们的项目可能会在各种浏览器中运行,为了尽可能兼容大多数用户的设备,因此引入 Babel 来统一处理兼容性。

在 webpack.common.js 配置文件中增加:

...

rules: [

{

test: /\.tsx?$/,

use: [

+ {

+ loader: "babel-loader",

+ options: {

+ presets: [

+ [

+ "@babel/preset-env", // 预制配置

+ {

+ corejs: {

+ version: 3,

+},

+ useBuiltIns: "usage", // 按需引入 pollyfill

+ },

+ ],

+ "@babel/preset-react", // React 环境

+ ],

+ plugins: ["@babel/plugin-transform-runtime"],

+ },

+ },

"ts-loader",

],

exclude: /node_modules/,

},

...

],

...

放到 webpack.common.js 文件下也是为了考虑在开发环境下验证引入 pollyfill 的正确性。

同时还需要安装如下依赖:

# 安装 babel 核心和加载器

yarn add @babel/core babel-loader -D

# core-js 中有各种各样的 pollyfill,用于提升兼容性

# https://github.com/zloirock/core-js

yarn add core-js -D

# 预制环境

yarn add @babel/preset-env @babel/preset-react -D

# 统一的 pollyfill,打包时候加载到代码中,减少冗余代码

yarn add @babel/plugin-transform-runtime -D

三、路由 React-router-dom

前端的页面一般是多页面的,因此我们需要一个统一的路由来方便管理,这里用到了 react-router-dom v6[3] 版本。

多路由的使用方式基本相似,因此官方提炼出了 useRoutes 的 Hooks,用于便捷生成路由,相较于 V5 版本,确实方便太多了。

安装作为应用依赖:

yarn add react-router-dom

1、 统一管理的路由配置首先是配置

路由 /src/config/router.tsx 文件:

import { RouteObject } from "react-router-dom";

import HomePage from "@/pages/home";

const ROUTER_CONFIG: RouteObject[] = [

{

path: "/",

element: ,

},

{

path: "*",

element: <>404 Not Found!,

},

];

export { ROUTER_CONFIG };

之后如果新增任意页面,都可以在 /src/pages/ 文件夹下新增任,并且都可以放到 /src/config/router.tsx 文件来统一管理,嵌套路由同样适用,只需要根据 RouteObject 类型声明规范即可:

/

**

* A route object represents a logical route, with (optionally) its child

* routes organized in a tree-like structure.

*/

export interface RouteObject {

caseSensitive?: boolean; // 大小写敏感

children?: RouteObject[]; // 子路由

element?: React.ReactNode; // 组件

index?: boolean; // 在子路由中,默认为父级路由的首页

path?: string; // URL 路径

}

2、 项目中引入

然后在 /src/app.tsx 文件中使用 useRoutes() 并嵌入到应用中:

import { useRoutes } from "react-router-dom";

import { ROUTER_CONFIG } from "./config/router";

const App = () => {

const appRoutesElement = useRoutes(ROUTER_CONFIG);

return appRoutesElement;

};

export default App;

最后在 /src/inde.tsx 使用 BrowserRouter 包裹 组件。

import { render } from "react-dom";

import { BrowserRouter } from "react-router-dom";

import App from "./app";

render(

,

document.getElementById("root")

);

此时的项目目录结构如下:

目录结构

如此就可以愉快的编写任意页面啦!

3、 [优化]延迟按需加载页面

虽然路由集中管理了,但是首屏加载的 js 文件太大,会使得白屏时间较长,增加了用户等待时间。

因此考虑延迟按需加载页面方式,使用 import() 和 React.lazy() 来主动优化。

新建一个通用组件 LazyWrapper 在 /src/components/lazy-wrapper/index.tsx 文件。

import { FC, lazy, Suspense } from "react";

interface LazyWrapperProps {

/** 组件路径: 在 src/pages 目录下的页面路径,eg: /home => src/pages/home/index.tsx */

path: string;

}

/

**

* 懒加载组件包装器

*/

const LazyWrapper: FC= ({ path }) => {

const LazyComponent = lazy(() => import(`/src/pages${path}`));

return (

);

};

export default LazyWrapper;

此时修改 /config/router.tsx 路由配置文件:

效果如下: 当加载 Home 页面时,按需加载对应的组件。

另外由于拆包之后可能组件容易因网络抖动原因加载失败,所以还需要做自动重试拉取组件的方案,这里也不赘述了,参考之前写的文章:《性能优化竟白屏,难道真是我的锅?》

通过二次封装 Errorboundary 组件,实现组件加载失败自动重试,并针对错误上报日志,便于后期针对性优化。

四、状态管理 Redux

在一个应用中,自然是少不了全局状态管理,一般情况下如果状态比较简单,可以直接使用 React 的 useContext 和 useReducer Hooks 组合实现简单的全局状态管理。

但通常我们的项目应该是比较庞大复杂,为了提升后期可维护性,因此使用了 Redux 作为全局状态管理。

Redux 的另一大优势则是提供了 @reduxjs/toolkit[4] 辅助工具,使得状态管理更加简单。

安装:

# react-redux 是 redux 的 UI 桥接层

yarn add redux react-redux

yarn add @reduxjs/toolkit

这里就不在赘述了,对于 Redux 的状态管理方案,可以参考之前写的文章:《用 Redux 做状态管理,真的很简单

本文地址:http://www.bzve.cn/news/377d62498998.html
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

全站热门

如何使用Cardreader读卡器(掌握Cardreader读卡器的基本操作及技巧)

同样是高并发,QQ/微博/12306的架构难度一样吗?

Java那么多锁,能锁住灭霸吗?

揭开JavaScript引擎的面纱

磁盘扫描程序(使用磁盘扫描程序对C盘进行扫描修复的方法与技巧)

作为初创公司的第一位数据工程师,我学到了什么

如何保证前端项目代码质量

架构师分析 架构的重要性

友情链接

滇ICP备2023006006号-39