Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

「19」如何开发一个基于 TypeScript 的工具库并自动生成文档 #25

Open
BuptStEve opened this issue Jul 5, 2019 · 0 comments

Comments

@BuptStEve
Copy link
Owner

为什么用 TypeScript?

TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. Any browser. Any host. Any OS. Open source. ———— TypeScript 官网

1.第一时间发现类型错误

rollbar 统计,在前端项目中 10 大错误类型如下图所示:

JavaScript 错误类型

其中有 7 个是类型错误(TypeError):

  • Cannot read property 'xxx' on undefined:无法在 undefined 上读取 xxx 属性,通常出现在 a.b.c 的情况。
  • 'undefined' is not an objectundefined 不是对象
  • null is not an object:null 不是对象
  • 'undefined' is not a functionundefined 不是函数,通常出现在 a.b.c() 的情况。
  • Object doesn't support property
  • Cannot read property 'length':无法读取 'length' 属性,本来期望一个数组,但是变量的实际类型却不是数组。
  • Cannot set property of undefined:无法给 undefined 设置属性。

除了 7 个 TypeError,还有一个 ReferenceError:

  • 'xxx' is not defined:xxx 没有定义。

还有一个 RangeError:

  • 在 JS 中,数组越界并不会抛出 RangeError,但是某些函数则抛出这个错误

range error

嘿嘿,看着这些错误眼不眼熟?

由于 JavaScript 是一门很灵活的语言,所以以上这些错误往往要在代码运行时才能发现。

2.智能提示

在使用 JavaScript 时,编辑器的智能提示往往很有限,比如提示你最近输入的变量。

但是基于 TypeScript,由于知道当前变量是什么类型,所以编辑器能经过类型推导后为你提示这个变量的所有属性,以及对于函数的参数进行提示和校验。

智能提示

此外,对于一般的 JavaScript 项目也可以自己编写 .d.ts 声明文件,来获取类型推导能力。

至于其他的优点在这里就不展开了...

综上,在项目中使用 TypeScript 能让你极大地提高工作效率,并减少大量的类型错误。

TypeScript 初体验

由于目前业务项目中的框架用的是 Vue.js,众所周知 2.x 版本对于 TypeScript 支持的不是很好,所以就打算先搞个工具函数库项目试试水。

语言学习

略,这个各种资料很多,这里就不赘述了...

项目架构

  • 项目入口:src/index.ts,没有实质内容全是 export * from '...'(都是纯函数)
  • 实际代码:根据工具函数分类放在不同的文件中,例如
    • string(字符串相关)
    • env(环境探测)
    • url(链接地址)
    • ...
  • 单元测试:test/
  • 文档目录:docs/

注意:package.json 中的 sideEffects 字段要写成 false,这样可以方便业务代码打包时 tree-shaking

相关工具链

之前对于 TypeScript 一直在观望的原因之一就是相关工具链的搭配还不是很成熟。不过现在倒是基本明晰了:

TypeScript 和 babel 都可以将你的 ES6+ 代码转成 ES5。

但在 Babel v7 之前将两个独立的编译器(TypeScript 和 Babel)链接在一起并非易事。编译流程变为:TS > TS Compiler > JS > Babel > JS (again)

现在只要安装 @babel/preset-typescript 这个包就能让你完美结合 babel 和 TypeScript。

再也不用纠结到底用 tslint 还是 eslint 了,TypeScript 官方已经钦定了 eslint(Migrate the repo to ESLint #30553)。

嘿嘿,Facebook 的 jest 和 yarn(Yarn's Future - v2 and beyond #6953) 都抛弃自家的 Flow 转投 TypeScript 的怀抱了

虽然 rollup 自己用的是 rollup-plugin-typescript,不过项目中还是选了 rollup-plugin-typescript2

改造过程

  • 安装各种依赖
  • 配好各种配置文件(eslint、babel、commitlint、jest),其中最重要的是 tsconfig.json
  • 源代码的文件名后缀由 .js 改成 .ts(单测的文件也改)
  • 然后 TypeScript 的静态代码类型检查就会告诉你有什么错误
  • 看情况改代码,或者是加 ignore 注释(有时甚至需要改 tsconfig 的配置)

文档

文档标准

TypeScript 官方有一套基于 jsdoc 的文档标准 tsdoc

export class Statistics {
  /**
   * Returns the average of two numbers.
   *
   * @remarks
   * This method is part of the {@link core-library#Statistics | Statistics subsystem}.
   *
   * @param x - The first input number
   * @param y - The second input number
   * @returns The arithmetic mean of `x` and `y`
   *
   * @beta
   */
  public static getAverage(x: number, y: number): number {
    return (x + y) / 2.0;
  }
}

生成文档

于是顺藤摸瓜找到 typedoc 这个自动文档网站生成器。但这玩意儿的常规操作就是读取源代码,然后 duang 地一下,生成一堆页面。

虽然这样解决了文档生成,但是没法进行开发时实时预览文档。

自动生成

  1. 失败尝试:结合 vuepress

由于 typedoc 能导出 md 文件,所以尝试过将其结合 vuepress。不过由于 typedoc 在生成时会先清空目标目录下所有文件,折腾起来太麻烦(比如做个插件)。

  1. 下策:手动触发文档生成

没啥好说的,适用于有毅力的同学。

  1. 中策:监听源文件变化,自动触发文档生成

虽然能自动生成文档页面了,不过预览时没法自动刷新页面。

  1. 上策:借助 webpack、gulp、grunt 自动生成文档并刷新页面(正好有这三者的 typedoc 插件

说到开发时自动刷新页面,第一个自然想到 browser-sync

  • 虽说 webpack 无所不能,不过杀鸡焉用牛刀
  • grunt 这玩意儿有点儿落伍了
  • gulp 正好以前捣鼓过,加这个小需求正好

最后这里贴一下 gulpfile.js 的代码,节省一下也有相关需求同学的时间吧。

const gulp = require('gulp')
const typedoc = require('gulp-typedoc')
const browserSync = require('browser-sync').create()

const runTypeDoc = () => gulp
    .src(['src'])
    .pipe(typedoc({
        out: './docs',
        // 这个文件里都是 export * from '...' 就没必要导出文档了
        exclude: 'src/index.ts',
        tsconfig: 'tsconfig.json',
    }))

const reload = (done) => {
    browserSync.reload()
    done()
}

const runBrowserSync = (done) => {
    browserSync.init({
        server: {
            baseDir: './docs',
        },
    })
    done()
}

const watch = () => gulp.watch(
    ['README.md', 'src/*.ts'],
    gulp.series(runTypeDoc, reload)
)

gulp.task('default', gulp.series(runTypeDoc, runBrowserSync, watch))

以上 to be continued...

参考资料

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant