前言
create-react-app
太过笨重了,自己手动搭建一个脚手架。本篇介绍开发环境的搭建。
需要实现如下功能:
- 能执行
react
代码 - 能在不引入
React
的情况下解析JSX
- 使用
webpack
打包 - 能启动开发服务
- 能实现
HMR
- 能生成
Html
模板 - 能处理
css
和less
,并实现样式兼容 - 能解析
js
代码 - 能实现代码自动检查
- 够快
下面就来一一实现。
准备
创建一个custom_react
文件夹,作为根目录。
创建文件.gitignore
,
mode_modules
初始化生成package.json
npm init -y
根目录下创建src
文件夹,分别写入如下文件:
// index.js
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
const root = createRoot(document.getElementById("root"));
root.render(
<StrictMode>
<App />
</StrictMode>
);
// App.jsx
import { useState } from 'react';
import './app.less';
const App = () => {
const [count, setCount] = useState(0);
const [val, setVal] = useState('');
return (
<>
<h3>Hello React18 !</h3>
<button className='btn'
onClick={() => {setCount(count + 1)}}
>click me {count} times.</button>
<div className='flex_box'>
<input type="text" value={val} onChange={e=> {setVal(e.target.value)}} />
</div>
</>
)
}
export default App;
/* app.less */
.btn {
margin-top: 30px;
}
.flex_box {
display: flex;
width: 300px;
height: 300px;
box-sizing: border-box;
border: 2px solid pink;
border-radius: 10px;
justify-content: center;
align-items: center;
margin-top: 20px;
}
根目录下创建public
文件夹,并写入如下文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React App</title>
</head>
<body>
<noscript>
You need to enable javascript to run this app.
</noscript>
<div id="root"></div>
</body>
</html>
实现
下面来一步步实现需求。
第一个,能执行react
代码
安装
npm i react react-dom -D
第三个,使用webpack
打包
安装
npm i webpack webpack-cli -D
第四个,能启动开发服务
安装
npm i webpack-dev-server -D
下面是对接下来功能实现中需要用到的插件/库的安装和介绍:
// 实现HMR
npm i @pmmmwh/react-refresh-webpack-plugin react-refresh -D
// 生成html模板
npm i html-webpack-plugin -D
// 处理css
npm i style-loader css-loader -D
// css兼容
npm i postcss postcss-loader postcss-preset-env -D
// 处理less
npm i less less-loader -D
// babel相关
// babel的核心库
npm i @babel/core -D
// babel环境预设
npm i @babel/preset-dev -D
// 辅助函数核心库
npm i core-js -D
// react预设
npm i @babel/preset-react -D
// 辅助函数运行时转换插件
npm i @babel/plugin-transform-runtime -D
npm i @babel/runtime
npm i @babel/runtime-corejs3 -D
// eslint代码检查
npm i eslint eslint-webpack-plugin -D
// 初始化生成eslint配置文件
npx eslint --init
配置介绍
babel.config.js
module.exports = {
presets: [
[
"@babel/preset-env", // 环境预设
{
useBuiltIns: "usage", // 只打包用到的辅助函数
corejs: { // 辅助函数核心库
version: "^3.29.1", // core-js的版本号
proposals: true
}
}
],
[
"@babel/preset-react", // react预设
{
// runtime配置非常重要
// 设置为automatic会自动解析jsx代码的引入
// 配置后就会自动运行jsx-runtime,无需手动引入React了
runtime: "automatic"
}
]
],
plugins: [
[
"@babel/plugin-transform-runtime",
{
corejs: 3, // @babel/runtime-corejs3的版本号
version: "^7.21.0" // @babel/runtime的版本号
}
]
]
}
postcss.config.js
module.exports = {
plugins: [
"postcss-preset-env" // postcss预设,会自动补充css前缀等
]
}
webpack.dev.js
const path = require("path");
const ReactRefreshPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const EslintWebpackPlugin = require("eslint-webpack-plugin");
const cssRules = /\.css$/; // 匹配css
const lessRules = /\.less$/; // 匹配less
// 抽取公共部分
const getStyleOptions = (importLoaders, loader) => {
return [
"style-loader",
{
loader: "css-loader",
options: {
importLoaders
}
},
"postcss-loader",
loader
].filter(Boolean);
}
module.exports = {
// 开发环境
mode: "development",
// 入口
entry: "./src/index.js",
// 配置loader
module: {
rules: [
{
// oneOf可以提供精准解析
oneOf: [
{
test: cssRules,
use: getStyleOptions(1)
},
{
test: lessRules,
use: getStyleOptions(2, "less-loader")
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
// 开启缓存
cacheDirectory: true,
// 关闭压缩
cacheCompression: false
}
}
}
]
}
]
},
plugins: [
// 生成html模板
new HtmlWebpackPlugin({
// 以index.html文件为模板
template: path.resolve(__dirname, "public/index.html")
}),
// 开启HMR功能
new ReactRefreshPlugin(),
// 开启eslint检查
new EslintWebpackPlugin({
// 检查jsx js json文件
extensions: ["jsx", "js", "json"],
// 只对修改内容的文件做检查
lintDirtyModulesOnly: true,
// 开启多线程
threads: true
})
],
// 开启source-map,精准定位错误代码
devtool: "cheap-module-source-map",
// 开启开发服务器
// hot: true是默认的,无需重复配置
devServer: {
// 启动端口号为3001
port: 3001,
// 启动服务后自动打开浏览器
open: true
},
resolve: {
// 扩展文件名,引入时不需要写后缀
extensions: [".jsx", ".js", ".json"]
}
}
.eslintrc.js
module.exports = {
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
// 配置jsx-runtime后,不引入React也不会报错了
"plugin:react/jsx-runtime"
],
"overrides": [
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
}
}
在package.json
中添加启动项
"start": "webpack serve --config ./webpack.dev.js"
测试
根目录下打开终端,执行npm start
启动后就可以看到
在App.jsx
文件中,把Hello React18
改为Hello React
,然后在控制台打印666
,按钮再点击几下,输入框里输入内容,保存文件,可以看到
修改的内容变化了,点击按钮的次数和输入框的内容都还在,控制台打印内容还在,控制台中也显示出了[HMR]...
修改文件的提示,.less
样式显示正常,说明我们的配置没问题,HMR
也实现了。
开源
https://gitee.com/guozia007/custom_react