likes
comments
collection
share

React项目构建详解(不含ESLint和Prettier)

作者站长头像
站长
· 阅读数 23

React项目构建详解(不含ESLint和Prettier)

一、初始化项目

yarn init

二、Webpack 打包三件套

1.webpack webpack核心

2.webpack-cli 命令行中运行 webpack 的工具

3.webpack-merge 分离的配置进行合并

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

webpack 相关的东西人家官网写的还是很好,要学会看文档。

三、安装React 和 React-Dom

1.React React核心提供React API

2.ReactDom 渲染器,渲染DOM树

yarn add react react-dom

四、解析器

首先根据考虑需要哪些解析器,比如 html ts js jsx css less sass png jpg ttf 等

举例:

文件或功能解析器或插件备注
htmlhtml-webpack-pluginhtml解析和打包插件
csscss-loadercss解析器
lessless-loaderless解析器
sasssass-loadersass解析器
filefile-loader文件解析器
threadthread-loader多线程打包
mini-css-extract-pluginmini-css-extract-plugincss文件提取插件
postcsspostcsscss浏览器兼容处理
babel-loaderbabel-loaderwebpack使用babel

五、babel(代码转化器)

1、作用

高版本ES转换语法到低版本ES语法。

2、安装

yarn add  @babel/core core-js @babel/preset-env babel-loader @babel/preset-react @babel/preset-typescript babel-plugin-dynamic-import-node @babel/plugin-transform-runtime @babel/plugin-transform-runtime @babel/plugin-proposal-decorators -D

3、说明

文件或功能解析器或插件备注
@babel/core@babel/corebabel核心
babel-loaderbabel-loaderwebpack使用babel
core-jscore-jsJavaScript的模块化标准库
@babel/preset-env@babel/preset-env转码插件
@babel/preset-react@babel/preset-reactreact转码插件,包含3个插件,有兴趣点击链接了解
@babel/preset-typescript@babel/preset-typescripttypescript转码插件
babel-plugin-dynamic-import-nodebabel-plugin-dynamic-import-nodeimport()转require(),使用有些许不一样,可以看下文或者点击查看
@babel/plugin-transform-runtime@babel/plugin-transform-runtimeJavaScript标准库注入
@babel/plugin-proposal-decorators@babel/plugin-proposal-decoratorsES7修饰器转码器

其实需要什么功能去搜索就可以了,用法我是直接去npm搜索插件看,再不行点击上面的git地址去看,实在不清楚建议阅读源码,宗旨就是这么一个学习过程,没有捷径,不要什么都喂到嘴里,又不是所有人是你双亲,授人以鱼不如授人以渔。

4、配置

/*babel.config.json*/
{
	"comments": false,    //注释状态
	"presets": [
		[
			"@babel/preset-env", //语法转化
			{
				"targets": {
					"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
				},
				"useBuiltIns": "usage",
				"corejs": 3,
				"loose": true
			}
		],
		"@babel/preset-react",    //解析React语法,JSX
		"@babel/preset-typescript"    //解析TS
	],
	"plugins": [
		"dynamic-import-node",    //将import() 转为 require()
		"@babel/plugin-transform-runtime",    //注入兼容性方法
		[
			"@babel/plugin-proposal-decorators",    //ES7修饰器转化
			{
				"legacy": true
			}
		]
	]
}

六、Typescript(TS配置)

1、作用

为项目能使用Typescript

2、安装

yarn add typescript -D

3、说明

文件或功能解析器或插件备注
typescripttypescripttypescript核心
ts-nodets-node直接运行TS代码,看个人需求
ts-loaderts-loaderwebpack解析ts代码,推荐使用babel就不用loader了,看个人需求

4、配置

(1)初始化

tsc --init

执行命令会生成一个tsconfig.json文件,文件里面有详细的配置说明,更详细的点击配置说明

{
	"compilerOptions": {
		"module": "commonjs", //设置程序的模块系统。
		"target": "es5", //编译目标
		"jsx": "react", //控制 JSX 在 JavaScript 文件中的输出方式。
		"sourceMap": true, //调试显示原始的 TypeScript 代码。
		"removeComments": true, //移除注释
		/**
		 * TypeScript 开启严格模式 ,开启 "noImplicitAny": true,"strictNullChecks": true, "strictFunctionTypes": true,
		 * "strictBindCallApply": true,"strictPropertyInitialization": true,"noImplicitThis": true,"alwaysStrict": true
		 */
		"strict": true,
		"noImplicitAny": true, //ypeScript无法推断变量的类型时,TypeScript将返回到变量的any。
		"strictNullChecks": true, //null和undefined有各自不同的类型
		"moduleResolution": "node", //指定模块解析策略
		"baseUrl": "./", //基准目录
		"typeRoots": ["node_modules/@types"], //类型根路径
		"allowSyntheticDefaultImports": true, //允许合成默认导入
		"esModuleInterop": true, //ES 模块互操作性
		"experimentalDecorators": true //ES7类修饰器允许
	},
	"exclude": ["node_modules", "config/*"],  //忽略文件
	"include": ["src/**/*"] //包含文件
}

