美文网首页
快来跟我一起学 React(Day4)

快来跟我一起学 React(Day4)

作者: vv_小虫虫 | 来源:发表于2021-03-20 12:37 被阅读0次

    简介

    上一节我们从 0 开始搭建了一个项目,完成了入口与出口的配置、ts 语法支持、react 基本库的安装、css 样式配置等工作,我们继续上一节的内容。

    知识点

    • Eslint(代码质量校验)
    • eslint-webpack-plugin(Eslint webpack 插件)
    • eslint-config-react-app(React 官方 eslint 配置)
    • fork-ts-checker-webpack-plugin(ts 语法校验插件)
    • Optimization(分包优化等)

    准备

    上一节所有的内容在 dev 分支:https://gitee.com/vv_bug/cus-react-demo/tree/dev,我们重新切一个新分支 dev-v1.0.0

    我们安装好依赖,并且用 npm start 命令启动项目:

    npm install --registry https://registry.npm.taobao.org && npm start
    
    1-1.png

    可以看到,浏览器自动打开了我们项目入口,并且在页面正常显示了 ”hello react111“ ,到这,我们的准备工作算是完成了。

    Eslint

    ESLint 是在 ECMAScript/JavaScript 代码中识别和报告模式匹配的工具,它的目标是保证代码的一致性和避免错误。

    接下来我们来安装一下 ESLint 相关依赖:

    安装 ESLint

    Eslint 核心 API。

    在工程目录 cus-react-demo 下执行以下命令安装:

    npm install -D eslint --registry https://registry.npm.taobao.org
    

    安装 eslint-webpack-plugin

    Eslint 在 Webpack 中的插件。

    在工程目录 cus-react-demo 下执行以下命令安装:

    npm install -D eslint-webpack-plugin --registry https://registry.npm.taobao.org
    

    安装 eslint-config-react-app

    React 官方提供的 Eslint 配置。

    在工程目录 cus-react-demo 下执行以下命令安装:

    npm install -D eslint-config-react-app --registry https://registry.npm.taobao.org
    

    安装 @typescript-eslint/eslint-plugin

    ESLint 中的 ts 插件。

    在工程目录 cus-react-demo 下执行以下命令安装:

    npm install -D @typescript-eslint/eslint-plugin --registry https://registry.npm.taobao.org
    

    安装 @typescript-eslint/parser

    ESLint 中的 ts 语法解析器。

    在工程目录 cus-react-demo 下执行以下命令安装:

    npm install -D @typescript-eslint/parser --registry https://registry.npm.taobao.org
    

    安装 typescript

    ts 语法核心库。

    在工程目录 cus-react-demo 下执行以下命令安装:

    npm install -D typescript --registry https://registry.npm.taobao.org
    

    安装 eslint-plugin-import

    Eslint 中对 EsModule 导入导出的规范插件。

    在工程目录 cus-react-demo 下执行以下命令安装:

    npm install -D eslint-plugin-import --registry https://registry.npm.taobao.org
    

    安装 eslint-plugin-flowtype

    Eslint 中对 flow 语法规范插件。

    在工程目录 cus-react-demo 下执行以下命令安装:

    npm install -D eslint-plugin-flowtype --registry https://registry.npm.taobao.org
    

    安装 eslint-plugin-jsx-a11y

    安装 eslint-plugin-react-hooks

    安装 eslint-plugin-react

    安装 babel-eslint

    在工程目录 cus-react-demo 下执行以下命令安装:

    npm install -D eslint-plugin-jsx-a11y eslint-plugin-react-hooks  eslint-plugin-react babel-eslint --registry https://registry.npm.taobao.org
    

    总算是安装完毕了,其实这些都是 React 官方要求的一些 Eslint 插件,都是在 eslint-config-react-app 中定义要求的,每一个具体什么功能我就不一一分析了,小伙伴自己去官网查看哦,童鞋们平时也不需要刻意去记这些东西,直接 copy 然后安装即可,ESLint 依赖我们是安装完毕了,下面我们来给项目配置一下 ESLint。

    首先找到 webpack 配置文件 webpack.config.js,然后添加 eslint-webpack-plugin

    const path = require('path');
    const config = new (require('webpack-chain'))();
    const isDev = process.env.NODE_ENV === 'development'; // 判断是否是开发环境
    config
        .target('web')
        .context(path.resolve(__dirname, '.')) // webpack 上下文目录为项目根目录
        .entry('app') // 入口文件名称为 app
            .add('./src/main.tsx') // 入口文件为 ./src/main.tsx
            .end()
        .output
            .path(path.join(__dirname, './dist')) // webpack 输出的目录为根目录的 dist 目录
            .filename(isDev ? '[name].[hash:8].js' : '[name].[contenthash:8].js') // 打包出来的 bundle 名称为 "[name].[contenthash:8].js"
            .publicPath('/') // publicpath 配置为 "/"
            .end()
        .resolve
            .extensions.add('.js').add('.jsx').add('.ts').add('.tsx').end() // 添加后缀自动解析
            .end()
        .module
            .rule('ts') // 配置 typescript
                .test(/\.(js|mjs|jsx|ts|tsx)$/)
                .exclude
                    .add(filepath => {
                        // Don't transpile node_modules
                        return /node_modules/.test(filepath)
                    })
                    .end()
                .use('babel-loader')
                    .loader('babel-loader')
                    .end()
                .end()
            .rule('sass') // sass-loader 相关配置
                .test(/\.(sass|scss)$/) // Sass 和 Scss 文件
                .use('extract-loader') // 提取 css 样式到单独 css 文件
                    .loader(require('mini-css-extract-plugin').loader)
                    .end()
                .use('css-loader') // 加载 css 模块
                    .loader('css-loader')
                    .end()
                .use('postcss-loader') // 处理 css 样式
                    .loader('postcss-loader')
                    .end()
                .use('sass-loader') // Sass 语法转 css 语法
                    .loader('sass-loader')
                    .end()
                .end()
            .end()
        .plugin('extract-css') // 提取 css 样式到单独 css 文件
            .use(require('mini-css-extract-plugin'), [
                {
                    filename: isDev ? 'css/[name].css': 'css/[name].[contenthash].css',
                    chunkFilename: isDev ? 'css/[id].css': 'css/[name].[contenthash].css',
                },
            ])
            .end()
        .plugin('html') // 添加 html-webpack-plugin 插件
            .use(require('html-webpack-plugin'), [
                {
                    template: path.resolve(__dirname, './public/index.html'), // 指定模版文件
                    chunks: ['app'], // 指定需要加载的 chunk
                    inject: 'body', // 指定 script 脚本注入的位置为 body
                },
            ])
            .end()
        .plugin('eslint') // 添加 eslint-webpack-plugin 插件
            .use(require('eslint-webpack-plugin'), [
                {
                    // Plugin options
                    extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
                    eslintPath: require.resolve('eslint'),
                    failOnError: !isDev,
                    context: path.resolve(__dirname, "./src"),
                    // ESLint class options
                    cwd: __dirname,
                    resolvePluginsRelativeTo: __dirname,
                }
            ])
            .end()
        .devServer
            .host('0.0.0.0') // 服务器外部可访问
            .disableHostCheck(true) // 关闭白名单校验
            .contentBase(path.resolve(__dirname, './public')) // 设置一个 express 静态目录
            .historyApiFallback({
                disableDotRule: true, // 禁止在链接中使用 "." 符号
                rewrites: [
                    { from: /^\/$/, to: '/index.html' }, // 将所有的 404 响应重定向到 index.html 页面
                ],
            })
            .port(8080) // 当前端口号
            .hot(true) // 打开页面热载功能
            .sockPort('location') // 设置成平台自己的端口
            .open(true)
    module.exports = config.toConfig();
    

    如果要让 eslint 起作用的话,我们还需要给 eslint 添加一个配置文件 .eslintrc.js

    我们在工程目录 cus-react-demo 下创建一个 .eslintrc.js 文件:

    touch .eslintrc.js
    

    然后写入以下代码到 .eslintrc.js 文件:

    module.exports = {
        env: {
            node: true, // 添加 node 环境
        },
        extends: [
            "react-app", // 继承 react-app 配置
            "react-app/jest" // 继承 react-app/jest 配置
        ],
        rules: {
            // 自定义规则
            semi: [
                // 代码结尾必须使用 “;“ 符号
                'error',
                'always',
            ],
            quotes: [
                // 代码中字符串必须使用 ”” 符号
                'error',
                'double',
            ],
            'no-console': 'error', // 代码中不允许出现 console
        },
    };
    

    其实我们需要的只是对 src 目录底下的所有文件做代码质量校验,其它的文件是不需要的。所以我们在工程目录 cus-react-demo 下再创建一个 .eslintignore 文件,列出那些不需要校验的文件列表:

    touch .eslintignore
    

    然后写入以下内容到 .eslintignore 文件:

    node_modules/*
    public/*
    dist/*
    webpack.config.js
    .eslintrc.js
    

    ok!万事都已俱备。

    然后我们重新运行项目:

    npm start
    
    1-2.png

    可以看到,终端中报了一些警告,我们尝试修复一下这些警告。

    为了方便,我们在 package.json 文件中声明一个 lint 脚本:

    {
      "name": "cus-react-demo",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "rimraf dist && cross-env NODE_ENV=production webpack --mode=production",
        "start": "cross-env NODE_ENV=development webpack serve --mode=development --progress",
        "lint": "eslint  --ext .js,.mjs,.jsx,.ts,.tsx --fix ./src"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "@typescript-eslint/eslint-plugin": "^4.18.0",
        "@typescript-eslint/parser": "^4.18.0",
        "@webpack-cli/serve": "^1.3.0",
        "autoprefixer": "^9.8.6",
        "babel-eslint": "^10.1.0",
        "babel-loader": "^8.2.2",
        "babel-preset-react-app": "^10.0.0",
        "cross-env": "^7.0.3",
        "css-loader": "^5.1.3",
        "cssnano": "^4.1.10",
        "eslint": "^7.22.0",
        "eslint-config-react-app": "^6.0.0",
        "eslint-plugin-flowtype": "^5.4.0",
        "eslint-plugin-import": "^2.22.1",
        "eslint-plugin-jsx-a11y": "^6.4.1",
        "eslint-plugin-react": "^7.22.0",
        "eslint-plugin-react-hooks": "^4.2.0",
        "eslint-webpack-plugin": "^2.5.2",
        "html-webpack-plugin": "^5.3.1",
        "mini-css-extract-plugin": "^1.3.9",
        "postcss-loader": "^5.2.0",
        "sass": "^1.32.8",
        "sass-loader": "^11.0.1",
        "typescript": "^4.2.3",
        "webpack": "^5.26.3",
        "webpack-chain": "^6.5.1",
        "webpack-cli": "^4.5.0",
        "webpack-dev-server": "^3.11.2"
      },
      "dependencies": {
        "@types/react": "^17.0.3",
        "@types/react-dom": "^17.0.2",
        "react": "^17.0.1",
        "react-dom": "^17.0.1"
      }
    }
    

    然后我们在工程目录 cus-react-demo 执行 npm run lint 脚本去修复当前项目代码:

    npm run lint
    

    运行过后,ESLint 会自动帮我们修复掉了一些格式方面的问题。

    从这里也可以看出,ESLint 不但可以发现我们代码中的一些问题,还能自动帮我们解决大部分语法、格式等问题。但也很多小伙伴是很反感 ESLint 的,因为他们觉得有了 ESLint 后,代码变得难写多了,但我想说的是 “真的代码难写了?还是你写出来的代码本来就问题呢?”。

    ok!警告解决完毕后,我们再次执行 npm start 的时候就会发现,没有错误和警告信息了:

    npm start
    
    1-4.png

    一般我们在平时开发中,为了更好的显示代码规范错误信息,我们直接利用 webpack.devServeroverlay 选项将 webpack 的报错跟警告显示到页面中去,所以我们修改一下 webpack.config.js 文件:

    ...
    .devServer
            .host("0.0.0.0") // 为了让外部服务访问
            .port(8090) // 当前端口号
            .hot(true) // 热载
            .open(true) // 开启页面
            .overlay({
                warnings: true,
                errors: true
            }) // webpack 错误和警告信息显示到页面
    ...
    

    比如我们现在项目中有代码不符合我们的代码规范:

    1-5.png

    可以看到,页面中提示了 ”编译失败“,IDE 提示了 “语句结尾需要添加分号”,终端中照样提示了 “语句结尾需要添加分号”,这样就很好的保持了项目代码风格的一致性,在团队合作中还是很有必要的。

    fork-ts-checker-webpack-plugin

    校验 ts 语法,检测 ts 语法中的一些报错并且通过 webpack 在终端中打印出来。

    我们首先在工程目录 cus-react-demo 下执行以下命令进行安装:

    npm install -D fork-ts-checker-webpack-plugin --registry https://registry.npm.taobao.org
    

    安装完毕后,我们在 webpack.config.js 中将其引入:

    .plugin('fork-ts-checker') // 配置 fork-ts-checker
            .use(require('fork-ts-checker-webpack-plugin'), [{
                eslint: {
                    files: './src/**/*.{ts,tsx,js,jsx}' // required - same as command `eslint ./src/**/*.{ts,tsx,js,jsx} --ext .ts,.tsx,.js,.jsx`
                },
                typescript: {
                    extensions: {
                        vue: {
                            enabled: true,
                            compiler: "vue-template-compiler"
                        },
                    }
                }
            }])
    

    webpack.config.js 全部配置:

    const path = require('path');
    const config = new (require('webpack-chain'))();
    const isDev = process.env.NODE_ENV === 'development'; // 判断是否是开发环境
    config
        .target('web')
        .context(path.resolve(__dirname, '.')) // webpack 上下文目录为项目根目录
        .entry('app') // 入口文件名称为 app
            .add('./src/main.tsx') // 入口文件为 ./src/main.tsx
            .end()
        .output
            .path(path.join(__dirname, './dist')) // webpack 输出的目录为根目录的 dist 目录
            .filename(isDev ? '[name].[hash:8].js' : '[name].[contenthash:8].js') // 打包出来的 bundle 名称为 "[name].[contenthash:8].js"
            .publicPath('/') // publicpath 配置为 "/"
            .end()
        .resolve
            .extensions.add('.js').add('.jsx').add('.ts').add('.tsx').end() // 添加后缀自动解析
            .end()
        .module
            .rule('ts') // 配置 typescript
                .test(/\.(js|mjs|jsx|ts|tsx)$/)
                .exclude
                    .add(filepath => {
                        // Don't transpile node_modules
                        return /node_modules/.test(filepath)
                    })
                    .end()
                .use('babel-loader')
                    .loader('babel-loader')
                    .end()
                .end()
            .rule('sass') // sass-loader 相关配置
                .test(/\.(sass|scss)$/) // Sass 和 Scss 文件
                .use('extract-loader') // 提取 css 样式到单独 css 文件
                    .loader(require('mini-css-extract-plugin').loader)
                    .end()
                .use('css-loader') // 加载 css 模块
                    .loader('css-loader')
                    .end()
                .use('postcss-loader') // 处理 css 样式
                    .loader('postcss-loader')
                    .end()
                .use('sass-loader') // Sass 语法转 css 语法
                    .loader('sass-loader')
                    .end()
                .end()
            .end()
        .plugin('extract-css') // 提取 css 样式到单独 css 文件
            .use(require('mini-css-extract-plugin'), [
                {
                    filename: isDev ? 'css/[name].css': 'css/[name].[contenthash].css',
                    chunkFilename: isDev ? 'css/[id].css': 'css/[name].[contenthash].css',
                },
            ])
            .end()
        .plugin('html') // 添加 html-webpack-plugin 插件
            .use(require('html-webpack-plugin'), [
                {
                    template: path.resolve(__dirname, './public/index.html'), // 指定模版文件
                    chunks: ['app'], // 指定需要加载的 chunk
                    inject: 'body', // 指定 script 脚本注入的位置为 body
                },
            ])
            .end()
        .plugin('eslint') // 添加 eslint-webpack-plugin 插件
            .use(require('eslint-webpack-plugin'), [
                {
                    // Plugin options
                    extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
                    eslintPath: require.resolve('eslint'),
                    failOnError: !isDev,
                    context: path.resolve(__dirname, "./src"),
                    // ESLint class options
                    cwd: __dirname,
                    resolvePluginsRelativeTo: __dirname,
                }
            ])
            .end()
        .plugin('fork-ts-checker') // 配置 fork-ts-checker
            .use(require('fork-ts-checker-webpack-plugin'), [{
                eslint: {
                    files: './src/**/*.{ts,tsx,js,jsx}' // required - same as command `eslint ./src/**/*.{ts,tsx,js,jsx} --ext .ts,.tsx,.js,.jsx`
                },
                typescript: {
                    extensions: {
                        vue: {
                            enabled: true,
                            compiler: "vue-template-compiler"
                        },
                    }
                }
            }])
            .end()
        .devServer
            .host('0.0.0.0') // 服务器外部可访问
            .disableHostCheck(true) // 关闭白名单校验
            .contentBase(path.resolve(__dirname, './public')) // 设置一个 express 静态目录
            .historyApiFallback({
                disableDotRule: true, // 禁止在链接中使用 "." 符号
                rewrites: [
                    { from: /^\/$/, to: '/index.html' }, // 将所有的 404 响应重定向到 index.html 页面
                ],
            })
            .port(8080) // 当前端口号
            .hot(true) // 打开页面热载功能
            .sockPort('location') // 设置成平台自己的端口
            .open(true) // 开启页面
            .overlay({
                warnings: true,
                errors: true
            }) // webpack 错误和警告信息显示到页面
    module.exports = config.toConfig();
    

    我们来测试一下,我们在 src/main.tsx 文件中添加一些错误的 ts 语法:

    1-6.png

    可以看到,我们对一个 string 类型的 a 赋值为 number

    首先 IDE 直接报错了,说我们不能对一个string 类型的变量赋值 number 类型。

    接下来我们运行一下项目,看 webpack 会不会编译通过:

    npm start
    
    1-7.png

    可以看到,还是三个地方提示我们报错了,所以很好的避免了 ts 语法的报错。

    Optimization

    minimizer

    将生产环境的代码进行压缩,并且去掉代码中的注释:

    //----- optimization start-----
    config.when(
      !isDev,
      () => {
        // 生成环境的时候
        config.optimization
          .minimize(true) // 打开压缩代码开关
          .minimizer('terser')
          .use(require('terser-webpack-plugin'), [
            {
              extractComments: false, // 去除注释
              terserOptions: {
                output: {
                  comments: false, // 去除注释
                },
              },
            },
          ]);
      },
      () => {
        // 开发环境的时候
      }
    );
    //----- optimization end-------
    

    Devtool

    开发环境的时候将 devtool 改成 cheap-module-source-map 加快速度:

    //----- optimization start-----
    config.when(
      !isDev,
      () => {
        // 生成环境的时候
        config.optimization
          .minimize(true) // 打开压缩代码开关
          .minimizer('terser')
          .use(require('terser-webpack-plugin'), [
            {
              extractComments: false, // 去除注释
              terserOptions: {
                output: {
                  comments: false, // 去除注释
                },
              },
            },
          ]);
      },
      () => {
        // 开发环境的时候
        config.devtool('cheap-module-source-map');
      }
    );
    //----- optimization end-------
    

    分包机制

    1. node_modules 目录下所有的依赖都打包到 chunk-vendor.js 文件,优先级最高。
    2. 将重复次数 >=2 的依赖打包到 chunk-common.js 文件。
    3. webpack runtime 代码从每个 chunk 中抽离,单独打包到 runtime.js 文件。
    config.optimization
      .splitChunks({
        cacheGroups: {
          vendors: {
            // 分离入口文件引用 node_modules 的 module(vue、@babel/xxx)
            name: `chunk-vendors`,
            test: /[\\/]node_modules[\\/]/,
            priority: -10,
            chunks: 'initial',
          },
          common: {
            // 分离入口文件引用次数 >=2 的 module
            name: `chunk-common`,
            minChunks: 2,
            priority: -20,
            chunks: 'initial',
            reuseExistingChunk: true,
          },
        },
      })
      .runtimeChunk('single'); // 分离 webpack 的一些帮助函数,比如 webpackJSONP 等等
    

    webpack.config.js 所有配置内容:

    const path = require('path');
    const config = new (require('webpack-chain'))();
    const isDev = process.env.NODE_ENV === 'development'; // 判断是否是开发环境
    config
        .target('web')
        .context(path.resolve(__dirname, '.')) // webpack 上下文目录为项目根目录
        .entry('app') // 入口文件名称为 app
            .add('./src/main.tsx') // 入口文件为 ./src/main.tsx
            .end()
        .output
            .path(path.join(__dirname, './dist')) // webpack 输出的目录为根目录的 dist 目录
            .filename(isDev ? '[name].[hash:8].js' : '[name].[contenthash:8].js') // 打包出来的 bundle 名称为 "[name].[contenthash:8].js"
            .publicPath('/') // publicpath 配置为 "/"
            .end()
        .resolve
            .extensions.add('.js').add('.jsx').add('.ts').add('.tsx').end() // 添加后缀自动解析
            .end()
        .module
            .rule('ts') // 配置 typescript
                .test(/\.(js|mjs|jsx|ts|tsx)$/)
                .exclude
                    .add(filepath => {
                        // Don't transpile node_modules
                        return /node_modules/.test(filepath)
                    })
                    .end()
                .use('babel-loader')
                    .loader('babel-loader')
                    .end()
                .end()
            .rule('sass') // sass-loader 相关配置
                .test(/\.(sass|scss)$/) // Sass 和 Scss 文件
                .use('extract-loader') // 提取 css 样式到单独 css 文件
                    .loader(require('mini-css-extract-plugin').loader)
                    .end()
                .use('css-loader') // 加载 css 模块
                    .loader('css-loader')
                    .end()
                .use('postcss-loader') // 处理 css 样式
                    .loader('postcss-loader')
                    .end()
                .use('sass-loader') // Sass 语法转 css 语法
                    .loader('sass-loader')
                    .end()
                .end()
            .end()
        .plugin('extract-css') // 提取 css 样式到单独 css 文件
            .use(require('mini-css-extract-plugin'), [
                {
                    filename: isDev ? 'css/[name].css': 'css/[name].[contenthash].css',
                    chunkFilename: isDev ? 'css/[id].css': 'css/[name].[contenthash].css',
                },
            ])
            .end()
        .plugin('html') // 添加 html-webpack-plugin 插件
            .use(require('html-webpack-plugin'), [
                {
                    template: path.resolve(__dirname, './public/index.html'), // 指定模版文件
                    chunks: ['app'], // 指定需要加载的 chunk
                    inject: 'body', // 指定 script 脚本注入的位置为 body
                },
            ])
            .end()
        .plugin('eslint') // 添加 eslint-webpack-plugin 插件
            .use(require('eslint-webpack-plugin'), [
                {
                    // Plugin options
                    extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
                    eslintPath: require.resolve('eslint'),
                    failOnError: !isDev,
                    context: path.resolve(__dirname, "./src"),
                    // ESLint class options
                    cwd: __dirname,
                    resolvePluginsRelativeTo: __dirname,
                }
            ])
            .end()
        .plugin('fork-ts-checker') // 配置 fork-ts-checker
            .use(require('fork-ts-checker-webpack-plugin'), [{
                eslint: {
                    files: './src/**/*.{ts,tsx,js,jsx}' // required - same as command `eslint ./src/**/*.{ts,tsx,js,jsx} --ext .ts,.tsx,.js,.jsx`
                },
                typescript: {
                    extensions: {
                        vue: {
                            enabled: true,
                            compiler: "vue-template-compiler"
                        },
                    }
                }
            }])
            .end()
        .devServer
            .host('0.0.0.0') // 服务器外部可访问
            .disableHostCheck(true) // 关闭白名单校验
            .contentBase(path.resolve(__dirname, './public')) // 设置一个 express 静态目录
            .historyApiFallback({
                disableDotRule: true, // 禁止在链接中使用 "." 符号
                rewrites: [
                    { from: /^\/$/, to: '/index.html' }, // 将所有的 404 响应重定向到 index.html 页面
                ],
            })
            .port(8080) // 当前端口号
            .hot(true) // 打开页面热载功能
            .sockPort('location') // 设置成平台自己的端口
            .open(true) // 开启页面
            .overlay({
                warnings: true,
                errors: true
            }) // webpack 错误和警告信息显示到页面
    
    //----- optimization start-----
    config.when(
        !isDev,
        () => {
            // 生成环境的时候
            config.optimization
                .minimize(true) // 打开压缩代码开关
                .minimizer('terser')
                .use(require('terser-webpack-plugin'), [
                    {
                        extractComments: false, // 去除注释
                        terserOptions: {
                            output: {
                                comments: false, // 去除注释
                            },
                        },
                    },
                ]);
        },
        () => {
            // 开发环境的时候
            config.devtool('cheap-module-source-map');
        }
    );
    config.optimization
        .splitChunks({
            cacheGroups: {
                vendors: {
                    // 分离入口文件引用 node_modules 的 module(vue、@babel/xxx)
                    name: `chunk-vendors`,
                    test: /[\\/]node_modules[\\/]/,
                    priority: -10,
                    chunks: 'initial',
                },
                common: {
                    // 分离入口文件引用次数 >=2 的 module
                    name: `chunk-common`,
                    minChunks: 2,
                    priority: -20,
                    chunks: 'initial',
                    reuseExistingChunk: true,
                },
            },
        })
        .runtimeChunk('single'); // 分离 webpack 的一些帮助函数,比如 webpackJSONP 等等
    //----- optimization end-------
    module.exports = config.toConfig();
    

    到这,我们的项目就算是搭建完毕了,可能还需要一些缝缝补补,不过已经可以满足一个企业级的项目标准了,小伙伴自己直接拖到项目中去使用。

    总结

    我们花了两节课完成了从 0 开始搭建一个企业级 React 的项目,怎么样?是不是感觉还是有点难度的? 正因为 Webpack 的配置太多了,所以 ReactVue 官方都会直接提供一个脚手架,然后通过一些简单的命令把一个配置好的项目直接给你,你不需要进行配置就可以轻松的把一个项目跑起来了,官方提供的项目可以满足大多数公司的一个业务需求,但是如果不能满足业务需求的时候,我们就需要自己具备从 0 搭建一个项目的功底了,这也是大公司必备的一个技能(对 webpack 不熟的小伙伴,强烈推荐去看我课程 《来和 webpack 谈场恋爱吧》:https://www.lanqiao.cn/courses/2893)。

    Demo 项目的全部代码地址:https://gitee.com/vv_bug/cus-react-demo/tree/dev-v1.0.0

    相关文章

      网友评论

          本文标题:快来跟我一起学 React(Day4)

          本文链接:https://www.haomeiwen.com/subject/jxqwcltx.html