【React进阶-1】从0搭建一个完整的React项目(入门篇)

article/2025/11/7 19:13:54

这篇文章带领大家从零开始手动撸一个React项目的基础框架,集成React全家桶。万字长文,请各位有足够的时间时再来阅读和学习。

概述
平时工作中一直在用React提供的脚手架工具搭建React项目,一行命令全都搞定,自己只管做需求开发即可,从来没仔细研究过各个模块代码怎么去配置,相互之间怎么去进行交互。这周正好有时间,所以决定仔细研究下React项目中的各个功能模块,所以我们来讲解下如何从零搭建一个完整的React项目。

目录
项目初始化
安装NodeJS环境和初始化项目

安装webpack

新建项目目录和文件
核心配置
ES6、ES7、ES8、ES9等高级语法转换成ES5

less/sass等css预处理器代码转换为css

解析字体、图片等静态资源

压缩打包后的JS、CSS文件

抽理公共代码

添加resolve选项

代码热更新

删除上一次的打包结果及记录
集成React全家桶
集成react

集成react-router-dom

集成redux

集成Antd

添加express服务接口,用axios打通前后端

操作步骤
项目初始化
安装NodeJS环境和初始化项目

在开始之前,我们本机首先要安装部署Node环境。Node环境安装部署其实很简单,只需要去官网https://nodejs.org/zh-cn/下载安装包,然后双击安装即可,中间并没有太大的坑,安装过程中会自动将node安装路径添加至操作系统的环境变量中,所以安装完成后我们直接可以在命令行中使用ndoe、npm这些命令,不像java一样还要自己手动去配环境变量。
安装完成后,我们打开命令行工具或者win10的powershell窗口,输入以下命令,如果成功输入信息,即表明Node环境安装部署成功:

node -v
npm -v

在这里插入图片描述

Node环境部署成功后,我们在he’sh合适的目录文件夹中,打开powershell窗口,输入以下命令来创建我们的项目文件夹,并且进入到这个新建的文件夹中,最后通过”npm init”来初始化一个最基础的项目框架:

mkdir myreactproject
cd .\myreactproject\
npm init

在这里插入图片描述

当我们进入到新建的项目文件夹的时候,通过”npm init”来初始化一个基础的项目框架时,命令行中会出现有一些问答信息,这些信息是在询问我们关于初始化的这个项目的一些基础信息,包括项目名称、项目描述、项目版本、入口文件、测试命令、git库地址、关键字、项目作者、项目遵循的版权信息等,在这里我们直接按回车即可,它会将默认信息填入相应的属性中,同样的,我们也可以输入自定义的一些信息,看自己喜好吧。
到此时呢,我们的一个基础项目框架已经完成了,打开这个项目文件夹,大家可以看到,在此文件夹下生成了一个”package.json”文件,里面就是我们刚才创建项目时候指定的一些基础信息,如下:

在这里插入图片描述
在这里插入图片描述

安装webpack
webpack是一个模块打包工具,它会自动分析我们项目中的依赖以及项目编码中所用的高级语法这些东西,然后将它们打包编译成浏览器可以解析运行的js和css等文件。我们可以将webpack的API和CLI配合使用,API不用过多解释,这是webpack提供给我们调用和配置的接口,CLI是webpack提供的一个类似于脚手架的东西,它允许我们在命令行中可以使用webpack命令、运行webpack,所以在此处我们安装两个东西。
在项目根目录下运行命令行或powershell工具,然后通过以下命令安装webpack和webpack-cli工具:

npm install webpack webpack-cli --save-dev

在这里插入图片描述

安装完成之后可以在项目根目录下看到,多了一个”node_modules”文件夹和一个”package-lock.json”文件,同时在我们的”package.json”文件中也多了些信息。
其中”node_modules”文件夹中存放的是我们整个项目代码中安装的一些插件模块的代码;”package-lock.json”文件是我们执行”npm install”命令后生成的,它锁定所有模块的版本号,包括主模块和所有依赖子模块。当我们执行npm install的时候,node从package.json文件读取模块名称,从package-lock.json文件中获取版本号,然后进行下载或者更新。因此,正因为有了package-lock.json文件锁定版本号,所以当我们执行npm install的时候,node不会自动更新package.json文件中的模块,必须用npm install packagename(自动更新小版本号)或者npm install packagename@x.x.x(指定版本号)来进行安装才会更新,package-lock.json文件中的版本号也会随着更新。当package.json与package-lock.json都不存在,执行”npm install”时,node会重新生成package-lock.json文件,然后把node_modules中的模块信息全部记入package-lock.json文件,但不会生成package.json文件,此时,我们可以通过”npm init –yes”或者”npm init”来初始化生成package.json文件;”package.json”文件中多出来的信息就是我们刚才安装的webpack的描述信息,它里面记录了安装的webpack的版本号和webpack-cli的版本号,如下:
在这里插入图片描述

新建项目目录和文件
项目根目录下新建”src”文件夹,用来存放后期的项目源码,然后里面新建一个“index.js”文件作为被webpack编译的文件,同时也是webpack配置的入口文件;项目根目录下再新建一个“build”文件夹,存放项目的webpack配置文件,然后在文件夹中新建”webpack.config.js”文件,用于编写webpack的核心配置代码;在项目根目录新建一个”index.html”文件,是后期我们的项目打包运行的主页面,同时项目打包后自动将打包的文件添加在该文件中。
文件目录新建完成后是如下所示的结构:

在这里插入图片描述

文件目录和文件都创建成功后,我们分别为各个文件添加上基础代码,最后测试一下搭建的基础环境是否成功。
首先是webpack.config.js文件,在此文件中我们根据官网文档,在里面添加如下代码,完成webpack的基础配置:

const path = require('path');
​
module.exports = {mode: 'development',            //此行表示我们webpack打包环境是开发环境entry: './src/index.js',        //项目的入口文件,是我们新建的index.js文件,它的路径是相对于项目根路径的,所以此处我们写的是“./src”,而不是“../src”output: {                       //配置输出信息filename: 'bundle.js',      //打包输出的文件名称,这里是一个写死的名称,后期可以改成按一定规则动态生成path: path.resolve(__dirname, '../dist')     //输出的路径,这里的路径针对的是当前目录,所以我们写成了"../dist",而不是"./dist"}
};

接下来是新建的index.js文件,在此文件我们添加以下测试代码即可,仅仅是用来测试打包是否成功:

function sum (a, b) {return a + b;
}
var result = sum (12, 23);
console.log(result);

最后将package.json文件中的script属性修改一下,使它能够让在我们命令行中输入启动命令后自动完成打包过程,如下:

"build": "webpack --config ./build/webpack.config.js"

在这里插入图片描述

到此为止呢,我们编辑和修改代码已经完成了,index.html文件中并没有增加任何代码,此时它只是一个空文件,我们后期再增加。在项目根目录下运行命令行或powershell工具,然后通过“npm run build”来启动我们的项目,此处其实并不叫启动,因为我们没有为项目配置调试服务器这些插件,准确点应该说是通过这个命令来进行项目打包,如下:
在这里插入图片描述

由上图可看到我们的项目已经顺利打包,这时候在我们项目根目录自动创建了“dist”文件夹,并且里面生成了结果文件bundle.js,如下:

在这里插入图片描述

打开bundle.js文件,我们可以看到打包后的代码,如下所示:
在这里插入图片描述

此时说明我们项目安装和配置的webpack是正确的。

核心配置
ES6、ES7、ES8、ES9等高级语法转换成ES5

ES6、ES7、ES8、ES9等这些高级语法在浏览器中是无法直接编译运行的,所以需要我们在编译运行之前对这些高级语法进行转换,将它们转换成ES5代码,以便在浏览器中进行编译运行。这个事情是babel-loader来做的,它主要是将ES6等高级语法转换成浏览器能解析运行的低级语法,所以我们要在项目根目录中安装这些插件:

npm install babel-loader @babel/core @babel/preset-env @babel/preset-react --save-dev

以上插件中babel-loader主要用于高级语法转换成低级语法,它是webpack的一个loader,用来预处理文件;@babel/core是babel的核心模块,提供转换的API;@babel/preset-env可以根据配置的目标浏览器或者运行环境将ES5+代码自动转换为ES5代码,也是babel的一个模块;@babel/preset-react用来解析React中的JSX语法,同样也是babel的模块。以上的模块写法中,前面加有”@”符号的写法是babel 7.0+版本的写法,具体的可以查看babel官网。

在这里插入图片描述

相关的babel依赖安装完成后,我们在项目根目录新建“babel.config.js”文件,用来配置babel。如果不创建此文件的话babel的配置信息我们直接写到webpack配置文件中的对应规则下的options属性中即可,在此处我们用babel.config.js配置文件的方式。在配置文件中我们加入如下代码:

const babelConfig = {presets: [                      //它的功能相当于是下面plugins的一个集合,即插件集。有了它我们不用在plugins中一个一个的配置插件了["@babel/preset-env", {useBuiltIns: "entry",    //如果用了@babel/polyfill的话,配置这个属性可以将@babel/polyfill按需引入corejs: 2}], "@babel/preset-react"],plugins: []
};
​
module.exports = babelConfig;

然后在webpack.config.js配置文件中,我们配置一下babel-loader,代码如下:

const path = require('path');
​
module.exports = {mode: 'development',entry: './src/index.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, '../dist')},module: {       //通过module属性配置babel-loaderrules: [{test: /\.js/,use: ['babel-loader?cacheDirectory=true'],include: path.join(__dirname, '../src')}]}
};

配置完成之后,我们修改下index.js中的代码,来测试下是否可以成功打包我们的ES5+的代码文件:

let xbeichen = () => {console.log('测试箭头函数');
}xbeichen();

通过在命令行运行启动命令后发现,我们的项目打包成功,如下:

在这里插入图片描述
在这里插入图片描述

以上的配置还存在两个问题,第一个首先是虽然我们打包成功了项目,这也表示着ES5+的代码我们可以顺利打包,但是我们在代码中用Promise、Set、Symbol等全局对象或者一些定义在全局对象上的方法时它都不会转换,这是因为我们的babel-loader只能转换高级语法,并不会转换新的API,所以这时候我们就需要用@babel/polyfill来为当前环境提供一个垫片;还有第二个问题是,当我们执行打包后,打包的文件里会有大量的重复代码,那我们这时候就需要提供统一的模块化的helper来减少这些helper函数的重复输出。所以就需要我们安装以下插件模块:

npm install @babel/polyfill --save-dev

在这里插入图片描述

@babel/polyfill安装完之后我们不再需要进行额外的配置,因为在上面babel的配置文件中我们已经指定了@babel/polyfill是按需引入。

npm install @babel/runtime @babel/plugin-transform-runtime @babel/plugin-syntax-dynamic-import --save-dev

在这里插入图片描述

以上三个插件安装完成之后,我们需要在babel的配置文件中进行相应的配置,如下:

const babelConfig = {presets: [["@babel/preset-env", {useBuiltIns: "entry",corejs: 2}], "@babel/preset-react"],plugins: ["@babel/plugin-syntax-dynamic-import", ["@babel/plugin-transform-runtime"]]   //就是在此处添加了两个@babel/runtime中的插件
};
​
module.exports = babelConfig;

最后我们在index.js文件中添加Promise相关的代码来查看打包结果,如下:

let xbeichen = () => {console.log('测试箭头函数');
}xbeichen();let promise = new Promise((resolve, reject) => {setTimeout(() => {resolve(123);}, 1000);
});
​
promise.then(res => {console.log(res);
});

运行启动命令后打包结果如下所示:

在这里插入图片描述

less/sass等css预处理器代码转换为css
在项目中如果我们使用了css预处理器,那就需要在打包的时候将less、sass等预处理器编写的代码转换成浏览器可以执行的css代码,这就需要我们安装以下插件,此处介绍less预处理器代码的转换配置:

npm install stylus stylus-loader less less-loader sass-loader node-sass css-loader style-loader --save-dev

在这里插入图片描述

以上安装的依赖插件中:css-loader主要的作用是解析css文件, 像@import等动态语法;style-loader主要的作用是解析的css文件渲染到html的style标签内;stylus、less、sass是CSS的常见预处理器;stylus-loader、less-loader、sass-loader主要是将其对应的语法转换成css语法。
然后我们修改webpack的配置文件,代码如下:

const path = require('path');
​
module.exports = {mode: 'development',entry: './src/index.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, '../dist')},module: {rules: [{test: /\.js/,use: ['babel-loader?cacheDirectory=true'],include: path.join(__dirname, '../src')}, {                                                 //此处再添加一条rules,用于配置css预处理器信息test: /\.less$/,use: [{loader: 'style-loader'}, {loader: 'css-loader'}, {loader: 'less-loader'}]}]}
};

在src目录下新建”index.less”文件,添加如下代码:

@color: red;
​
#div1 {color: @color;font-size: 23px;
}

复制

然后在index.js文件中我们引入新建的index.less文件,运行启动命令来执行打包,结果如下:

在这里插入图片描述
在这里插入图片描述

但是如果我们使用CSS3的一些新特性时,需要为不同的浏览器在CSS代码中添加不同的前缀,在开发中手动添加太麻烦,所以我们可以通过postcss来自动添加各种浏览器前缀。首先我们先要安装以下依赖插件:

npm install postcss-loader autoprefixer --save-dev

复制

然后在webpack配置文件中添加postcss的配置信息即可,如下:

const path = require('path');
​
module.exports = {mode: 'development',entry: './src/index.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, '../dist')},module: {rules: [{test: /\.js/,use: ['babel-loader?cacheDirectory=true'],include: path.join(__dirname, '../src')}, {test: /\.less$/,use: [{loader: 'style-loader'}, {loader: 'css-loader'}, {     //添加这段配置信息即可loader: 'postcss-loader',options: {plugins: [require('autoprefixer')]}}, {loader: 'less-loader'}]}]}
};

解析字体、图片等静态资源
在我们的项目中会使用到图片等静态资源,在此处我们来添加配置。首先是安装相关依赖,如下:

npm install file-loader url-loader --save-dev

在这里插入图片描述

以上依赖中:file-loader可以用来帮助webpack打包处理一系列的图片文件,比如:.png 、 .jpg 、.jepg等格式的图片。打包的图片会给每张图片都生成一个随机的hash值作为图片的名字;url-loader封装了file-loader,它的工作原理:1、文件大小小于limit参数,url-loader将会把文件转为Base64;2、文件大小大于limit,url-loader会调用file-loader进行处理,参数也会直接传给file-loader。
安装完依赖后,我们进行webpack的配置,代码如下:

const path = require('path');
​
module.exports = {mode: 'development',entry: './src/index.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, '../dist')},module: {rules: [{test: /\.js/,use: ['babel-loader?cacheDirectory=true'],include: path.join(__dirname, '../src')}, {test: /\.less$/,use: [{loader: 'style-loader'}, {loader: 'css-loader'}, {loader: 'postcss-loader',options: {plugins: [require('autoprefixer')]}}, {loader: 'less-loader'}]}, {                                       //配置图片静态资源的打包信息test: /\.(jpg|png|jpeg|gif)$/,use: [{loader: 'url-loader',options: {limit: 1024,fallback: {loader: 'file-loader',options: {name: 'img/[name].[hash:8].[ext]'}}}}]}, {                                       //配置多媒体资源的打包信息test: /\.(mp4|webm|ogg|mp3|wav)$/,use: [{loader: 'url-loader',options: {limit: 1024,fallback: {loader: 'file-loader',options: {name: 'media/[name].[hash:8].[ext]'}}}}]}]}
};

然后我们在项目src目录下新建”assets”文件夹,里面放置两张图片,在index.js中引入这两张图片,运行启动命令来打包项目代码,最后查看结果:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

除此之外,在我们的dist目录下新建了一个img文件夹,里面存放的是两张打包后的图片文件,如下:

在这里插入图片描述

以上是我们对静态资源打包的配置信息。

压缩打包后的JS、CSS文件
我们打包后的JS和CSS文件中存在大量的空格和引号等,这些会严重影像我们打包后的文件体积,所以接下来我们通过安装配置相应的依赖插件来压缩我们打包后的代码文件。首先安装如下依赖:

npm install mini-css-extract-plugin --save-dev

在这里插入图片描述

然后在webpack配置文件中增加我们依赖插件的配置,如下:

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');       //首先引入我们新安装的依赖插件
​
module.exports = {mode: 'development',entry: './src/index.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, '../dist')},plugins: [                             //然后新建一个plugins属性来实例化这个依赖插件new MiniCssExtractPlugin({filename: '[name].[contenthash].css',chunkFilename: '[id].[contenthash].css'})],module: {rules: [{test: /\.js/,use: ['babel-loader?cacheDirectory=true'],include: path.join(__dirname, '../src')}, {                                             //最后添加这个依赖插件的配置信息test: /\.css$/,use: [{loader: MiniCssExtractPlugin.loader,options: {publicPath: '../'}},'css-loader',]}, {test: /\.less$/,use: [{loader: 'style-loader'}, {loader: 'css-loader'}, {loader: 'postcss-loader',options: {plugins: [require('autoprefixer')]}}, {loader: 'less-loader'}]}, {test: /\.(jpg|png|jpeg|gif)$/,use: [{loader: 'url-loader',options: {limit: 1024,fallback: {loader: 'file-loader',options: {name: 'img/[name].[hash:8].[ext]'}}}}]}, {test: /\.(mp4|webm|ogg|mp3|wav)$/,use: [{loader: 'url-loader',options: {limit: 1024,fallback: {loader: 'file-loader',options: {name: 'media/[name].[hash:8].[ext]'}}}}]}]}
};

然后我们在src目录下新建”index02.css”文件,在此文件中添加css测试代码,如下:

#divview {position: relative;color: blue;width: 200px;
}

接下来在index.js文件中引入新建的这个index02.css文件和我们之前新建的index.less文件,最后运行启动命令来进行打包,最后结果如下:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

由结果可以看到,最后css文件被打包,重新在dist目录下生成了一个打包后的文件,但是我们的less文件依然是直接打包在了bundle.js的文件中,这是因为mini-css-extract-plugin这个依赖插件只针对于css文件的。

