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
,这种打包后可以自动生成项目声明文件,在其他项目中引入会有更友好的开发体验。