从react16+webpack4版本升级react18+webpack5要干的那些事情
1.用create-react-app搭建一个react18的空白项目
1.使用react18搭建空白项目,搭配craco,craco.config.js文件写配置
设置代理,默认端口等
module.exports = {
devServer: {
proxy: {
'/xx': {
target: 'xxx',
changeOrigin: true,
}
},
},
}
2.craco自带了对css,sass相关处理但是没有带less处理,需要额外下载craco-less插件来处理相关代码
plugins: [
{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
lessOptions: {
modifyVars: {
'@primary-color': '#1DA57A',
'@link-color': '#1DA57A',
'@border-radius-base': '4px'
},
javascriptEnabled: true
}
}
}
}
],
3.设置别名,安装相应的东西,废弃url-loader file-loader ,Webpack 5不再默认包含Node.js核心模块的polyfills
module.exports = {
webpack: {
configure: (webpackConfig, { env, paths }) => {
paths.appBuild = 'dist.app/prod';
webpackConfig.output = {
...webpackConfig.output,
path: path.resolve(__dirname, 'dist.app/prod'),
publicPath: './'
};
webpackConfig.resolve = {
...webpackConfig.resolve,
fallback: {
...webpackConfig.resolve.fallback,
path: require.resolve('path-browserify'),
fs: false,
os: require.resolve('os-browserify/browser'),
crypto: require.resolve('crypto-browserify'),
buffer: require.resolve('buffer'),
stream: require.resolve('stream-browserify'),
vm: require.resolve('vm-browserify')
}
};
webpackConfig.module.rules.push({
test: /.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
});
return webpackConfig;
},
alias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
'@utils': path.resolve(__dirname, 'src/utils'),
'@assets': path.resolve(__dirname, 'src/assets'),
'@styles': path.resolve(__dirname, 'src/styles'),
'@services': path.resolve(__dirname, 'src/services')
}
},
plugins: [
{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
lessOptions: {
modifyVars: {
'@primary-color': '#1DA57A',
'@link-color': '#1DA57A',
'@border-radius-base': '4px'
},
javascriptEnabled: true
}
}
}
}
],
devServer: {
proxy: {
'/xx': {
target: 'http://xx',
changeOrigin: true
}
},
}
};
将原版本的代码移入
react-router-dom从v5->v6
1.变动的东西
1、Switch 单一匹配 变为Routes
2.Redirect 组件取消 变为 Navigate
3.useNavigate替代了useHistory
4.v6移出了WithRouter
5.component / render 变为 element
@babel/eslint-parser替代babel-eslint
.eslintrc.js
module.exports = {
parser: '@babel/eslint-parser',
parserOptions: {
sourceType: 'module',
experimentalDecorators: true,
allowImportExportEverywhere: true,
ecmaFeatures: {
legacyDecorators: true
}
},
extends: ['react-app', 'prettier'],
env: {
browser: true,
node: true
},
rules: {
'react-hooks/rules-of-hooks': 'error', // 检查 Hook 的规则
'react-hooks/exhaustive-deps': 'off', // 检查 effect 的依赖
// "indent": ["error",2], //缩进默认为2
eqeqeq: 0, // === ==的问题,老项目要慎重
'no-console': 0,
'no-var': 0,
'no-empty': 0,
'comma-dangle': 0,
'no-const-assign': 'error',
'no-dupe-class-members': 'error',
'no-dupe-args': 'error',
'no-dupe-keys': 'error',
'no-self-assign': 'error',
'no-self-compare': 'error',
'no-sequences': 'error',
quotes: 0,
'no-extra-parens': ['error', 'functions'],
'no-use-before-define': [
'error',
{
functions: false,
classes: false,
variables: false
}
],
'no-extra-semi': 'error',
'no-empty-pattern': 'error',
'comma-spacing': [
'error',
{
before: false,
after: true
}
],
'no-await-in-loop': 'off',
'for-direction': 'error',
'no-sparse-arrays': 'error',
'no-debugger': 'error',
'no-unexpected-multiline': 'error',
'no-unreachable': 'error',
'no-unsafe-finally': 'error',
'no-unsafe-negation': 'error',
'use-isnan': 'error',
'no-alert': 'error',
'no-fallthrough': 'error',
'no-implied-eval': 'error',
'no-loop-func': 0,
'no-redeclare': 'error',
'no-return-await': 'error',
'no-unmodified-loop-condition': 'error',
'jsx-a11y/anchor-is-valid': 'off',
'react/jsx-no-target-blank': 'off',
'no-unused-expressions': [
'error',
{
allowShortCircuit: true,
allowTernary: true,
allowTaggedTemplates: true
}
],
'vars-on-top': 'off',
'array-callback-return': 'error',
'no-unused-vars': 'off',
// "compat/compat": "warn",
// "promise/param-names": "error",
// "promise/always-return": "error",
// "promise/catch-or-return": "error",
'react/sort-comp': [
'warn',
{
order: [
'type-annotations',
'static-methods',
'lifecycle',
'everything-else',
'render'
]
}
],
'react/jsx-no-bind': 'off',
'react/jsx-filename-extension': [
'warn',
{
extensions: ['.js', '.jsx']
}
],
'react/prefer-stateless-function': 'warn'
},
plugins: [
'react-hooks',
'import',
// "promise",
// "compat",
'react',
'prettier'
]
};
配置antd 按需加载和其他的,安装babel-plugin-import
.babelrc
{
"plugins": [
[
"import",
{
"libraryName": "antd",
"libraryDirectory": "es",
},
"antd"
]
]
}
src/index.js写法改变,路由相关写法也细微改变了
// 获取根节点
const container = document.getElementById('root');
// 使用 React 18 的 createRoot API
const root = createRoot(container);
// 渲染根组件
root.render(<RootComp />);
// 注册 Service Worker
registerServiceWorker();
import React, { memo, useState } from 'react';
import useStores from '@/stores';
import { useObserver } from 'mobx-react-lite';
import { toJS } from 'mobx';
import { Route, Routes, Redirect } from 'react-router-dom';
import { getFirstNode } from '@/utils/commons/routerTool';
import routerConfig from '@/config/routerConfig';
const getRoutes = () => {
let roteList = [];
const getRoute = list => {
list.forEach((child, index) => {
if (child.routes) {
getRoute(child.routes);
} else {
let myRoute = (
<Route
key={child.id}
path={child.path}
element={<child.component />} //注意
exact
/>
);
roteList.push(myRoute);
}
});
};
getRoute(routerConfig);
return roteList;
};
const ManagerRoute = memo(props => {
return useObserver(() => {
return <Routes>{getRoutes()}</Routes>;
});
});
export default ManagerRoute;
"dependencies": {
"@ant-design/icons": "^5.5.2",
"@babel/eslint-parser": "^7.25.9",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/preset-env": "^7.26.0",
"@babel/preset-react": "^7.26.3",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.1.0",
"@testing-library/user-event": "^14.5.2",
"@typescript-eslint/eslint-plugin": "^8.19.0",
"@typescript-eslint/parser": "^8.19.0",
"antd": "5.1.6",
"antd-mobile": "^5.38.1",
"antd-mobile-v2": "^2.3.4",
"autoprefixer": "^10.4.20",
"axios": "^1.7.9",
"babel-eslint": "^10.1.0",
"babel-plugin-import": "^1.13.8",
"babel-plugin-named-asset-import": "^0.3.8",
"babel-plugin-transform-decorators-legacy": "^1.3.5",
"babel-polyfill": "^6.26.0",
"babel-preset-react-app": "^10.0.1",
"buffer": "^6.0.3",
"camelcase": "^8.0.0",
"case-sensitive-paths-webpack-plugin": "^2.4.0",
"cra-template": "1.2.0",
"craco-less": "^2.1.0-alpha.0",
"crypto-browserify": "^3.12.1",
"crypto-js": "^4.2.0",
"css-loader": "6.7.2",
"dayjs": "^1.11.13",
"dotenv": "^16.4.7",
"dotenv-expand": "^12.0.1",
"echarts": "^5.4.2",
"echarts-for-react": "^3.0.2",
"eslint": "^8.35.0",
"eslint-config-prettier": "^8.6.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.37.3",
"fs": "^0.0.1-security",
"fs-extra": "^11.2.0",
"history": "^5.3.0",
"html-webpack-plugin": "^5.6.3",
"http-proxy-middleware": "^3.0.3",
"identity-obj-proxy": "^3.0.0",
"less": "4.1.3",
"less-loader": "11.1.0",
"lodash": "^4.17.21",
"mini-css-extract-plugin": "^2.9.2",
"mobx": "^6.13.5",
"mobx-react": "^9.2.0",
"mobx-react-lite": "^4.1.0",
"moment": "^2.30.1",
"optimize-css-assets-webpack-plugin": "^6.0.1",
"os-browserify": "^0.3.0",
"path-browserify": "^1.0.1",
"postcss": "8.4.18",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-loader": "7.0.2",
"postcss-normalize": "^13.0.1",
"postcss-preset-env": "^10.1.3",
"postcss-safe-parser": "^7.0.1",
"prettier": "^2.8.4",
"prop-types": "^15.8.1",
"react": "^18.3.1",
"react-animated-css": "^1.2.1",
"react-app-polyfill": "^3.0.0",
"react-beautiful-dnd": "^13.1.1",
"react-color": "^2.19.3",
"react-dev-utils": "^12.0.1",
"react-dom": "18.0.0",
"react-loadable": "^5.5.0",
"react-router-dom": "^6.28.0",
"react-scripts": "5.0.1",
"react-vant": "^3.3.5",
"sass-loader": "13.1.0",
"stream-browserify": "^3.0.0",
"strip-pragma-loader": "^1.0.1",
"terser-webpack-plugin": "^5.3.11",
"ts-pnp": "^1.2.0",
"vm-browserify": "^1.1.2",
"workbox-webpack-plugin": "^7.3.0"
},
很简单的轻量级项目版本升级,剩余冲突的东西一个个改吧