ts-loader 和 babel 混用的时代
那时候 create-react-app 还没有官方的 ts 版本。 eslint 和 tslint 还没合并在一起。 大部分项目都在用 ts-loader + eslint + tslint + webpack + babel 混用的工作流。
缺点:
- 每次修改了一点代码,都会将 ts 代码传递给 typescript 转换为 js ,然后再将这份 js 代码传递给 Babel 转换为低版本 js 代码,不但慢,而且最终转译出来的代码可能比较冗余。
- 需要配置两个编译器,并且每次做了一点更改,都会经过两次转译,代码重新编译会非常慢。
优点: typescript 会做两个动作转译和类型检查。
ts-loader + fork-ts-checker-webpack-plugin
因为 typescript 会同时做转译和代码检查,那可不可以只做转译或者代码检查其中一件事情呢? 可以通过 ts-loader 配置关闭掉类型检查
transpileOnly: true,
然后再使用 fork-ts-checker-webpack-plugin来做类型检查 ,开辟一个单独的进程去执行类型检查的任务,这样就不会影响 webpack 重新编译的速度。
// webpack.config.js
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
module.exports = {
...
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
// disable type checker - we will use it in fork plugin
transpileOnly: true
}
}
]
},
plugins: [new ForkTsCheckerWebpackPlugin()]
};
后来还出现过 awesome-typescript-loader 来解决一些问题,不过这插件有各种各样的小问题,已经成为历史了,大家有空的自己了解。
缺点:
- 每次修改了一点代码,都会将 ts 代码传递给 typescript 转换为 js ,然后再将这份 js 代码传递给 Babel 转换为低版本 js 代码,不但慢,而且最终转译出来的代码可能比较冗余。
- 当时需要转译和类型检查等时候速度还是非常慢。
优点:
- 不需要类型检查,只编译等时候,速度比较快
@babel/preset-typescript 横空出世。
具体文档和文章在这里。
- iamturns.com/typescript-…
- babeljs.io/docs/en/bab…
你可以理解成 @babel/preset-typescript 和 typescript 的区别就是。
- typescript 既做代码转换,也做类型检查)。
- @babel/preset-typescript 只做语法转换,不做类型检查。
还有在语法转换区别有以下四点:
- Namespace语法不推荐(改用标准的 ES6 module(import/export)。
- 不支持 x 语法转换类型,(改用x as newtype)。
- const 枚举
- 历史遗留风格的 import/export 语法。比如:import foo = require(...) 和 export = foo。
- 第1条和第4条语法新项目基本没人用了。
- 第2条缺陷改一下语法就好了,这个语法会直接提示语法报错,很好改,问题不大。
- 第3条 2021 年 02 月亲测可用。
优点:
- 更快的编译速度。
- babel 可以根据目标浏览器情况转换部分语法。
- 配置简单许多。
缺点: 如果单单只用 @babel/preset-typescript,当我们在执行 npm run build 的时候,肯定需要把 ts 文件的代码输出成 js 代码,这时候不管代码是否正确,代码都会被打包出来,不能及时发现代码的问题。
我大概在三年前写过一个 babel + tsx 最简单的 demo (只转译,没做类型检查,会出现上述问题) github.com/Faithree/we…
下面再介绍一种方式。
- @babel/preset-typescript 做语法转换
- typescript 做语法检查。
package.json
"scripts": {
"check-types": "tsc --watch"
}
tsconfig.json 设置 noEmit 不生成文件,只做类型检查
{
"compilerOptions": {
"noEmit": true,
},
"include": [
"src"
]
}
缺点:
- 你要起两个线程,一个是 webpack 的线程,另一个是 typescript 执行代码类型检查的线程,可能会出现报错不同步,还要搭配支持 vscode 编辑器可能才有比较好的体验。
- 防止 build 转译代码的时候出现类型错误。如果你改了代码,没运行 check-types 命令,代码也能转译成功,但是可能代码是有类型问题的。
最佳实践 @babel/preset-typescript+ fork-ts-checker-webpack-plugin
这种是在上面的基础上,把 typescript 替换成 fork-ts-checker-webpack-plugin。
// webpack.config.js
const path = require('path');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
mode: 'development',
entry: './src/index',
output: {
path: path.resolve(__dirname, 'dist'),
// filename: '[name]-[hash].js'
filename: 'bundle.js',
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.json'],
},
devServer: {
publicPath: '/',
host: '127.0.0.1',
port: 3000,
stats: {
colors: true,
},
},
module: {
rules: [
{
test: /\.(ts|js)x?$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
],
},
plugins: [
new ForkTsCheckerWebpackPlugin({
formatter: 'codeframe',
async: true,
}),
new HtmlWebPackPlugin({
template: 'public/index.html',
filename: 'index.html',
inject: true,
}),
],
};
优点:
- @babel/preset-typescript 做语法转换,fork-ts-checker-webpack-plugin 做语法检查, 集成在了 webpack 中,只用一个命令就可以启动。
- 编译速度快。
- 代码转译的时候也能发现类型错误。
- 丰富的 babel 插件,根据浏览器版本,输出指定 js 代码。
React 17
react 17 源代码不需要再引入 React 了,所以在 babel 和 ts 配置上有一些不同。
yarn add @babel/preset-react -D
babel.config.js
const presets = [
...
['@babel/preset-typescript'],
["@babel/preset-react", {
"runtime": "automatic"
}]
];
tsconfig.json
{
...
"jsx": "react-jsx"
}
eslint 和 tslint ?
eslint 其实也经历了很多的变化,从最开始 eslint-loader 到现在的 eslint-webpack-plugin,从 tslint + eslint 混用,到现在 eslint 的统一也经历了非常多年。
tslint -> eslint 主要是下面这三个库来做兼容。
- @typescript-eslint/eslint-plugin
- @typescript-eslint/parser
- @typescript-eslint/typescript-estree
详情可以看看 github.com/typescript-…
如何使用
eslint 具体的规则配置,从来没用过的,我的建议是没必要太纠结具体配置,先用上再说,我推荐 @umijs/fabric,也可以自行选择 airBnb等其他代码书写规则。
yarn add eslint-webpack-plugin -D
new ESLintPlugin({
extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
cache: true,
}),
eslint-webpack-plugin 详细配置可参考文档 github.com/webpack-con…
.eslint.js
module.exports = {
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json',
createDefaultProgram: true,
},
extends: [require.resolve('@umijs/fabric/dist/eslint')],
rules: {
'no-console': 0,
'no-new': 0,
'no-case-declarations': 0,
'react/jsx-tag-spacing': 0,
'react/no-danger': 0,
'react-hooks/exhaustive-deps': 'warn',
'no-param-reassign': 0,
'react/jsx-uses-react': 0,
'react/react-in-jsx-scope': 0,
'no-undef':2,
quotes: ['error', 'single'], // 使用单引号
semi: ['error', 'always'], // 结束添加分号
},
};
你可以运行下面这三个命令,会发现他们的报错信息都一致。
- yarn start
- yarn build
- yarn lint
git hook
yarn add yorkie lint-staged -D
package.json
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.{js,jsx}": [
"eslint"
],
"*.ts?(x)": [
"eslint"
]
},
.prettierrc.js
因为上面 用了 umi 的eslint 规范,这里我推荐直接用他们提供的 prettierrc
yarn add @umijs/fabric -D
const fabric = require('@umijs/fabric');
module.exports = {
...fabric.prettier,
};
参考
- github.com/webpack-con…
- github.com/typescript-…
- iamturns.com/typescript-…
- babeljs.io/docs/en/bab…
- github.com/Faithree/we…
- github.com/facebook/cr…
- github.com/umijs/umi
- github.com/Faithree/we…
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!