webpack4.0搭建React + typescript + eslint + antd项目过程

没有webpack配置项目经验的同学,可以先看以下两篇文章
(1.)https://segmentfault.com/a/11...【基础配置1】
(2.)https://segmentfault.com/a/11...【应用配置2】

写在前面

之前一直都是在帮别人做react的项目,所以并没有去详细了解如果去通过webpack搭建一个react项目,再加上ts项目也是未自己从零开始配置过,刚好最近有时间就配置了一下,发现刚开始还是会对配置有很多疑惑和踩一些小坑

如:

  • typescript + react项目eslint该怎么配置。
  • typescript + react 如何配置babel
  • React cssModules怎么配置。
  • 以及配置antd时babel.confgtsconfig需要怎么支持。

因为并不是项目使用,所以这里没有去研究如何对打包做优化,感觉应该跟vue的项目差不多是一样的。图片文字处理的话也可以看基础配置,应该也是差不多的

常规配置

本项目都是将开发环境,生产环境分成不同的文件配置而执行的(分离一向是一件比较美好的事。)以下是文件的作用

webpack.config.js 打包时执行文件

  • webpack.common.js 公共的配置文件
  • webpack.dev.js 开发环境配置文件
  • webpack.prd.js 生产环境配置文件

安装相关依赖

npm install webpack webpack-cli webpack-dev-server webpack-merge html-webpack-plugin clean-webpack-plugin cross-env --save-dev
主要配置入口和出口和以及prd与dev的公共插件和module
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    entry: {
        app: path.resolve(__dirname, '../src/index.tsx')
    },

    output: {
        filename: '[name].[chunkhash].js',
        path: path.resolve(__dirname, '../dist'),
        chunkFilename: '[name].[chunkhash].js'
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js']
    },
    plugins: [
        new CleanWebpackPlugin({
            cleanOnceBeforeBuildPatterns: [path.resolve(__dirname, '../dist')]
        }),
    ]
}

配置webpack.dev.js

主要包含起node服务,以及区分与生产环境相关的配置。
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    devServer: {
        port: 3000,
        host: 'localhost',
        contentBase: path.resolve(__dirname, 'dist')
    },
    devtool: 'cheap-module-eval-source-map',
    plugins: [
        new HtmlWebpackPlugin({
            title: '风',
            template: path.resolve(__dirname, '../page/index.html'),
            minify: {
                collapseWhitespace: true,
                hash: true,
                chunksSortMode: 'manual'
            }
        }),
    ],
    mode: 'development'
}

配置webpack.prd.js

生产环境'production'相关配置
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    devtool: "cheap-module-source-map",
    plugins: [
        new HtmlWebpackPlugin({
            title: '风',
            template: path.resolve(__dirname, '../page/index.html'),
            minify: {
                collapseWhitespace: true,
                hash: true,
                chunksSortMode: 'manual'
            }
        })
    ],
    mode: 'production'
}

配置webpack.config.js

webpack 执行主文件
const merge = require('webpack-merge');
const common = require('./build/webpack.common');
const dev = require('./build/webpack.dev');
const prd = require('./build/webpack.prd');
module.exports = mode => {
    if(mode === 'production') {
        return merge(common, prd)
    }
    return merge(common, dev)
}

配置npm script

配置 npm 脚本命令(通过--env development向webpack.config.js函数传入参数)
"scripts": {
    "start": "webpack-dev-server --env development --open",
    "prd": "webpack --env production"
 },

通过以上能够基本起动一个开发环境了,和通过build能生成一个dist目录文件。

配置typescript

在配置typescript的时候我们需要知道typescript是什么,这很重要!在学习过typescript之后我们有了以下的认知:

  • typescript文件将js文件修改为.ts后缀。
  • typescript在js基础上多了一些类型约束。
  • typescript会在编译的时候会根据tsconfig.json的配置进行检查。
  • typescript能够在不配置babel的时候通过配置tsconfig.json支持es6语法。
  • typescript使我们写代码的时候更严谨了。(这与后面将到的配置无关)

既然将.js修改为了.ts后缀肯定loader是必然不可少的东西,以及配置ts.confing.json

配置ts-loader

安装依赖:

npm install --save-dev babel-loader typescript ts-loader

webapck.common.js文件添加以下配置, 以将ts文件和tsx编译成浏览器认识的文件

module: {
    rules: [
        {
            test: /\.(ts|tsx)?$/,
            use: [
                'babel-loader',
                'ts-loader'
            ],
            exclude: /node_modules/
        }
    ]
}

配置ts.config.json

tsconfig文件主要配置包含以下几项:

  • compilerOptions 主要是一系列编译选项, 平时配得比较多的一般就target, moduleallowSyntheticDefaultImports,strict,baseUrl, outDir, sourceMap,jsx这些项,至于这些选项的具体作用,可以查看https://www.tslang.cn/docs/ha...
  • exclude 去除node_modules
  • include 设置为[src/**/*]

