快来跟我一起学 React(Day4)

Posted vv_小虫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了快来跟我一起学 React(Day4)相关的知识,希望对你有一定的参考价值。

简介

上一节我们从 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

可以看到,浏览器自动打开了我们项目入口,并且在页面正常显示了 ”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

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

为了方便,我们在 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

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

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

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

可以看到,页面中提示了 ”编译失败“,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')以上是关于快来跟我一起学 React(Day4)的主要内容,如果未能解决你的问题,请参考以下文章

快来跟我一起学 React(Day8)

快来跟我一起学 React(Day2)

快来跟我一起学 React(Day7)

快来跟我一起学 React(Day7)

快来跟我一起学 React(Day6)

快来跟我一起学 React(Day6)