配置Typescript、ESLint并支持polyfill踩坑指南

5,848 阅读5分钟

前言

最近在搞一个公司用的插件开发环境,环境是以TypeScript+Webpack+ESlint+Sass并支持polyfill为基础进行配置的 但是在配置的过程中TypeScript与其他工具的配合上总会出现一些坑,而这些坑是我翻了很多国外论坛、知乎提问、去github仓库找到两年前的issue才解决的,所以在此记录分享一下,希望可以帮助需要的人躲避这些坑。

TypeScript支持polyfill

起初我在TypeScript文档中找到,配置tsconfig.js,其中 compilerOptions 参数中 lib 这个配置,中文文档中的描述为:

编译过程中需要引入的库文件的列表。

所以我一直认为只要在lib中声明了es2015.promise 它就可以智能的为我引入promise

{
    "compilerOptions" :{
        "lib":["dom", "scripthost", "es5","es2015.promise"],
        ...
    },
    ...
}

然而并不会这样,在配置文件中lib的实际作用是声明我们环境中TypeScript文件支持的语法方式。

简单一句话不易理解,我们来测试一下:

如果把lib中的"dom"删掉,那么如果你在写代码的时候使用JS创建了一个Element(dom)元素,在编译的时候是不允许的。

如果你使用了VScode,它会根据你tsconfig.js的配置文件,直接在使用了Element的代码片段告诉你,当前配置是不允许使用Element。

如果我们把lib中的"dom"添加回去,则编辑器就没有错误提示了:

同时,lib这个字段是可选项,我们可以不配置它,它会有默认的配置,根据target的值不同,它的默认值也不同

//target = es5
{
    "compilerOptions" :{
        "target":"es5"
        //"lib":["dom", "scripthost", "es5"]默认值
        ...
    },
    ...
}

//target = es6
{
    "compilerOptions" :{
        "target":"es6"
        //"lib":["dom", "scripthost", "es6","dom.iterable"]默认值
        ...
    },
    ...
}

那么 lib 中的配置究竟都做了什么呢?

比如上面我想要让它支持promise,我在lib中就添加了"es2015.promise"的值

打开node_modules找到typescript文件夹,他下面有一堆的lib.xx.xx文件

看看lib.es2015.promise都做了什么, 它只是对promise方法做了类型语法的检测支持

所以问题到这里就迎刃而解了,单独的配置lib属性并不会带来支持polyfill的实际作用

我们需要安装core-js

yarn add core-js --dev

然后在需要使用polyfill的文件中引用它

import * as Promise from 'core-js-pure/features/promise';

由于我不希望我插件中的promise对全局的方法造成污染

所以我调用了core-js-pure中的promise,而不是core-js/features/promise注意两者的区别

另外记得配置下tsconfig.js的module参数为commonjs

{
    "compilerOptions" :{
        "module":"commonjs",
        ...
    },
    ...
}

注意这里有坑:

core-js的官方代码中,推荐我们引用方式是

import Promise from 'core-js-pure/features/promise';

而不是

import * as Promise from 'core-js-pure/features/promise';

但它推荐的方式在typescript中编译后会报错,不符合typescript的语法

我在tsconfig.js中的module参数尝试了umd/esnext/es2015都没办法正常打包

但当使用commonjs模式就可以正常使用了,需要注意一下

配置后大功告成,环境已经可以根据需求支持polyfill了 ~

ESLint配合TypeScript使用

现在很多其他文章的配置已经被淘汰了,或者git仓库也不再维护,我也是顺藤摸瓜找到的一份配置方案,其中也有一些坑,在此作记录。

先列出需要安装的扩展:

yarn add eslint eslint-loader @typescript-eslint/parser @typescript-eslint/eslint-plugin --dev

eslint和eslint-loader就不多说了,一个是基础支持库无需配置,一个是webpack检测文件处理的loader

这里主要介绍下后面两个

@typescript-eslint/parser

由于eslint默认是不支持检测typescript的,我们需要安装它的扩展,让它支持typescript的语法,所以它必不可少

@typescript-eslint/eslint-plugin

但当我们有了它的功能后,我们如何设定它的规则?于是官方提供了一套规则的扩展插件,也就是它了

配置ESLint

当我看到官方提供了一套这么友好简单易读的默认配置,我的内心是非常激动的,在解决typescript支持polyfill的问题上我已经心神憔悴了,它的出现就像夏日夜晚里的一阵微风,你以为是凉爽的,结果吹到脸上却热得发烫,让人失望,因为这个配置会报错!

//在根目录创建.eslintrc.js
{
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "project": "./tsconfig.json"
  },
  "plugins": ["@typescript-eslint"],
  "rules": {
    "@typescript-eslint/restrict-plus-operands": "error"
    //这里就调用了@typescript-eslint/eslint-plugin的rule配置,更多配置可以去github上查文档
  }
}
//运行后报错
Parsing error: ImportDeclaration should appear when the mode is ES6 and in the module context

这个ImportDeclaration是什么东西?这个错误该如何解决?我的大脑比较蒙,按照以往的逻辑,国内的搜索引擎直接pass掉,肯定找不到答案,于是我来到了stackoverflow.com企图找到解决方案,结果比较遗憾,只搜到了一条相关的问题,而里面的回答也没有参考性,最终在github的issue看到有很多人也遇到过,但是问题都是一两年前的,解决方案都是让它们升级版本,而我们在当前时间线的版本已经是最新的了!开发人员真是鬼才啊,两年前的bug又复现了呢

翻阅了四五个issue后,在绝望之际找到了解决方案,在parserOptions新增三个参数即可(ecmaVersion、sourceType、ecmaFeatures)

//在根目录创建.eslintrc.js
{
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 6,//也就是ES6语法支持的意思
    "sourceType": "module",
    "ecmaFeatures": {
        "modules": true
    },
    "project": "./tsconfig.json"
  },
  "plugins": ["@typescript-eslint"],
  "rules": {
    "@typescript-eslint/restrict-plus-operands": "error"
    //这里就调用了@typescript-eslint/eslint-plugin的rule配置,更多配置可以去github上查文档
  }
}

参考.eslintrc配置文档

如此一来ESLint即可与TypeScript搭配使用了!

结尾

另外我发现webpack在编译typescript后没有办法压缩,需要借助webpack的uglifyjs-webpack-plugin插件来进行压缩, 在配置TS环境有很多坑,而每个人根据 需求遇到的问题可能不同,还需耐心解决!