这是我的tsconfig配置

{
    "compilerOptions": { // 编译配置
        "sourceMap": true,
        "noImplicitAny": true,
        "module": "ESNext",
        "target": "es5",
        "jsx": "react",
        "strict": true,
        "allowSyntheticDefaultImports": true,
        "moduleResolution": "node" // 解决按需引入antd 报错问题(module设置为ESNext)
    },
    "exclude": [ // 不检查以下文件内容
        "node_modules"
    ],
    "include": [ // 检查以下文件内容
        "src/**/*", 
        "postcss.config.js"
    ]
}

配置babel

babel主要作用是将ECMAScript2015+ 版本的代码转为向后兼容的javascript代码。如果没配置过babel可以推荐去看下地址,如果想更深入可以去阅读一遍官方文档babel-中文网.

babel配置列表

  • presets 预设。 如果不需要自己手动组合插件就可以选择配置presets相关插件。

数组结构,执行从后往前执行。

  • plugins 插件。

安装插件:(@babel/core)是必须的
npm install --save-dev @babel/core babel/plugin-syntax-dynamic-import @babel/preset-react @babel/plugin-transform-runtime @babel/preset-env @babel/preset-typescript

我这儿使用的是babel.config.js的配置方式

配置:

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

    // 从后往前执行
    const presets = [
        require("@babel/preset-env"), // 编译转换将其转换为2015的代码
        require("@babel/preset-react"),  // 编译react
        require("@babel/preset-typescript") // 编译typescript
    ]

    // 顺序执行
    const plugins = [
        // require("react-hot-loader/babel"),
        // require("transform-react-jsx-source"), // 开发环境使用
        require("@babel/plugin-syntax-dynamic-import"),
        require("@babel/plugin-transform-runtime")
    ]
    return {
        presets,
        plugins
    }
}

配置eslint

eslint配置文件可以使用.eslintrc.json或者.eslintrc.js或者package.json文件通过添加eslintConfig项配置

eslint配置列表项

  • root 设置为true表示当前文件为根目录
  • parser 解析器,因为是typescript项目,所以添加@typescript-eslint/parser
  • parserOptions 解析器配置选项,react项目将配置
{
    'ecmaVersion': 6, // 指定ECMAScript版本
    'sourceType': 'module', // ECMAscript 模块
    'ecmaFeatures': { //额外的语言特性
        'jsx': true
    }
}
  • env 配置文件指宝环境
{
    "node": true, 
    "browser": true,// 支持浏览器
    "es6": true
}
  • overrides为特定类型的文件指定处理器 也可以禁用一组文件的某些配置[数组对象列表]

如我这儿禁用掉.tsx文件不校验某些规则

{
    "files": ["*.tsx"],
    "rules": {
        "@typescript-eslint/explicit-function-return-type": 0,
        "react/prop-types": 0
    }
}
  • extends 使eslint继承某些已有配置,或者库。我这儿使用airbnb,airbnb包含了react的相关规则,所以一般需要安装eslint-plugin-reacteslint-plugin-jsx-a11y等以及promise规则

安装:
npm install --save-dev eslint-plugin-import, eslint-plugin-react, eslint-plugin-react-hooks, and eslint-plugin-jsx-a11y eslint-plugin-promise

"extends": [
    'airbnb',
    "plugin:promise/recommended"
],
  • plugins 借用官网的话 插件可以提供处理器。处理器可以从另一种文件中提取 JavaScript 代码,然后让 ESLint 检测 JavaScript 代码。或者处理器可以在预处理中转换 JavaScript 代码

安装npm install --save-dev eslint-plugin-react-hooks

"plugins": [
    "react-hooks", // hooks 规则
    "promise"
],
  • rules配置规则官方地址eslint-rules以及插件对应默认规则配置。

webpack配置eslint-loader

只配置了eslint规则文件并不会生效,还需要配置对应loader

安装:
npm install --save-dev eslint-loader

webpack配置module中添加Loader配置:

{
    enforce: 'pre',
    test: /\.(ts|tsx|js)?$/,
    loader: 'eslint-loader',
    exclude: /node_modules/,
    options: {
        fix: true // 自动修复
    }
}

详细配置规则地址:eslint-loader

引入antd

注意tsconfig 编译器需要配置"moduleResolution": "node"
安装:

npm install --save antd

支持按需引入,需要安装babel-plugin-import

npm install --save-dev babel-plugin-import

babel.config.js新增以下配置

plugins.push([
    "import",
    {
        "libraryName": "antd",
        "style": true
    }
])

css modules配置

React项目跟vue不一样的是,在配置css模块化的时候,vue可以直接配置一个vue-loader然后在