Webpack 转译 Typescript

392 阅读4分钟

前言

最近在看自己的以前写的React项目脚手架,跑起来的时候报错了,去查了一下才知道是用的转译ts方法 awesome-typescript-loader 已经过时了,这个包也几年没有更新了

image.png 查了一下资料,现在流行的方案是TypeScript 和 Babel 团队官方合作的成果@babel/preset-typescript,至少是有保障的。

回顾一下 awesome-typescript-loader 方案

@babel/preset-typescript的优越性之前,还是先说下awesome-typescript-loader方案是如何对TypeScript进行处理的。

首先我们需要知道TypeScript是一个将TypeScript转换为指定版本JS代码的编译器,而Babel同样是一个将新版本JS新语法转换为低版本JS代码的编译器。

所以我们之前的方案每次修改了一点代码,都会将TS代码传递给TypeScript转换为JS,然后再将这份JS代码传递给Babel转换为低版本JS代码

因此我们需要配置两个编译器,并且每次做了一点更改,都会经过两次编译

babel-loader + @babel/preset-typescript 转译

image.png @babel/preset-typescript@babel/preset-react类似,是将特殊的语法转换为JS

但是有点区别的是,@babel/preset-typescript是直接移除TypeScript,转为JS,这使得它的编译速度飞快。并且只需要管理Babel一个编译器就行了,因为我将脚手架中的typescript库卸载后,依然可以完美运行。而且重要的是你写的TypeScript不会再进行类型检测,使得你改动代码后中断运行的页面。

  • 这种方案,当 webpack 编译的时候,babel-loader 会读取 .babelrc 里的配置, 不会调用 typescript(所以本地项目无需安装 typescript),不会去检查类型
  • 但是 tsconfig.json 是需要配置的,因为需要在开发代码时,让 idea 提示错误信息 webpack.config,js
rules: [
        {
          test:/\.(tsx?|jsx?)$/,
          // 默认会调用 @babel/core 
          use:'babel-loader'
        }
]

.babelrc

{
    "presets": [
        "@babel/preset-env"
        "@babel/preset-react",
        "@babel/preset-typescript"
    ]
}

使用 @babel/preset-typescript 需要注意的地方

有四种语法在 babel 中是无法编译的

  • namespace:不要再用了,已经过时了。改用标准的 ES6 module(import/export),在推荐的 tslint 规则中也建议不要使用 namesapce。
namespace Person{
    const name = 'abc';
}
  • 类型断言:改用 as 来断言类型(但是在 demo 中试了下,好像没报错,不知道是不是可以正常编译了)。
interface Person {
    name: string;
    age: number
}

let p1 = {age18as Person;
console.log(p2.name);

let p2 = <Person>{age18};
console.log(p3.name);
  • 常量枚举
const enum Sex {
    man,
    woman
}
  • 历史遗留风格的 import/export 语法:import xxx= require(…) 和 export = xxx

Typescript 官方转向 ESLint 的原因

  • TSLint 执行规则的方式存在一些架构问题,从而影响了性能,而修复这些问题会破坏现有规则;
  • ESLint 的性能更好并且使用者较多

使用了 TypeScript,为什么还需要 ESLint

  • TS 主要是用来做类型检查和语言转换的,顺带一小部分的语法检查
  • ESLint 主要是用来检查代码风格和语法错误的

如果在使用 babel-loader + @babel/preset-typescript 这种方案时,也想要类型检查,该怎么做

  • 第一种方案(再开一个 npm 脚本自动检查类型,需要同时启动两个线程)
// package.json
{
  "scripts": {
     // 再开一个 npm 脚本自动检查类型
    "type-check""tsc --watch",
  },
}

// tsconfig.json
{
  "compilerOptions": {
    // 不生成文件,只做类型检查
         "noEmit"true,                      \
  },
}
//使用 fork-ts-checker-webpack-plugin来做类型检查 ,开辟一个单独的进程去执行类型检查的任务,这样就不会影响 webpack 重新编译的速度
// webpack.config.js
    const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
    //...
    plugins: [
    new ForkTsCheckerWebpackPlugin({
      formatter: 'codeframe',
      async: true,
    }),
  ],

优点

  1. @babel/preset-typescript 做语法转换,fork-ts-checker-webpack-plugin 做语法检查, 集成在了 webpack 中,只用一个命令就可以启动。
  2. 编译速度快。
  3. 代码转译的时候也能发现类型错误。

参考

[译] TypeScript 牵手 Babel:一场美丽的婚姻

Webpack 转译 Typescript 现有方案

使用@babel/preset-typescript取代awesome-typescript-loader和ts-loader

细嚼慢咽 Typescript + React17 +Eslint + Git hook 工作流