轻量级从react16+webpack4版本升级react18+webpack5要干的那些事情

239 阅读3分钟

从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"
  },

很简单的轻量级项目版本升级,剩余冲突的东西一个个改吧