从零开始配置 react + typescript(三):webpack

本文是《从零开始配置 react + typescript》系列的第三部分,详细介绍了如何配置webpack以适应react+typescript项目。文章强调了配置的灵活性、新潮性、严格性和实用性,同时对比了不同webpack配置方式。作者分享了如何使用TypeScript配置webpack,选择了express+webpack devServer中间件,以及如何实现热更新和生产环境优化,如CSS拆分、代码压缩等。
摘要由CSDN通过智能技术生成

本篇为 从零开始配置 react + typescript 系列第三篇,将带大家完成模板项目的 webpack 配置。整个项目的配置我力求达到以下目标:
灵活: 我在配置 eslint 是选择使用 js 格式而不是 json,就是为了灵活性,使用 js 文件可以让你使用环境变量动态配置,充分发挥 js 语言的能力。当然了,用 js 作配置文件也是有缺点的,不能使用 json schema 校验。
新潮: 我觉得时刻保持对新事物的关注和尝试去使用它是一个优秀的素质。当然,追新很容易碰到坑,但是,没关系,我已经帮你们踩过了,踩不过去我也不会写出来 😂。从我 eslint parserOptions.ecmaVersion 设置为 2020, 还有经常来一发 yarn upgrade --latest 都可以体现出来。
严格: 就像我平时判断相等性我大多数情况都是使用严格等 ===,而不是非严格等 ==,我觉得越严格,分析起来就越清晰,越早能发现问题。例如我么后面会使用一些 webpack 插件来严格检查模块大小写,检查是否有循环依赖。
安逸: 项目中会尽量集成当前前端生态界实用的和能提高开发愉悦性的(换个词就是花里胡哨)工具。
生产 ready:配置的时候针对不同的打包环境针对性优化,并确保能够投入生产环境使用。
如果读者是初次看到这篇文章,建议先看下前两篇:

从零开始配置 react + typescript(一):dotfiles
从零开始配置 react + typescript(二):linters 和 formatter

dev server
想当初我刚开始学前端框架的那时候,也是被 webpack 折磨的欲仙欲死,我是先自学的 node 才开始写前端,写 nodejs 很方便,自带的模块化方案 commonjs,写前端项目就要配置打包工具。当时最火的打包工具已经是 webpack 了,其次就是 gulp。配置 webpack 总是记不住 webpack 配置有哪些字段,还要扯到一堆相关的工具像 ES6 编译器 babel,CSS 预处理器 sass/less,CSS 后处理器 postcss,以及各种 webpack 的 loader 和 plugin。然后嫌麻烦就有一段时间都是用官方的脚手架,react 就用 cra,也就是 create-react-app,vue 就用 vue-cli。其实也挺好用的,不过说实话,我个人觉得,cra 没 vue-cli 设计的好,无论是易用性和扩展性都完败,cra 不方便用户修改 webpack 配置,vue-cli 不但易于用户修改 webpack 配置,还能让用户保存模板以及自带插件系统。我感觉 react 官方也意识到了这点,所以官方声称近期将会重点优化相关工具链。现在的话,如果我新建一个前端项目,我会选择自己配,不会去采用官方的 cli,因为我觉得我自己已经相当熟悉前端各种构建工具了,等我上半年忙完毕业和找工作的事情我应该会将一些常用的配置抽成一个 npm 包,现在每次写一个项目都 copy 改太累了,一个项目的构建配置有优化点,其它项目都要手动同步一下,效率太低。
技术选型
TypeScript 作为静态类型语言,相对于 js 而言,在类型提示上带来的提升无疑是巨大的。借助 IDE 的类型提示和代码补全,我们需要知道 webpack 配置对象有哪些字段就不用去查官方文档了,而且还不会敲错,很安逸,所以开发语言就选择 TypeScript。
官方文档上有专门一节 Configuration Languages 介绍怎么使用 ts 格式的配置文件配置 webpack 命令行工具,我觉得 webpack-dev-server 命令行工具应该是一样的。
但是我不打算使用官方文档介绍的方式,我压根不打算使用命令行工具,用 node API 才是最灵活的配置方式。配置 webpack devServer 总结一下有以下方式:

webpack-dev-server,这是最不灵活的方式,当然使用场景简单的情况下还是很方便的
webpack-dev-server node API,在 node 脚本里面调用 web-dev-server 包提供的 node API 来启动 devServer
express + webpack devServer 相关中间件,实际上 webpack-dev-server 就是使用 express 以及一些 devServer 相关的中间件开发的。在这种方式下, 各种中间件直接暴露出来了,我们可以灵活配置各个中间件的选项。
koa + webpack devServer 相关中间件,我在 github 上还真的搜到了和 webpack devServer 相关的 webpack 中间件。其实 webpack devServer 就是一个 node server 嘛,用什么框架技术实现不重要,能实现我们需要的功能就行。

我最终采用 express + webpack devServer 相关中间件的方式,为什么不选择用 koa ?因为我觉得官方用的就是 express,用 express 肯定要比 koa 更成熟稳定,坑要少一些。
实现最基本的打包功能
从简到繁,我们先来实现最基本的打包功能使其能够打包 tsx 文件,在此基础上一步一步丰富,优化我们的配置。
配置入口文件
先安装 TypeScript:

本地安装开发依赖 typescript