七、组装

1、html文件书写

新建index.html

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta http-equiv="pragma" content="no-cache" />
		<meta http-equiv="Cache-Control" content="no-store, must-revalidate" />
		<meta http-equiv="expires" content="Wed, 26 Feb 1997 08:21:57 GMT" />
		<meta
			name="viewport"
			content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"
		/>
		<title><%= htmlWebpackPlugin.options.title %></title>
	</head>
	<body>
		<div id="app_root"></div>
	</body>
</html>

2、新建源码文件夹和入口

(1)根目录下新建文件夹src (2)src下新建index.tsx (3)src下新建APP.tsx

//index.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
createRoot(document.querySelector('#app_root') as Element).render(<App />);
//APP.tsx
import React, { FC } from 'react';
const App: FC<any> = (props) => {
	return <>app</>;
};
export default App;

3、新建webpack配置文件夹和配置文件

(1)在根目录下创建Webpack文件及 (2)在Webpack文件夹下创建webpack.base.js、webpack.dev.js、webpack.prod.js (3)编写webpack配置文件 首先梳理一下 公共部分 入口,ts,js,图片,其他文件,less,html相同 dev模式 less 略微不同,devServer相关配置,代理,resove路径,优化模式 product模式 出口,优化模式, 公共部分配置

//webpack.base.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const path = require('path');
const devMode = process.env.NODE_ENV !== 'production';
const resolve = (dir) => path.resolve(__dirname, dir);

