使用typescript下的项目架构最佳实践

此贴记录下在 typescript 项目里的一些相关配置和包的选用,其中各种依赖包和最佳实践都在不断发展演变中,最新的配置以该仓库 MVVM 为准。

typescript 支持

webpack中使用 babel 7.0 +,摒弃了传统的 ts-loaderawesome-typescript-loader 方案。原因如下:

1
2
yarn add @babel/core babel-loader @babel/preset-env @babel/preset-typescript -D
yarn add @babel/plugin-proposal-class-propertie -D //根据项目需求添加其他env未包含的转义插件

babel 只负责转换,并不会做对应的类型检查,所以需要安装 fork-ts-checker-webpack-plugin 来进行报错提示:

1
yarn add fork-ts-checker-webpack-plugin -D

项目通用转 ES5 安装包:

1
yarn add @babel/plugin-transform-runtime @babel/runtime-corejs3 -D

babel.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module.exports = {
presets: [
[
'@babel/env',
{
targets: '> 1%, not dead',
},
],
'@babel/preset-typescript',
],
plugins: [
[
'@babel/plugin-transform-runtime',
{
corejs: 3,
},
],
'@babel/plugin-proposal-class-properties',
],
};

tsconfig.json 配置:

1
2
3
4
5
6
7
8
9
{
"compilerOptions": {
"target": "ESNext",
"module": "commonjs",
"noImplicitAny": true,
"sourceMap": false
},
"include": ["src/**/*"]
}

webpack 配置:

1
2
3
4
5
6
7
8
9
module: {
rules: [
{
test: /\.(js|ts)$/,
exclude: /(node_modules|bower_components)/,
use: ['babel-loader'],
},
];
}

代码检查 & 风格统一

代码检查使用 eslint官方未来推荐),抛弃传统的 tslint 方案:参考链接

1
2
3
4
yarn add eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin -D

//@typescript-eslint/parser :将 TypeScript 转换为 ESTree,使 eslint 可以识别
//@typescript-eslint/eslint-plugin :只是一个可以打开或关闭的规则列表

@typescript-eslint/parser 作为 babel 的解析器,这时候就不需要安装 babel 默认推荐的 eslint 解析器(babel-eslint)了,规则列表查阅

风格统一使用 prettier,在 typescript 项目里将配置文件 prettier.config.js 里添加 parser: "typescript" 即可(前提是已安装 @typescript-eslint/parser参考链接)。

项目通用 prettier 的其他包:

1
yarn add prettier eslint-config-prettier eslint-plugin-prettier -D

结合 eslint+prettier,得到:

prettier.config.js:

1
2
3
4
5
module.exports = {
singleQuote: false,
printWidth: 200,
parser: 'typescript',
};

.eslintrc.js (这里使用的 google 默认规则 eslint-config-google):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
env: {
browser: true,
es6: true,
},
extends: ['plugin:@typescript-eslint/recommended', 'google', 'prettier', 'prettier/@typescript-eslint'],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
},
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
rules: {
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-use-before-define': 0,
},
};

单元测试

jest

这里选用 jest 框架来测试。jest 的优势?

ts 项目里,摒弃了传统的 ts-jest,只需如上安装 @babel/preset-typescript,并在 babel.config.js 里的 presets 添加即可。参考链接

1
yarn jest @types/jest -D  //@types/jest 是 jest 的 ts 类型定义文件,而 vscode 便是基于 ts 进行代码提示的
  • 经查 jest 依赖包里发现,jest 依赖 babel-jest (用于支持 es6 语法),故不需要在单独引入依赖包 babel-jest
  • 因为引入了 @types/jest,也就不需要引入 eslint-plugin-jest 来消除 jest 变量的报错。
  • jest config 采用默认配置即可,更多个性化配置参见

coveralls

这里选用了 coveralls 作为自动测试代码覆盖率的在线工具。由于项目走 travis.com 的持续集成,所以配置为:

1
yarn add coveralls -D

.coveralls.yml:

1
2
service_name: travis-pro
repo_token: COVERALLS_TOKEN # COVERALLS_TOKEN为加密变量

package.json 添加 scripts (测试框架为 jest更多方法查阅):

1
2
3
"scripts": {
"coveralls": "jest --coverage && cat ./coverage/lcov.info | coveralls"
},

.travis.yml 添加:

1
2
3
script:
- sed -i "s/COVERALLS_TOKEN/$COVERALLS_TOKEN/" .coveralls.yml #$COVERALLS_TOKEN为在travis.com项目里配置的加密变量
- yarn run coveralls

在 vscode 里调试 jest/webpack 等 node.js

