webpack入门之ts处理(ts-loadr和babel-loader的选择)

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

简介

前面笔者在介绍TypeScript的时候,一直使用的是tsc来编译我们的TypeScript文件。但是在真实项目开发的时候,我们不会直接使用tsc来编译我们的TypeScript文件。一般我们都会结合webpack等构建工具来使用。

webpack中,编译ts文件有两种方式。

  1. 使用ts-loader编译。

  2. 使用babel-loader编译。

下面我们分别使用这两种方式来编译ts

ts-loader

我们先来说说我们熟悉的ts-loader

创建项目

首先我们创建一个文件夹,然后初始化package.json文件。

// 创建webpacktest文件夹
mkdir webpacktest

// 进入webpacktest文件夹
cd webpacktest

// 创建package.json
npm init

创建源文件

在根目录下创建tssrc目录,并创建index.ts文件。

// index.ts

const age: number = 24;

console.log(age);

const say = () => {
  console.log("hello world");
};

say();

const arr = [1, 2, 3];
console.log(arr.includes(4));

安装webpack 和 webpack-cli

我们本地安装webpack 和 webpack-cli

npm i webpack webpack-cli -D

安装ts-loader typescript

使用ts-loader编译,它其实就是使用的tsc进行编译,所以需要依赖typescriptts.config.json配置文件。

我们先来安装一下

npm i ts-loader typescript

配置webpack.config.js

然后在webpack.config.js进行配置,ts文件使用ts-loader进行处理。

module: {
  rules: [
    {
      test: /\.ts?$/,
      use: ["ts-loader"],
      exclude: /node_modules/, //排除 node_modules 目录
    },
  ],
},

配置ts.config.json

ts.config.json文件是必须要创建的,用来配置ts-loader的参数。

内容可以根据自己项目具体要求来进行配置。如果对ts的配置文件不熟悉的话可以看看笔者前面写的TypeScript学习之配置文件

这里我们简单配置下

{
  "compilerOptions": {
    "target": "es5" // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
  },
  "exclude": ["./node_modules"]
}

编译

package.josn里面配置webpack编译脚本。

"scripts": {
  "webpack1": "webpack"
}

在命令行运行 npm run webpack 就可以看到编译后的js文件了。

image.png

image.png

image.png

因为我们配置了"target": "es5",所以箭头函数编译成了普通函数。

但是inclides(),没有做任何处理。这个是不正常的,我们后面说。

生成类型申明文件

我们在ts.config.json文件,添加生成申明文件和输出目录的配置

// ...
"declaration": true, // 生成相应的 '.d.ts' 文件
"outDir": "./tsdist" // 输出目录

再次编译

image.png

可以看到,生成了类型申明文件index1.d.ts

错误检测

再来看看静态检测方面

我们在index.ts文件里面加一个未定义的变量a

// index.ts
// ...
console.log(a)

我们再次编译

image.png

可以看到,编译报错了,所以,使用ts-loader编译是会进行语法检查的。

我们再来试试babel-loader

babel-loader

有了上面的基础,我们就不需要再创建项目了。这里我们直接安装需要使用到的包。

安装babel相关包

npm i babel-loader @babel/preset-env @babel/preset-typescript core-js@3 -D

配置 babel.config.json

因为预设是从后往前执行的,所以我们这里的顺序也是有讲究的。先使用@babel/preset-typescript来识别ts,然后使用@babel/preset-env来编译js和按需引入polyfill

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

配置webpack.config.js

然后在webpack.config.js进行配置,ts文件使用babel-loader进行处理。

module: {
  rules: [
    {
      test: /\.ts?$/,
      use: ["babel-loader"],
      exclude: /node_modules/, //排除 node_modules 目录
    },
  ],
},

配置 .browserslistrc

这个主要是用来给@babel/preset-env配置编译目标环境的。

> 0.5%
last 2 versions
Firefox ESR

编译

在命令行运行 npm run webpack 就可以看到编译后的js文件了。

image.png

image.png

image.png

image.png

前面和使用ts-loader一样,箭头函数被转成普通函数了。

但是它多了引入polyfill这一步

./node_modules/core-js/internals/array-includes.js

所以使用babel-loader来处理ts的好处就是能动态按需引入polyfill。这个在ts-loader是不支持的,如果需要引入polyfill,需要在入口文件全量引入polyfill

如果还想进一步优化,抽离公共的辅助函数的话我们还可以配置@babel/plugin-transform-runtime插件。这个就不再细说了。可以看看笔者前面写的webpack入门之js处理(babel、babel polyfill)

生成类型申明文件

使用babel-loader的时候并没有使用到tsc,也不会读取ts.config.json文件配置,所以使用babel-loader是不能生成类型申明文件。

再来看看静态检测方面

错误检测

我们在index.ts文件里面加一个未定义的变量a

// index.ts
// ...
console.log(a)

我们再次编译,没报错,对,你没看错。babel-loader只会负责编译,并不会进行语法检查。

如果需要语法检测,需要单独配置命令

{
  "scripts": {
    "check": 'tsc --noEmit'
  }
}

可以使用noEmit参数,不生成输出文件来做语法检测。

这个命令可以单独跑,也可以结合git-hooks在每次提交的时候自动运行来做检测。

总结

polyfill

ts-loader不支持polyfill的按需引入,如果需要polyfill需要在入口全量引入。

babel-loader是可以按需引入polyfill。并且还可以配置@babel/plugin-transform-runtime插件来抽离公共辅助函数。

类型申明文件

ts-loader支持生成类型申明文件,只需要在ts.config.json中配置即可。而babel-loader不支持。

错误检测

ts-loader支持错误检测,如果语法有问题会编译不成功。babel-loader是不支持,需要单独利用tsc单独配置。

因为 tsc 的类型检查是需要拿到整个工程的类型信息,需要做类型的引入、多个文件的 namespace、enum、interface 等的合并,而 babel 是单个文件编译的,不会解析其他文件的信息。所以做不到和 tsc 一样的类型检查。

语法支持

截止到目前为止,babel-loader还不支持如下两种ts语法。

  1. 常量枚举
const enum A {
  X,
}
  1. 历史遗留风格的 import/export 语法

import foo = require(...) 和 export = foo

ts-loader 默认支持很多 es 的特性,但是不支持还在草案阶段的特性。babel-loaderpreset-env 支持所有标准特性,并且还可以通过配置插件的方式来支持更多还未进入标准的特性。

{
    plugins: ['@babel/proposal-xxx'],
    presets: ['@babel/presets-env', {...}]
}

编译速度

ts-loader编译速度慢,因为它有类型检查这一步。babel-loader编译速度快。

构建体积

babel-loader打包后的体积更小。因为它支持按需polyfill@babel/plugin-transform-runtime插件的配置。

其次babel-loader可以通过.browserslistrctarget精确配置需要适配的浏览器。而ts-loader只能配置target,其值有'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT',相对没那么精确。所以对打包体积也会有影响。

后记

看到这,小伙伴们应该能做出选择了吧。其实也没有孰强孰弱,各有优势,小伙伴们可以根据自己项目具体情况来选择使用。

感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!

猜你喜欢

转载自juejin.im/post/7127206384797483044