记一次webpack+typescript+react的优化过程

2,085 阅读2分钟

说在前头

项目采用的是react + webpack + typescript + tslint的技术栈,优化之后速度有了大幅度的提高。

优化之前的webpack配置

    module.exports = {
        ...,
        module: {
            rules : [
                {
                    test: /\.tsx?$/,
                    use: [
                        {
                            loader: 'awesome-typescript-loader',
                            options: {
                                configFileName: './tsconfig.json',
                                useCache: true,
                            }
                        }
                    ],
                },
                {
                    test: /\.tsx?$/,
                    enforce: 'pre',
                    loader: 'tslint-loader',
                    options: {
                        configFile: path.resolve(__dirname, './tslint.json'),
                        emitErrors: true,
                        failOnHint: true
                    },
                },
            ]
        }
    }

为什么想要弃用 awesome-typescript-loader呢?是因为每当文件改动时,该loader都会重新去转译和类型检查,项目慢慢大了,特别影响开发速度,并且会有类型检查遗漏的情况发生。

@babel/preset-typescript方案,直接移除了TypeScript,转为JS,这使得它的编译速度飞快。

优化之后的webpack配置

            {
                test: /\.(jsx?|tsx?)$/,
                use: ['thread-loader',  // 采用thread-loader多进程编译源文件
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-typescript'],
                            plugins: [
                                ["@babel/plugin-proposal-decorators", {
                                    legacy: true }],
                                ['@babel/plugin-transform-typescript', {
                                    allExtensions: true,
                                    isTSX: true,
                                    allowNamespaces: true }],
                            ]
                        },
                    }
                ],
            },
            {
                test: /\.tsx?$/,
                use: ['eslint-loader'], 
                // 由于去除了ts,故采用eslint来进行代码检测,同时添加ForkTsCheckerWebpackPlugin和ForkTsCheckerNotifierWebpackPlugin两个plugin单独开个进程来做lint
            },

babel.config.js(babel配置文件)

module.exports = function (api) {
    api.cache(true);

    const presets = [
        "@babel/preset-typescript",
        "@babel/preset-react",
        "@babel/preset-env",
        "mobx"
    ];
    const plugins = [
        "react-hot-loader/babel",
        "@babel/proposal-object-rest-spread",
        ["@babel/plugin-transform-runtime"],
        ["@babel/plugin-transform-modules-commonjs", { "strictMode": true }],
        ["@babel/plugin-proposal-decorators", { "legacy": true }],
        ["@babel/plugin-proposal-class-properties", { "loose": true }]
    ];

    return {
        presets,
        plugins
    };
}

.eslintrc.js (eslint配置文件)

module.exports = {
    parser:  '@typescript-eslint/parser',  //定义ESLint的解析器
    extends: [
        'plugin:react/recommended',
        'plugin:@typescript-eslint/recommended'
    ], //定义文件继承的子规范
    plugins: ['@typescript-eslint'],       //定义了该eslint文件所依赖的插件
    env:{                                  //指定代码的运行环境
        browser: true,
        node: true,
        commonjs: true,
        es6: true
    },
    settings: {                            //自动发现React的版本,从而进行规范react代码
        "react": {
            "pragma": "React",
            "version": "detect"
        }
    },
    parserOptions: {                       //指定ESLint可以解析JSX语法
        "ecmaVersion": 2019,
        "sourceType": 'module',
        "ecmaFeatures":{
            jsx:true
        }
    },
    rules: {
    }
}

需要特别指出的是,采用babel-loader之后,我们不能直接使用webpack-dev-server自带的hot模块,而是应该通过react-hot-loader来处理热更新的部分。

新增的package.json

    devDependencies: {
        "@babel/core": "^7.9.0",
        "@babel/plugin-proposal-class-properties": "^7.8.3",
        "@babel/plugin-proposal-decorators": "^7.8.3",
        "@babel/plugin-proposal-object-rest-spread": "^7.9.5",
        "@babel/plugin-transform-modules-commonjs": "^7.9.0",
        "@babel/plugin-transform-runtime": "^7.9.0",
        "@babel/plugin-transform-strict-mode": "^7.8.3", // 用来设置打包后js是否为严格模式
        "@babel/preset-env": "^7.9.5",
        "@babel/preset-react": "^7.9.4",
        "@babel/preset-typescript": "^7.9.0",
        "@typescript-eslint/eslint-plugin": "2.27.0",
        "@typescript-eslint/parser": "2.27.0",
        "babel-loader": "^8.1.0",
        "babel-plugin-transform-class-properties": "^6.24.1",
        "babel-plugin-transform-decorators-legacy": "^1.3.5",
        "babel-preset-mobx": "^2.0.0", // 项目里用到了mobx
        "eslint": "^6.8.0",
        "eslint-loader": "^4.0.0",
        "eslint-plugin-react": "^7.19.0",
        "react-hot-loader": "^4.12.20",
    },
    dependencies: {
        "@babel/runtime": "^7.9.2", // 构建时需要
    }