module.exports = {
	target: 'web',
	entry: resolve('../src/index.tsx'), //入口
	plugins: [
		/**
		 * html文件处理
		 */
		new HtmlWebpackPlugin({
			title: 'Wizard-RUI',
			filename: 'index.html',
			template: resolve('../index.html'),
			hash: true,
			cache: false,
			inject: true,
			minify: {
				removeComments: true,
				removeAttributeQuotes: true,
				collapseWhitespace: true,
				minifyJS: true, // 在脚本元素和事件属性中缩小JavaScript(使用UglifyJS)
				minifyCSS: true // 缩小CSS样式元素和样式属性
			},
			nodeModules: resolve('../node_modules')
		}),
		/**
		 * MiniCss插件,在生产环境使用
		 */
		!devMode
			? new MiniCssExtractPlugin({
					filename: '[name].[contenthash].css',
					chunkFilename: 'css/[id].[contenthash].css',
					ignoreOrder: true
			  })
			: function(){}
	],
	module: {
		rules: [
			/**
			 * 处理less,css 为dev模式下使用style-loader 为pod模式下使用MIniCss
			 */
			{
				test: /\.(le|c)ss$/i,
				use: [devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
			},
			/**
			 * ts,tsx,js,jsx解析
			 */
			{
				test: /\.(ts|tsx)$/,
				exclude: /(node_modules|bower_components)/,
				use: [
					{
						loader: 'babel-loader',
						options: {
							cacheDirectory: true
						}
					}
				]
			},
			/**
			 * 图片处理
			 */
			{
				test: /\.(png|svg|jpg|gif)$/, // 图片
				use: [
					{
						loader: 'file-loader',
						options: {
							name: 'assets/images/[name].[ext]' // 存放的位置: dist/assets/images/文件
						}
					}
				]
			},
			/**
			 * 字体文件处理
			 */
			{
				test: /\.(woff|woff2|eot|ttf|otf)$/, // 字体
				use: [
					{
						loader: 'file-loader',
						options: {
							name: 'assets/fonts/[name].[ext]' // 存放的位置: dist/assets/fonts/文件
						}
					}
				]
			}
		]
	}
};

开发环境配置

//webpack.dev.js
const base = require('./webpack.base'); //取出公共部分
const { merge } = require('webpack-merge');
const path = require('path');
const resolve = (dir) => path.resolve(__dirname, dir);

module.exports = merge(base, {
	mode: 'development', //开发环境webpack内置优化
	devtool: 'inline-source-map', //控制台调试代码
	devServer: {
		client: {
			progress: true //在浏览器中以百分比显示编译进度。
		},
		compress: false, //gzip压缩
		hot: true, //热更新
		open: {
			app: {
				name: 'goole-chrome', //走动打开chrome
				arguments: ['--incognito', '--new-window'] //无痕,新的窗口
			}
		},
		port: 8081, //监听端口
		proxy: {} //代理配置
	},
	optimization: {
		//优化模式
		minimize: false
	},
	/**
	 * 路径别名
	 */
	resolve: {
		alias: {
			// "@": ["../src"],
			'@': resolve('../src/'),
			src: resolve('../src/'),
			components: resolve('../src/components'),
			config: resolve('../src/config'),
			hook: resolve('../src/hook'),
			apis: resolve('../src/apis'),
			router: resolve('../src/router'),
			store: resolve('../src/store'),
			theme: resolve('../src/theme'),
			util: resolve('../src/util'),
			i18n: resolve('../src/i18n'),
			assets: resolve('../src/assets'),
			views: resolve('../src/views')
		},
		extensions: ['.tsx', '.ts', '.wasm', '.mjs', '.js', '.json']
	}
});

生产环境配置

//webpack.prod.js
const base = require('./webpack.base'); //取出公共部分
const { merge } = require('webpack-merge');
const CleanWebpackPlugin = require('clean-webpack-plugin').CleanWebpackPlugin;
const path = require('path');
const resolve = (dir) => path.resolve(__dirname, dir);

module.exports = merge(base, {
	mode: 'production', // 环境 development 和 production 环境 链接: https://www.webpackjs.com/concepts/mode/#mode-development
	output: {
		filename: 'index.js', // 文件名
		path: resolve('../dist'), // 文件输出地址
		library: {
			/**
			 * 发布运行环境
			 * umd——兼容浏览器
			 * commonjs,commonjs2,module——node
			 * amd——require.js
			 * cmd——sea.js
			 */
			type: 'umd'
		},
		clean: true
	},
	optimization: {
		//优化模式
		minimize: false
	},
	/**若通过CDN引入React和ReactDOM可以使用 */
	// externals: {
	// 	react: 'React',
	// 	'react-dom': 'ReactDOM'
	// },
	plugins: [new CleanWebpackPlugin()],
	resolve: {
		extensions: ['.js', '.jsx', '.ts', '.tsx']
	}
});

(4)配置运行命令 package.json 的script加入

{
    "dev": "webpack-dev-server --config ./webpack/webpack.dev.js",
    "build": "webpack --config ./webpack/webpack.prod.js",
    "test": "echo \"Error: no test specified\" && exit 1"
}

(5)yarn build,yarn dev 看看成功与否

附件: package.json

{
	"name": "wizard-rui",
	"version": "1.0.0",
	"description": "",
	"main": "index.js",
	"scripts": {
		"dev": "webpack-dev-server --config ./webpack/webpack.dev.js",
		"build": "webpack --config ./webpack/webpack.prod.js",
		"test": "echo \"Error: no test specified\" && exit 1"
	},
	"author": "",
	"license": "ISC",
	"devDependencies": {
		"@babel/cli": "^7.19.3",
		"@babel/core": "^7.20.2",
		"@babel/plugin-proposal-decorators": "^7.20.2",
		"@babel/plugin-transform-runtime": "^7.19.6",
		"@babel/preset-env": "^7.20.2",
		"@babel/preset-react": "^7.18.6",
		"@babel/preset-typescript": "^7.18.6",
		"@types/react": "^18.0.25",
		"@types/react-dom": "^18.0.8",
		"@typescript-eslint/eslint-plugin": "^5.42.1",
		"@typescript-eslint/parser": "^5.42.1",
		"babel-loader": "^9.1.0",
		"babel-plugin-dynamic-import-node": "^2.3.3",
		"babel-plugin-transform-runtime": "^6.23.0",
		"clean-webpack-plugin": "^4.0.0",
		"core-js": "^3.26.1",
		"css-loader": "^6.7.1",
		"file-loader": "^6.2.0",
		"html-webpack-plugin": "^5.5.0",
		"less-loader": "^11.1.0",
		"mini-css-extract-plugin": "^2.6.1",
		"prettier": "^2.7.1",
		"style-loader": "^3.3.1",
		"typescript": "^4.8.4",
		"webpack": "^5.74.0",
		"webpack-cli": "^4.10.0",
		"webpack-dev-server": "^4.11.1",
		"webpack-merge": "^5.8.0"
	},
	"dependencies": {
		"react": "^18.2.0",
		"react-dom": "^18.2.0"
	}
}

最后还是那就话,授人以鱼不如授人以渔,少抄袭,多学习少年!