yarn add typescript -D
复制代码每个 TypeScript 项目都需要有一个 tsconfig.json 配置文件,使用下面的命令在 src 目录下新建 tsconfig.json 文件:
cd src && npx tsc --init && cd …
复制代码我们暂时调整成这样:
// src/tsconfig.json
{
“compilerOptions”: {
/* Basic Options */
“jsx”: “react”,
“isolatedModules”: true,

    /* Strict Type-Checking Options */
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true,

    /* Module Resolution Options */
    "moduleResolution": "node",
    "esModuleInterop": true,
    "resolveJsonModule": true,

    /* Experimental Options */
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,

    /* Advanced Options */
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true
}

}
复制代码我们将使用 babel 去编译 TypeScript,babel 在编译 TypeScript 代码是直接去掉 TypeScript 的类型,然后当成普通的 javascript 代码使用各种插件进行编译,因此 tsconfig.json 中很多选项例如 target 和 module 是没有用的。

启用 isolatedModules 选项会在 babel 编译代码时提供一些额外的检查,esModuleInterop 这个选项是用来为了让没有 default 属性的模块也可以使用默认导入,举个简单的例子,如果这个选项没开启,那你导入 fs 模块只能像下面这样导入:
import * as fs from ‘fs’;
复制代码开启了以后,可以直接使用默认导入:
import fs from ‘fs’;
复制代码本质上 ESM 默认导入是导入模块的 default 属性:
import fs from ‘fs’;
// 等同于
import * as module from ‘fs’;
let fs = module.default;
复制代码但是 node 内建模块 fs 是没有 default 属性的,开启 isolatedModules 选项就会在没有 default 属性的情况下自动转换:
import fs, { resolve } from ‘fs’;
// 转换成
import * as fs from ‘fs’;
let { resolve } = fs;
复制代码
我们添加一个入口文件 src/index.tsx,内容很简单:
import plus from ‘./plus’;

console.log(plus(404, 404, 404, 404, 404)); // => 2020
复制代码src/plus.ts 内容为:
export default function plus(…nums: number[]) {
return nums.reduce((pre, current) => pre + current, 0);
}
复制代码编译 TypeScript
我们知道 webpack 默认的模块化系统只支持 js 文件,对于其它类型的文件如 jsx, ts, tsx, vue 以及图片字体等文件类型,我们需要安装对应的 loader。对于 ts 文件,目前存在比较流行的方案有三种:

babel + @babel/preset-typescript

ts-loader

awesome-typescript-loader

awesome-typescript-loader 就算了,作者已经放弃维护了。首先 babel 我们一定要用的,因为 babel 生态有很多实用的插件。虽然 babel 是可以和 ts-loader 一起用,ts-loader 官方给了一个例子 react-babel-karma-gulp,但是我觉得既然 babel 已经能够编译 TypeScript 我们就没必要再加一个 ts-loader,所以我选择方案一。
添加 webpack 配置
我们将把所有 node 脚本放到项目根目的 scripts 文件夹,因为 src 文件夹是前端项目,而 scripts 文件夹是 node 项目,我们应该分别配置 tsconfig.json,通过下面的命令在其中生成初始的 tsconfig.json 文件:
cd ./scripts && npx tsc --init && cd …
复制代码我们调整成酱:
// scripts/tsconfig.json
{
“compilerOptions”: {
/* Basic Options */
“target”: “ES2020”,
“module”: “commonjs”,

    /* Strict Type-Checking Options */
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true,

    /* Module Resolution Options */
    "moduleResolution": "node",
    "esModuleInterop": true,
    "resolveJsonModule": true,

    /* Experimental Options */
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,

    /* Advanced Options */
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true
}

}

复制代码提几个需要注意的地方:

“target”: “ES2020”,其实编译级别你调的很低是没问题的,你用高级语法 tsc 就转码呗,缺点就是转码后代码体积会变大,执行效率也会降低,原生语法一般都是被优化过的。我喜欢调高一点,一般来说只要不用那些在代码运行平台还不支持的语法就没问题。自从 TypeScript3.7 支持了可选链,我就开始尝试在 TypeScript 使用它,但是问题来了,我之前编译级别一直都是调成最高,也就是 ESNext,因为可选链在 ESNext 已经是标准了,所以 tsc 对于可选链不会转码的。然后 node 12 还不支持可选链,就会报语法错误,于是我就降到 ES2020 了。

Strict Type-Checking Options,这部分全开,既然上了 TypeScript 的船,就用最严格的类型检查,拒绝 AnyScript

删掉 Additional Checks 部份的配置,这部分 eslint 能做的更多,更好

接着我们新建 scripts/configs文件夹,里面用来存放包括 webpack 的配置文件。在其中新建三个 webpack 的配置文件 webpack.common.ts, webpack.dev.ts和 webapck.prod.ts。webpack.common.ts 保存一些公共的配置文件,webpack.dev.ts 是开发环境用的,会被 devServer 读取,webapck.prod.ts 是我们在构建生产环境的 bundle 时用的。
我们接着安装 webpack 和 webpack-merge 以及它们的类型声明文件:
yarn add webpack webpack-merge @types/webpack @types/webpack-merge -D
复制代码webpack-merge 是一个为 merge webpack 配置设计的 merge 工具,提供了一些高级的 merge 方式。不过我目前并没有用到那些高级的 merge 方式,就是当成普通的 merge 工具使用,后续可以探索一下这方面的优化。
为了编译 tsx,我们需要安装 babel-loader 和相关插件:
yarn add babel-loader @babel/core @babel/preset-typescript -D
复制代码新建 babel 配置文件 ba

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值