调试 -> 添加配置 -> 选择node.js,自动生成.vscode/launch.json,修改配置为:

文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"configurations": [
{
"type": "node", //系统默认,不可更改,标识要使用的调试器的类型
"request": "launch", //系统默认,不可更改,在指定的文件上启动调试器 program. attach: 将调试器附加到已经运行的进程。
"name": "Launch Program", //调试配置的名称
"program": "${workspaceFolder}/index.js", //要调试的Node.js程序的绝对路径
"args": ["--runInBand", "--env=jsdom", "${fileBasename}"], //传递给程序进行调试的参数[array]
"runtimeExecutable": "npm", // 要使用的运行时可执行文件的绝对路径。默认是node (https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_launch-configuration-support-for-npm-and-other-tools)
"runtimeArgs": ["run-script", "debug"], // 传递给运行时可执行文件的可选参数
"runtimeVersion":"7.10.1", //使用nvm可以用此属性控制node.js版本
"port": 5858, //要使用的调试端口
"console": "externalTerminal", //指定如何显示程序输出: externalTerminal:独立控制台窗口,integratedTerminal(默认):VS代码集成终端
"stopOnEntry": true, // 设置为true时,在调试程序的第一行中断开调试器。如果省略(默认)或设置为false,则调试器将程序运行到第一个断点。
"skipFiles": ["<node_internals>/**/*.js","${workspaceFolder}/lib/**/*.js"] // 跳过不感兴趣的代码, Node.js的内置核心模块定义为:<node_internals>,其他变量定义(https://code.visualstudio.com/docs/editor/variables-reference)
}
]
  • 调试单一 node 文件:
    • launch.json 配置:
      • program:${workspaceFolder}/index.js
      • args:['--dev']
  • 调试 npm scripts (包括普通 node 命令如 index.js 和非 node 命令如 jest,webpack 等)时:
    • launch.json 配置:
      • runtimeExecutable:"npm" //必须设置为npm
      • runtimeArgs:["run", "debug"] //第一个参数必须为run
      • runtimeVersion:"10.6.0" //可选
    • package.jsonnpm scripts 配置:
      • 必须加 --inspect-brk=58585858port 设置须相同
      • 非普通命令需要转换成 node 调用: webpack=>./node_modules/.bin/webpack (因为 npm run build 实际调用的是 node_modules/.bin/webpack)
      • 带参数的命令接在后面即可:node --inspect-brk=5858 ./node_modules/.bin/jest --coverage

npm scripts:

1
2
3
4
5
"scripts": {
"debug": "node --inspect-brk=5858 index.js",
"build": "node --inspect-brk=5858 ./node_modules/.bin/webpack --mode=development",
"test": "node --inspect-brk=5858 ./node_modules/.bin/jest --coverage"
},

前端测试概念

测试类型

  • 单元测试 (Unit Test) - 通过模拟输入和预测输出的方式测试独立的函数或者类。
  • 集成测试 (Integration Test) - 测试多个模块间的联动是否和期望相同。
  • E2E 测试 (也被称为 Functional Test) - 关注点不在内部实现方式,而是测试产品在真实使用场景(比如在浏览器)中是否可以达到预想的结果,属于黑盒测试。

更多

其他

Typescript 错误忽略

  • 单行忽略 // @ts-ignore
  • 忽略全文 // @ts-nocheck
  • 取消忽略全文 // @ts-check

github 徽章

shields 上面可生成任意徽章。

.d.ts 文件是什么

d.ts 就是 TypedDefinition 类型定义文件,用来定义类型信息以及接口规范。

ts代码最终会编译成 .jsjs 代码,供他人使用。这个时候类型信息就丢失了。所以 ts 编译器会自动根据 .ts 中的信息,可以自动生成对外的 .d.ts 文件,和生成的 js 文件搭配使用。其中,js 文件是给运行引擎用的,而 .d.ts 文件是给 IDE(智能编辑器) 写代码时参考用的。

如何测试本地 node 包

采用 npm link

  • 在需要测试的包(如 test )路径下执行:npm link,这时 全局node_modules 包下就可以看到这个 test 包。
  • 在需引用的目标包的项目下安装该测试包:npm link test(如果有作用域需要加上作用域:npm link @fe_korey/test),这时 test 包就被安装在了该目录下,在 test 包里的修改会同步到目标包里。
  • 取消连接:在 test 包里执行:npm unlink 即可.

注意:在 webpack 项目中,如果用 npm link 方式测试本地包,需要设置 config:

1
2
3
resolve: {
symlinks: false;
}
---- 本文结束,感谢您的阅读 ----