• ts-loader:将ts转为js,再使用babel将js转为低版本js;
  • @babel/preset-typescript:它是直接移除TypeScript,转为JS,这使得它的编译速度飞快,并且只需要管理Babel一个编译器就行了。
  • 二、方案对比

    首先我们需要安装 webpack、webpack-cli、typescript 随便写一点ts,用于打包测试:

    // index.ts
    class Student {
      name: string
      age: Number
      constructor(name: string, age: Number) {
        this.name = name
        this.age = age
      greet() {
        console.log(`Hello, my name is ${this.name}`)
    const testPromise = (): Promise<string> => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('1')
        }, 1000)
    const studentA = new Student('a', 20)
    studentA.greet()
    testPromise().then(data => {
      console.log('data', data)
    

    1.使用方法法对比

    1)ts-loader:

    先安装 ts-loader : npm install ts-loader --save-dev 在项目中配置webpack.config.js:

    const path = require('path')
    module.exports = {
      mode: 'development',
      entry: './index.ts',
      output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './dist')
      resolve: {
        extensions: [".ts", ".tsx", ".js"]
      module: {
        rules: [
            test: /\.tsx?$/,
            exclude: /node_modules/,
            loader: 'ts-loader'
      plugins: []
    

    然后需要设置tsconfig.json:

    "compilerOptions" : { "module" : "commonjs" , "sourceMap" : true , "target" : "es5" , "lib" : [ "es5" , "dom" , "es2015.promise"

    lib根据具体代码和应用场景还可以配置其他参数:

    接下来打包后可以看到打包代码:

    实际const、箭头函数之类的已经转成了es5,而 promise可能在低版本浏览器不兼容,那么设置babel将一些不兼容的语法转为es5:

    npm install core-js
    npm install --save-dev babel-loader @babel/core @babel/cli @babel/preset-env
    npm install --save @babel/polyfill
    

    设置.babelrc;

    "presets" : [ "@babel/preset-env" , "corejs" : "3" , "useBuiltIns" : "usage"

    在webpack.config.js中设置babel-loader处理js

    module: {
        rules: [
            test: /\.tsx?$/,
            exclude: /node_modules/,
            loader: ['babel-loader', 'ts-loader']
    

    再进行打包:

    可以看到promse这类的方法已经有了定义,这样不会造成低版本不兼容的问题了,当然如果你已经设置了 高版本的浏览器,这部分代码也不会被打包进来,因为高版本浏览器已经可以直接使用promise。

    2)@babel/preset-typescript:

    和上面相关bebel的插件基本相同

    npm install core-js
    npm install --save-dev babel-loader @babel/core @babel/cli @babel/preset-env
    npm install --save @babel/polyfill
    npm install --save-dev @babel/preset-typescript
    

    就多了 @babel/preset-typescript webpack.config.js中直接使用了babel-loader:

    const path = require('path')
    module.exports = {
      mode: 'development',
      entry: './index.ts',
      output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './dist')
      module: {
        rules: [
            test: /\.tsx?$/,
            exclude: /node_modules/,
            loader: ['babel-loader']
      plugins: []
    

    .babelrc中也只多了 @babel/preset-typescript

    "presets" : [ "@babel/preset-env" , "corejs" : "3" , "useBuiltIns" : "usage" "@babel/preset-typescript"

    执行打包,发现bundle.js也是打包了promise。
    这里使用 @babel/preset-typescript 的时候专门删了tsconfig.js,发现依然可以打包成功,但是 ts-loader 是一定要设置tsconfig.js的,因为我只是做了一下测试,所以删除了,实际项目中还是要设置tsconfig.js。

    2.打包时间比较

    两种方案中ts代码完全相同:
    ts-loader 打包时间:

    大概 1000ms

    @babel/preset-typescript 打包时间:

    大概500ms 感觉打包速度上提升还是很明显的,打包的大小是大致一样。

    3.使用ts封装npm工具包比较

    如果我们需要使用ts来开发一些开发工具类的npm包,其实我还是更推荐 ts-loader

    我们先新建两个项目,然后随便写一点测试代码:

    1)ts-loader:

    ts-build-loader 为使用 ts-loader 来开发的npm包:

    ts-build-loader:  src/index.ts
    export function addFn(a: number, b: number): number {
      return a + b
    

    在tsconfig.json中需要配置生成项目声明文件:

    "compilerOptions" : { "module" : "commonjs" , "sourceMap" : true , "target" : "es5" , "declaration" : true , // 将生成.d.ts文件 "outDir" : "./dist" , "lib" : [ "es5" , "dom" , "es2015.promise" "exclude" : [ "./dist"

    此时我们可以执行 npm run build 看下打包后的代码:

    一个项目主要方法的js和一个声明文件index.d.ts。
    另外如果我们需要使用声明文件在我们使用时提示,你还是需要在package.json里指定主声明文件:

    2)@babel/preset-typescript:

    ts-build-babel 为使用 @babel/preset-typescript 开发的npm包:

    ts-build-babel:  src/index.ts
    export function subFn(a: number, b: number): number {
      return a - b
    

    执行 npm run build

    即使我在 tsconfig.json 中已经设置了 declaration 也没有项目的声明文件。

    最后我们在这两个项目的 package.json 中设置main为打包后的js:

    此时两种不同打包方案的npm包已经简单实现了。

    再新建一个项目 test-ts-npm 用来测试我们的工具是否可用,我们分别在 ts-build-loader ts-build-babel 中执行 npm link ,然后在 test-ts-npm 中分别链接这两个包: npm link ts-build-loader、 npm link ts-build-babel

    在项目中简单的安装一下ts,新建一个 index.ts 文件测试前面写好的两个工具类:

    test-ts-npm:  index.ts
    import { addFn } from 'ts-build-loader'
    import { subFn } from 'ts-build-babel'
    let n = addFn(1, 1)
    let m = subFn(1, 1)
    console.log(n)
    console.log(m)
    

    tsc index.ts 编译一下ts,再 node index.js 执行编译后的js:

    证明这两个包都是可用的,然后我们就最简单的对比一下用法就可以发现 ts-loader 开发npm包的优势是很明显的:

  • 1.引入没有报错提示:
  • 当我们使用了 ts-loader 打包项目时由于已经生成了声明文件,所以引用这里不会报无法找到模块之类的错误;

  • 2.更智能的错误提示:当我们故意写错一个参数时:
  • 很明显 ts-loader 打包后的代码由于有index.d.ts文件,在我们使用方法不正确时,vscode会提示相应错误信息。在开发过程中,这样的方式显然是更合理的。

    最后,还有了几个疑问没有解决:

  • @babel/preset-typescript 能否通过设置生成项目的声明文件;
  • 通过上面的两种方案对比:

    如果项目为业务逻辑相关,可以考虑使用 @babel/preset-typescript ,配置更简单,而且打包速度更快一点; 而 ts-loader 在配置过程中还是遇到了很多坑的,比如 tsconfig.json 中lib没有设置导致报错,而在转es5实际也是用babel处理es6的方案解决,这样直接使用 @babel/preset-typescript 感觉会更加清晰。

    如果是作为开发相关工具包或组件库,还是更推荐用 ts-loader ,这种打包后可以自动生成项目声明文件,在其他项目中引入会有更友好的开发体验。