React 学习
利用webpack创建React框架项目
开发模式
/*
* @Description:
* @Author: 莲白
* @Date: 2022-09-23 08:24:47
* @LastEditTime: 2022-09-23 11:57:47
* @LastEditors: 莲白
*/
/**
* eslint 处理
*/
const path=require('path')
const EslintWebpackPlugin=require('eslint-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const isDevelopment = process.env.NODE_ENV !== 'production';
/**
* 公共方法处理相同样式处理代码
* @param {*} pre 判断是sass或者less
* @returns
*/
const getStyleloaders=(pre)=>{
return [
'style-loader','css-loader',{
loader:"postcss-loader",
options:{
postcssOptions:{
plugins:['postcss-preset-env'],
}
}
},
pre
].filter(Boolean)
}
module.exports={
entry:'./src/main.js',
output:{
path:undefined,
filename:"static/js/[name].js",
chunkFilename:"static/js/[name].chunk.js",
assetModuleFilename:'static/media/[hash:10][ext][query]',
},
module:{
rules:[
//处理css 兼容性问题
//配合pack.json中的browserslist 来指定兼容性到什么成度
{
test:/\.css$/,
use:getStyleloaders(),
},
{
test:/\.less$/,
use:getStyleloaders('less-loader'),
},
{
test:/\.s[ac]ss$/,
use:getStyleloaders('sass-loader'),
},
{
test:/\.styl$/,
use:getStyleloaders('stylus-loader'),
},
//处理图片
{
test:/\.(jpe?g|png|gif|webp|svg)/,
type:"asset",
parser:{
dataUrlCondition:{
maxSize:10*1024,//一般来说10kb
}
},
},
{
//处理其他资源
test:/\.(wpff2?|ttf|map3|mp4)/,
type:"asset/resource",
},
//处理js
{
test:/\.jsx?$/,
exclude: /node_modules/,
include:path.resolve(__dirname,'../src'),
loader:require.resolve('babel-loader'),
options:{
cacheDirectory:true,
cacheCompression:false,
plugins: [isDevelopment && require.resolve('react-refresh/babel')].filter(Boolean) //激活js功能
},
},
],
},
//处理html
plugins:[
new EslintWebpackPlugin({
context:path.resolve(__dirname,'../src'),
exclude:'node_modules',
cache:true,
cacheLocation:path.resolve(__dirname,'../node_modules/.cache/.eslintcache'),
}),
new HtmlWebpackPlugin({
template:path.resolve(__dirname,'../public/index.html')
}),
isDevelopment && new ReactRefreshWebpackPlugin(),
].filter(Boolean),
//开发模式
mode: "development",
devtool:'cheap-module-source-map',
optimization:{
splitChunks: {
// include all types of chunks
chunks: 'all',
},
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}`,
},
},
//webpack解析模块加载选项
resolve:{
//自动补齐文件扩展名
extensions:['.jsx','.js','.json'],
},
devServer:{
host:"localhost",
port:3300,
open:true,
hot:true,//开启HMR
historyApiFallback: true ,//解决报错404页面无法加载的问题
},
}
相关依赖指令:
npm i eslint-webpack-plugin html-webpack-plugin style-loader css-loader postcss-loader postcss-preset-env less-loader sass-loader sass stylus-loader -D 样式-图片-其他处理依赖
npm i babel-loader @babel/core babel-preset-react-app eslint-config-react-app -D balel/eslint 相关依赖
npm i webpack-dev-server webpack webpack-cli -D webpack 相关依赖
npm i react react-dom react 依赖
npm install --save-dev cross-env cross-env 依赖
npm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh 开启HMR 依赖
npm i react-router-dom react 路由依赖
生产模式
/*
* @Description:
* @Author: 莲白
* @Date: 2022-09-23 08:24:47
* @LastEditTime: 2022-09-24 10:40:16
* @LastEditors: 莲白
*/
/**
* eslint 处理
*/
const path = require("path");
const EslintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerWebpackPlugin = require("css-minimizer-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
const ImageMinimizerWebpackPlugin = require("image-minimizer-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
/**
* 公共方法处理相同样式处理代码
* @param {*} pre 判断是sass或者less
* @returns
*/
const getStyleloaders = (pre) => {
return [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["postcss-preset-env"],
},
},
},
pre,
].filter(Boolean);
};
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "../dist"),
filename: "static/js/[name].[contenthash:10].js",
chunkFilename: "static/js/[name].chunk.js",
assetModuleFilename: "static/media/[hash:10][ext][query]",
clean: true,
},
module: {
rules: [
//处理css 兼容性问题
//配合pack.json中的browserslist 来指定兼容性到什么成度
{
test: /\.css$/,
use: getStyleloaders(),
},
{
test: /\.less$/,
use: getStyleloaders("less-loader"),
},
{
test: /\.s[ac]ss$/,
use: getStyleloaders("sass-loader"),
},
{
test: /\.styl$/,
use: getStyleloaders("stylus-loader"),
},
//处理图片
{
test: /\.(jpe?g|png|gif|webp|svg)/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, //一般来说10kb
},
},
},
{
//处理其他资源
test: /\.(wpff2?|ttf|map3|mp4)/,
type: "asset/resource",
},
//处理js
{
test: /\.jsx?$/,
exclude: /node_modules/,
include: path.resolve(__dirname, "../src"),
loader: require.resolve("babel-loader"),
options: {
cacheDirectory: true,
cacheCompression: false,
},
},
],
},
//处理html
plugins: [
new EslintWebpackPlugin({
context: path.resolve(__dirname, "../src"),
exclude: "node_modules",
cache: true,
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/.eslintcache"
),
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
}),
new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:10].css",
chunkFilename: "static/css/[name].[contenthash:10].chunk.css",
}),
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "../public"),
to: path.resolve(__dirname, "../dist"),
globOptions: {
//忽略index.html文件
ignore: ["**/index.html"],
},
},
],
}),
].filter(Boolean),
//开发模式
mode: "production",
devtool: "source-map",
optimization: {
splitChunks: {
// include all types of chunks
chunks: "all",
},
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}`,
},
minimizer: [
new CssMinimizerWebpackPlugin(), //css压缩
new TerserWebpackPlugin(), // js压缩
new ImageMinimizerWebpackPlugin({
minimizer: {
implementation: ImageMinimizerWebpackPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical",
},
},
],
},
],
],
},
},
}), //图片压缩
],
},
//webpack解析模块加载选项
resolve: {
//自动补齐文件扩展名
extensions: [".jsx", ".js", ".json"],
},
};
具体依赖:
生产环境依赖
npm i css-minimizer-webpack-plugin mini-css-extract-plugin -D 样式压缩依赖
npm i image-minimizer-webpack-plugin imagemin -D 图片压缩依赖
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo -D 无损压缩(推荐) 如果下载不下来,请换成淘宝镜像
npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo -D 有损压缩
npm install copy-webpack-plugin --save-dev 复制数据依赖 如果下载不下来,请换成淘宝镜像
最终优化版本
/*
* @Description:
* @Author: 莲白
* @Date: 2022-09-23 08:24:47
* @LastEditTime: 2022-09-24 11:52:58
* @LastEditors: 莲白
*/
/**
* eslint 处理
*/
const path = require("path");
const EslintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerWebpackPlugin = require("css-minimizer-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
const ImageMinimizerWebpackPlugin = require("image-minimizer-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
/**
* 公共方法处理相同样式处理代码
* @param {*} pre 判断是sass或者less
* @returns
*/
//获取cross-env定义的环境变量
const isProduction = process.env.NODE_ENV === "production";
console.log(process.env.NODE_ENV, "99999");
const getStyleloaders = (pre) => {
return [
isProduction ? MiniCssExtractPlugin.loader : "style-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["postcss-preset-env"],
},
},
},
pre && {
loader: pre,
options:
pre === "less-loader"
? {
lessOptions: {
//ant 自定义主体配置颜色
modifyVars: { "@primary-color": "#1DA57A" },
javascriptEnabled: true,
},
}
: {},
},
].filter(Boolean);
};
module.exports = {
entry: "./src/main.js",
output: {
path: isProduction ? path.resolve(__dirname, "../dist") : undefined,
filename: isProduction
? "static/js/[name].[contenthash:10].js"
: "static/js/[name].js",
chunkFilename: isProduction
? "static/js/[name].[contenthash:10].chunk.js"
: "static/js/[name].chunk.js",
assetModuleFilename: "static/media/[hash:10][ext][query]",
clean: true,
},
module: {
rules: [
//处理css 兼容性问题
//配合pack.json中的browserslist 来指定兼容性到什么成度
{
test: /\.css$/,
use: getStyleloaders(),
},
{
test: /\.less$/,
use: getStyleloaders("less-loader"),
},
{
test: /\.s[ac]ss$/,
use: getStyleloaders("sass-loader"),
},
{
test: /\.styl$/,
use: getStyleloaders("stylus-loader"),
},
//处理图片
{
test: /\.(jpe?g|png|gif|webp|svg)/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, //一般来说10kb
},
},
},
{
//处理其他资源
test: /\.(wpff2?|ttf|map3|mp4)/,
type: "asset/resource",
},
//处理js
{
test: /\.jsx?$/,
exclude: /node_modules/,
include: path.resolve(__dirname, "../src"),
loader: require.resolve("babel-loader"),
options: {
cacheDirectory: true,
cacheCompression: false,
plugins: [!isProduction && "react-refresh/babel"].filter(Boolean), //激活js功能
},
},
],
},
//处理html
plugins: [
new EslintWebpackPlugin({
context: path.resolve(__dirname, "../src"),
exclude: "node_modules",
cache: true,
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/.eslintcache"
),
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
}),
isProduction &&
new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:10].css",
chunkFilename: "static/css/[name].[contenthash:10].chunk.css",
}),
isProduction &&
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "../public"),
to: path.resolve(__dirname, "../dist"),
globOptions: {
//忽略index.html文件
ignore: ["**/index.html"],
},
},
],
}),
!isProduction && new ReactRefreshWebpackPlugin(),
].filter(Boolean),
//开发模式
mode: isProduction ? "production" : "development",
devtool: isProduction ? "source-map" : "cheap-module-source-map",
optimization: {
splitChunks: {
// include all types of chunks
chunks: "all",
cacheGroups: {
//react react-dom react-router-dom 一起打包成一个js文件
react: {
test: /[\\/]node_modules[\\/]react(.*)?[\\/]/,
name: "chunk-react",
priority: 40, //权重
},
//antd 单独打包
antd: {
test: /[\\/]node_modules[\\/]antd[\\/]/,
name: "chunk-antd",
priority: 30, //权重
},
//剩下的node_modules 单独打包
lib: {
test: /[\\/]node_modules[\\/]/,
name: "chunk-libs",
priority: 20, //权重
},
},
},
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}`,
},
//是否需要压缩
minimize: isProduction,
minimizer: [
new CssMinimizerWebpackPlugin(), //css压缩
new TerserWebpackPlugin(), // js压缩
new ImageMinimizerWebpackPlugin({
minimizer: {
implementation: ImageMinimizerWebpackPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical",
},
},
],
},
],
],
},
},
}), //图片压缩
],
},
//webpack解析模块加载选项
resolve: {
//自动补齐文件扩展名
extensions: [".jsx", ".js", ".json"],
},
devServer: {
host: "localhost",
port: 3300,
open: true,
hot: true, //开启HMR
historyApiFallback: true, //解决报错404页面无法加载的问题
},
performance:false, //关闭性能分析,提升打包速度
};
参考源码:
git hub 地址:
https://github.com/yingxingxing/React.git
下载后指令:
cnpm i antd
cnpm i less
cnpm i eslint
由于npm 下载依赖问题,请换成淘宝镜像,如遇到问题可提出来,共同讨论,共同进步,谢谢!
使用脚手架初始化项目
npx create-react-app my-app
cd my-app
npm start 或yarn start
my-app 为项目名称
脚手架中使用React 包
1.导入react和react -dom 两个包
1.导入react 和react-dom 两个包
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
2.绑定根元素
const root = ReactDOM.createRoot(document.getElementById('root'));
3.渲染组件元素
root.render(
<App />
);
JSX语法
const title=<div>JSX语法</div>
注意:
1.React 元素的属性名 使用驼峰命名法
2.特殊属性名:class->className,for–>htmlFor ,tabindex->tabIndex
3.没有子节点的React元素可以用/>结束
4.推荐:使用小括号包裹JSX,从而避免JS中的自动插入分号陷阱
JSX中使用js表达式
数据存储在js中
语法(javaScript表达式))
注意:语法中是单大括号,不是双大括号
{}单花括号
注意点
单大括号中可以使用任意的javaScript表达式 例如:
1.数字,2.字符串,3.运算,4.三元表达式 5.函数
JS中的对象是一个例外,一般只会出现在style属性中
注意:不能在{}中出现语句(比如:if/for等)
JSX中的条件渲染
条件渲染:根据条件渲染特定的jsx结构
可以使用if/else或者三元运算符或逻辑与运算符来实现
JSX中的列表渲染
如果要渲染一组数据,应该使用数据的map()方法
注意:渲染列表时应该添加key属性,key属性的值要保证唯一
原则map()遍历谁,就要给谁添加key属性
const array=[
{
id:1,
title:'莲白'
},
{
id:2,
title:'莲花'
},
]
{array.map(item=>{ return <li key={item.id}>{item.title} </li>})}
JSX样式渲染
1.行内样式 —style
<header style={{display:'flex'}}>
</header>
- 类名----className(推荐)
<div className="App">
</div>