抽离公共代码
我们在打包后的JS或者CSS文件中会有很多公共代码,如果不将这些代码进行抽离,我们最后的打包文件会变得很大,所以抽离公共代码这件事情是由SplitChunksPlugin插件来做,我们只需要在webpack配置文件中加入如下代码即可:

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
​
module.exports = {mode: 'development',optimization: {        //添加抽离公共代码插件的配置splitChunks: {cacheGroups: {//打包公共模块commons: {chunks: 'initial', //initial表示提取入口文件的公共部分minChunks: 2, //表示提取公共部分最少的文件数minSize: 0, //表示提取公共部分最小的大小name: 'commons' //提取出来的文件命名}}},},entry: './src/index.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, '../dist')},plugins: [new MiniCssExtractPlugin({filename: '[name].[contenthash].css',chunkFilename: '[id].[contenthash].css'})],module: {rules: [{test: /\.js/,use: ['babel-loader?cacheDirectory=true'],include: path.join(__dirname, '../src')}, {test: /\.css$/,use: [{loader: MiniCssExtractPlugin.loader,options: {publicPath: '../'}},'css-loader',]}, {test: /\.less$/,use: [{loader: 'style-loader'}, {loader: 'css-loader'}, {loader: 'postcss-loader',options: {plugins: [require('autoprefixer')]}}, {loader: 'less-loader'}]}, {test: /\.(jpg|png|jpeg|gif)$/,use: [{loader: 'url-loader',options: {limit: 1024,fallback: {loader: 'file-loader',options: {name: 'img/[name].[hash:8].[ext]'}}}}]}, {test: /\.(mp4|webm|ogg|mp3|wav)$/,use: [{loader: 'url-loader',options: {limit: 1024,fallback: {loader: 'file-loader',options: {name: 'media/[name].[hash:8].[ext]'}}}}]}]}
};

添加resolve选项
这个选项的作用是为了方便我们开发者,比如文件的别名、文件的扩展名等,具体的配置如下:

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
​
module.exports = {mode: 'development',optimization: {splitChunks: {cacheGroups: {//打包公共模块commons: {chunks: 'initial', //initial表示提取入口文件的公共部分minChunks: 2, //表示提取公共部分最少的文件数minSize: 0, //表示提取公共部分最小的大小name: 'commons' //提取出来的文件命名}}},},entry: './src/index.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, '../dist')},plugins: [new MiniCssExtractPlugin({filename: '[name].[contenthash].css',chunkFilename: '[id].[contenthash].css'})],module: {rules: [{test: /\.js/,use: ['babel-loader?cacheDirectory=true'],include: path.join(__dirname, '../src')}, {test: /\.css$/,use: [{loader: MiniCssExtractPlugin.loader,options: {publicPath: '../'}},'css-loader',]}, {test: /\.less$/,use: [{loader: 'style-loader'}, {loader: 'css-loader'}, {loader: 'postcss-loader',options: {plugins: [require('autoprefixer')]}}, {loader: 'less-loader'}]}, {test: /\.(jpg|png|jpeg|gif)$/,use: [{loader: 'url-loader',options: {limit: 1024,fallback: {loader: 'file-loader',options: {name: 'img/[name].[hash:8].[ext]'}}}}]}, {test: /\.(mp4|webm|ogg|mp3|wav)$/,use: [{loader: 'url-loader',options: {limit: 1024,fallback: {loader: 'file-loader',options: {name: 'media/[name].[hash:8].[ext]'}}}}]}]},resolve: {                                    //resolve核心配置extensions: ['.js', '.jsx', '.json'],alias: {pages: path.join(__dirname, '../src/pages'),components: path.join(__dirname, '../src/components'),actions: path.join(__dirname, '../src/redux/actions'),reducers: path.join(__dirname, '../src/redux/reducers'),images: path.join(__dirname, '../src/images')}},
};

代码热更新
代码热更新需要安装以下两个依赖模块,如下:

npm install webpack-dev-server --save-dev
npm install html-webpack-plugin --save-dev

在这里插入图片描述
在这里插入图片描述

其中第一个依赖插件是热更新插件,第二个是我们的html-webpack-plugin插件,这个插件的作用是它可以每次动态的将我们打包后的js、css文件加入到index.html页面中。其中webpack的配置信息如下:

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');      //引入html模板插件
​
module.exports = {mode: 'development',optimization: {splitChunks: {cacheGroups: {//打包公共模块commons: {chunks: 'initial', //initial表示提取入口文件的公共部分minChunks: 2, //表示提取公共部分最少的文件数minSize: 0, //表示提取公共部分最小的大小name: 'commons' //提取出来的文件命名}}},},entry: './src/index.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, '../dist')},plugins: [new MiniCssExtractPlugin({filename: '[name].[contenthash].css',chunkFilename: '[id].[contenthash].css'}),new HtmlWebpackPlugin({             //实例化Html模板模块template: path.resolve(__dirname, '../index.html')})],module: {rules: [{test: /\.js/,use: ['babel-loader?cacheDirectory=true'],include: path.join(__dirname, '../src')}, {test: /\.css$/,use: [{loader: MiniCssExtractPlugin.loader,options: {publicPath: '../'}},'css-loader',]}, {test: /\.less$/,use: [{loader: 'style-loader'}, {loader: 'css-loader'}, {loader: 'postcss-loader',options: {plugins: [require('autoprefixer')]}}, {loader: 'less-loader'}]}, {test: /\.(jpg|png|jpeg|gif)$/,use: [{loader: 'url-loader',options: {limit: 1024,fallback: {loader: 'file-loader',options: {name: 'img/[name].[hash:8].[ext]'}}}}]}, {test: /\.(mp4|webm|ogg|mp3|wav)$/,use: [{loader: 'url-loader',options: {limit: 1024,fallback: {loader: 'file-loader',options: {name: 'media/[name].[hash:8].[ext]'}}}}]}]},resolve: {extensions: ['.js', '.jsx', '.json'],alias: {pages: path.join(__dirname, '../src/pages'),components: path.join(__dirname, '../src/components'),actions: path.join(__dirname, '../src/redux/actions'),reducers: path.join(__dirname, '../src/redux/reducers'),images: path.join(__dirname, '../src/images')}},devServer: {            //配置热更新模块hot: true,open: true,port: 3500,contentBase: '../dist'}
};

webpack配置好之后,我们在package.json中添加启动命令,这次的启动命令是真正意义的启动命令,如下所示:

"dev": "webpack-dev-server --config ./build/webpack.config.js"

在这里插入图片描述

在命令行中输入npm run dev来启动项目,这时候浏览器会自动打开,我们打开浏览器控制台可以看到,输出了我们在index.js中编写的代码,此时也说明它是将我们的js、css文件自动加载到index.html页面中了,如下:

在这里插入图片描述

此处我们index.js中的代码如下:

import './index.less';
import './index02.css';let sun = () => {console.log('xbeichen');
};sun();

同样的,这时候我们运行打包命令,可以看到dist目录下的打包结果,如下:

在这里插入图片描述

由上图可看到,它打包生成了三个文件,并且在html文件中,自动的将js和css文件引入进去了。

删除上一次的打包结果及记录
我们每次运行打包命令之前都要手动删除dist文件夹,不然的话它每次打包都会在dist文件夹中加入新的打包内容,上一次的打包内容还存留着,所以我们要安装clean-webpack-plugin插件来将我们上一次的打包记录及结果删除,安装配置如下:

npm install clean-webpack-plugin --save-dev

在这里插入图片描述

webpack中的配置信息如下:

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');     //引入clean-webpack-plugin插件
​
module.exports = {mode: 'development',optimization: {splitChunks: {cacheGroups: {//打包公共模块commons: {chunks: 'initial', //initial表示提取入口文件的公共部分minChunks: 2, //表示提取公共部分最少的文件数minSize: 0, //表示提取公共部分最小的大小name: 'commons' //提取出来的文件命名}}},},entry: './src/index.js',output: {filename: 'bundle.js',path: path.resolve(__dirname, '../dist')},plugins: [new CleanWebpackPlugin(),          //实例化clean-webpack-plugin插件new MiniCssExtractPlugin({filename: '[name].[contenthash].css',chunkFilename: '[id].[contenthash].css'}),new HtmlWebpackPlugin({template: path.resolve(__dirname, '../index.html')})],module: {rules: [{test: /\.js/,use: ['babel-loader?cacheDirectory=true'],include: path.join(__dirname, '../src')}, {test: /\.css$/,use: [{loader: MiniCssExtractPlugin.loader,options: {publicPath: '../'}},'css-loader',]}, {test: /\.less$/,use: [{loader: 'style-loader'}, {loader: 'css-loader'}, {loader: 'postcss-loader',options: {plugins: [require('autoprefixer')]}}, {loader: 'less-loader'}]}, {test: /\.(jpg|png|jpeg|gif)$/,use: [{loader: 'url-loader',options: {limit: 1024,fallback: {loader: 'file-loader',options: {name: 'img/[name].[hash:8].[ext]'}}}}]}, {test: /\.(mp4|webm|ogg|mp3|wav)$/,use: [{loader: 'url-loader',options: {limit: 1024,fallback: {loader: 'file-loader',options: {name: 'media/[name].[hash:8].[ext]'}}}}]}]},resolve: {extensions: ['.js', '.jsx', '.json'],alias: {pages: path.join(__dirname, '../src/pages'),components: path.join(__dirname, '../src/components'),actions: path.join(__dirname, '../src/redux/actions'),reducers: path.join(__dirname, '../src/redux/reducers'),images: path.join(__dirname, '../src/images')}},devServer: {hot: true,open: true,port: 3500,contentBase: '../dist'}
};

此时我们再次运行打包命令,结果如下:
在这里插入图片描述

它会删除掉上一次打包后的文件,并进行重新打包。
以上两部分的介绍是关于如何创建一个基于webpack的基础项目框架,并对webpack基础配置的介绍,到此为止我们的基础框架已经搭建完成了,在其中我们配置了webpack的相关基础配置信息,同时也指定了项目的打包命令和启动命令,接下来我们在项目中引入React,打造React项目框架。

集成React全家桶
集成react

集成react无非就是在项目框架中引入react和react-dom两个依赖插件,首先我们来进行安装,如下:

npm install react react-dom --save-dev

在这里插入图片描述

安装完成之后,我们在index.js中编写React代码,就是独具特色的JSX语法,因为在刚开始时我们已经配置了相应的loader,所以后面项目启动的时候,它是可以将我们里面的JSX代码编译成ES5代码的,如下:

import React from 'react';
import ReactDom from 'react-dom';
​
ReactDom.render(<div>X北辰北</div>,document.getElementById('xbeichen')
)

然后在项目根目录下的index.html文件中添加如下代码:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div id="xbeichen"></div>
</body>
</html>

现在我们通过npm run dev来启动项目,可以发现,此时我们将“X北辰北”字样渲染在了我们的前端页面,如下:
在这里插入图片描述

集成react-router-dom
配置好了基础的React环境之后,我们接下来配置路由。首先是安装依赖模块,如下:

npm install react-router-dom --save-dev

在这里插入图片描述

模块安装完成之后,我们在src目录下新建一个pages文件夹,然后在此文件夹下新建两个react组件,名称分别为ComponentOne和ComponentTwo,分别添加如下代码:
在这里插入图片描述

/

/组件一代码
import React,{ Component } from 'react';class ComponentOne extends Component {render () {return (<div><h3>组件1</h3></div>)}
}export default ComponentOne;
//组件二代码
import React,{ Component } from 'react';class ComponentTwo extends Component {render () {return (<div><h3>组件2</h3></div>)}
}export default ComponentTwo;

组件新建完成之后,我们在src目录下新建一个router文件夹,里面新建一个routers.js文件,用来进行路由模块化配置,然后在此文件中添加如下代码:
在这里插入图片描述

import ComponentOne from '../pages/ComponentOne';
import ComponentTwo from '../pages/ComponentTwo';let routes = [{path: '/',component: ComponentOne,exact: true}, {path: '/two',component: ComponentTwo}
];export default routes;

然后我们修改index.js文件,引入react-router-dom模块,进行路由配置,代码如下:

import React from 'react';
import ReactDom from 'react-dom';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import routes from './router/routers';
​
ReactDom.render(<Router><Link to="/">组件一</Link><br /><Link to="/two">组件二</Link>{routes.map((value, key) => {if(value.exact) {return <Route exact path={value.path} component={value.component} key={key} />}else {return <Route path={value.path} component={value.component} key={key} />}})}</Router>,document.getElementById('xbeichen')
)

此时我们已经完成了路由的配置,并且在此处还做了路由的模块化配置,最后我们启动项目,就可以看到下面的结果:
在这里插入图片描述

集成redux(后续更新)
集成Ant Design
此时Antd最新版本是4.0.1,那在此处我们就直接集成最新版。首先是安装这个插件:

npm install antd --save-dev

在这里插入图片描述

安装完成之后,我们在index.js中引入它的css文件,然后按照官网的组件实例代码来将我们之前配置的路由点击元素换成Antd的按钮组件,如下:

import React from 'react';
import ReactDom from 'react-dom';
import { Button } from 'antd';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import routes from './router/routers';
import 'antd/dist/antd.css';
​
ReactDom.render(<Router><Link to="/"><Button type="primary">组件一</Button></Link><br /><br /><Link to="/two"><Button type="primary">组件二</Button></Link>{routes.map((value, key) => {if(value.exact) {return <Route exact path={value.path} component={value.component} key={key} />}else {return <Route path={value.path} component={value.component} key={key} />}})}</Router>,document.getElementById('xbeichen')
)

最后启动项目,得到如下所示的结果:
在这里插入图片描述

这样我们就简单地完成了Antd的集成,具体的样式优化大家可以后面慢慢调。

添加express服务接口,用axios打通前后端
在项目根目录安装express和axios,如下:

npm install express axios --save-dev

在这里插入图片描述

其中Express是一个基于NodeJS的轻量级后台服务器框架,axios是一个基于Promise的HTTP网络请求库。安装完成之后,我们在项目根目录下新建server文件夹,然后在里面新建一个server.js文件,并添加如下代码,用来初始化我们的后台服务器:
在这里插入图片描述

const express = require('express');
const app = express();
​
app.get('/api/xuqw', (req, res) => {res.header('Access-Control-Allow-Origin', '\*');res.send({name: 'xbeichen',comurl: 'geov.online'});
});
​
app.listen(3000, () => {console.log('app listen 3000 port');
});

然后进入server这个文件夹,在这个文件夹目录下打开命令行工具,通过命令”node server.js”来启动后台服务器,然后在浏览器中通过接口地址来访问测试,如下:
在这里插入图片描述

在这里插入图片描述

以上可看到,我们的后台是运行成功的。接下来我们在ComponentTwo.js中添加一个生命周期函数,在这个函数里编写axios代码,让这个组件完成加载时去请求我们的后台获取数据,代码如下:

import React,{ Component } from 'react';
import axios from 'axios';class ComponentTwo extends Component {componentDidMount () {axios.get('http://localhost:3000/api/xuqw').then(res => {console.log(res);})}render () {return (<div><h3>组件2</h3></div>)}
}export default ComponentTwo;

然后我们启动前端项目系统,并且启动后台项目系统,点击组件二按钮时路由会跳转加载组件2,当它完成挂载后我们的生命周期函数就会自动执行,这时候axios就通过我们的后台接口去获取数据,最后将获取到的数据在浏览器控制台打印,如下:
在这里插入图片描述

在请求过程中如果我们遇到跨域的问题,那就要在webpack配置文件中进行配置跨域了,配置参考信息如下:
在这里插入图片描述

以上就是在项目中新建系统后台,然后用axios打通前后台数据交互的全过程了。
至此呢,本篇文章也就结束了。

总结
其实通过本篇文章的介绍,我们发现从0搭建一个React项目,它的本质还是在配置webpack的各种配置信息,只有把webpack玩得转、至于React或者Vue项目,那就相当于在基于webpack搭建的项目引入了一个开发包而已,所以最终需求还是要求我们一定要对webpack了解的够熟悉,并且现在webpack5快要出来了,好多大佬已经尝鲜了,你还不行动嘛。
原文链接 https://cloud.tencent.com/developer/article/1945103


http://chatgpt.dhexx.cn/article/yQibOc0j.shtml

相关文章

推荐10个不错的React开源项目

1&#xff0c;Kutt.it Kutt是一个现代的URL缩短器&#xff0c;支持自定义域&#xff0c;可以用来缩短网址、管理链接并查看点击率统计信息。Kutt支持自定义域名&#xff0c;设置链接密码和描述&#xff0c;缩短URL的私人统计信息&#xff0c;查看、编辑、删除和管理链接&#…

Github上8个很棒的React项目

大家好&#xff0c;我是若川。持续组织了近一年的源码共读活动&#xff0c;感兴趣的可以 点此加我微信ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。…

MySQL 数据库引擎比较

MyISAM: 优势 – 查询速度快 – 数据和索引压缩 问题 – 表级锁 – 数据丢失 InnoDB: 优势 – 行级锁 – 事务支持 – 数据安全 问题 – 数据文件庞大 – 启动慢 – 不支持FULLTEXT索引 比较:

数据库_mysql数据库引擎_数据库索引

文章目录 前言一、MySql数据库引擎1.1、数据库引擎任务1.2、常用的数据库引擎1.2.1、InnoDB存储引擎页主要部分 InnoDB的几个变量 1.2.2、MyISAM存储引擎1.3 、存储引擎设置1.4、如何选择存储引擎 二、索引的数据结构2.1、什么是索引2.2、索引有什么用2.3、优点和缺点2.4 为什么…

【Mysql】数据库引擎

引擎 存储引擎数据库引擎数据库引擎的定义数据库引擎的任务mySql引擎的类别ISAM引擎MyISAM引擎Heap引擎InnoDB引擎InnoDB与MyISAM对比 存储引擎 MySQL常见的两种存储引擎&#xff1a;MyISAM和InnoDB 数据库引擎 数据库引擎的定义 访问数据库时&#xff0c;通过数据库引擎访…

mysql之数据库引擎

一&#xff1a;引擎概述 1&#xff0c;为什么要合理选择数据库存储引擎&#xff1f; MySQL中的数据用各种不同的技术存储在文件&#xff08;或者内存&#xff09;中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。通过…

MYSQL——MYSQL中常见的数据库引擎

文章目录 MYSQL中常见的数据库引擎1、什么是数据库引擎&#xff1f;2、MYSQL中有哪些数据库引擎3、常见引擎介绍&#xff08;1&#xff09;InnoDB&#xff08;2&#xff09;MyISAM&#xff08;3&#xff09;Memory&#xff08;Heap&#xff09; MYSQL中常见的数据库引擎 1、什…

Mysql:数据库引擎

废话不多说&#xff0c;我们先看MySql 用到了那些引擎 SHOW ENGINES 直接可以看到有下面这些引擎 InnoDB&#xff0c;MRG_MYISAM&#xff0c;MEMORY&#xff0c;BLACKHOLE&#xff0c;MyISAM&#xff0c;CSV&#xff0c;ARCHIVE&#xff0c;PERFORMANCE_SCHEMA&#xff0c;FE…

MySQL体系结构及数据库引擎

文章目录 一、MYSQL的体系结构1、连接器2、查询缓存3、分析器&#xff08;要做什么&#xff09;4、优化器&#xff08;怎么做&#xff09;5、执行器6、数据库引擎1&#xff09;mysql支持的引擎2&#xff09;常用的mysql引擎比较3&#xff09;索引组织表、堆组织表4&#xff09;…

MySQL数据引擎

一、MySQL提供什么存储引擎 mysql> SHOW ENGINES;二、查看默认的存储引擎&#xff1a; mysql> SHOW VARIABLES LIKE %storage_engine%;三、各种引擎介绍 1、InnoDB存储引擎&#xff08;1&#xff09;大于等于5.5之后&#xff0c;默认采用InnoDB引擎&#xff08;2&…

MySQL数据库引擎详解

作为经常使用MySQL数据库的人&#xff0c;不得不对MySQL的数据库引擎有一定的了解&#xff0c;在之前我也是只会使用MySQL&#xff0c;但两次的面试中都被面试官问及项目用到的数据库引擎&#xff08;血与泪&#xff09;&#xff0c;因此&#xff0c;有必要写一篇文章&#xff…

数据库引擎

一&#xff1a;数据库引擎的定义 数据库引擎简单来说就是一个"数据库发动机"。当你访问数据库时&#xff0c;不管是手工访问&#xff0c;还是程序访问&#xff0c;都不是直接读写数据库文件&#xff0c;而是 通过数据库引擎去访问数据库文件。以关系型数据库为例&…

MySQL的数据库引擎介绍

1、什么是数据库引擎 数据库引擎就是操作数据库的一段程序或程序段&#xff0c;用于存储、处理和保护数据的核心服务。 利用数据库引擎可控制访问权限并快速处理事务&#xff0c;从而满足企业内大多数需要处理大量数据的应用程序的要求。数据库应用项目是通过数据库引擎与数据库…

CY7C68013 内存溢出问题

最近在开发CY68013 USB芯片的时候&#xff0c;开发环境&#xff08;keil C51&#xff09;&#xff0c;开始的时候都编译正常&#xff0c;但是在我增加了一些变量和操作后&#xff0c;出现了很多的报错&#xff0c;提示内存溢出 *** ERROR L107: ADDRESS SPACE OVERFLOW 之前的…

基于CY7C68013A usb转mdio win10 64bit

基于CY7C68013A usb转mdio win10 64bit 1、芯片简介&#xff1a; 目前市场上主流的实现USB通信的方案主要是基于stm32(基于目前比较流行的DAPLink方案)/ft232/ch341等&#xff0c;CY7C68013A芯片历史较久&#xff0c;价格也相对偏高但USB通信设计的方法应该都是一致的。 手上…

CY7C68013与FPGA接口的Verilog

USB(通用串行总线)是英特尔、微软、IBM、康柏等公司1994年联合制定的一种通用串行总线规范&#xff0c;它解决了与网络通信问题&#xff0c;而且端口扩展性能好、容易使用。最新的USB2.0支持3种速率&#xff1a;低速1.5 Mbit/s&#xff0c;全速12 Mbit/s&#xff0c;高速480 Mb…

CY7C68013A之LED闪烁

#include "fx2.h" #include "fx2regs.h"sbit LED_PIN IOD ^ 3;main() {unsigned long i 0;OED | 0x08; //PD3 Output Enable;while(TRUE){if( i > 50000 ){i 0;LED_PIN ~LED_PIN;}} } 程序下载 Download是将程序下载到RAM&#xff0c;Lg E…

CY7C68013与FPGA接口的Verilog_HDL实现

USB(通用串行总线)是英特尔、微软、IBM、康柏等公司1994年联合制定的一种通用串行总线规范&#xff0c;它解决了与网络通信问题&#xff0c;而且端口扩展性能好、容易使用。最新的USB2.0支持3种速率&#xff1a;低速1.5 Mbit/s&#xff0c;全速12 Mbit/s&#xff0c;高速480 Mb…

cy7c68013linux驱动,CY7C68013A USB Board教程2:CY7C68013A USB Board驱动安装

2、我们打开软件&#xff0c;看看可以怎么加载驱动&#xff1a; 3、这里面涉及到模块的VID和PID&#xff0c;具体怎么看呢&#xff0c;详见下图&#xff1a; 4、接着就是修改驱动文件上的VID和PID了&#xff0c;我们打开安装路径下的驱动目录&#xff0c;如下&#xff1a; 5、找…

FPGA----CY7C68013使用记录

一、CY7C68013简介 CY7C68013是Cypress公司的FX2系列芯片&#xff0c;是一款USB2.0芯片&#xff0c;最大传输速度60MByte/S &#xff0c;半双工通信方式。 功能引脚说明FD0~FD718~25数据线低字节FD8~FD1545~52数据线高字节 FIFOADDR0 FIFOADDR1 37 38 地址线&#xff0c;接收…