Webpack是JavaScript的模组建置工具,运行在Node.js上,它可以将零散的JavaScript档案用各式工具优化并打包起来,加快网页的载入时间。Webpack也并不限于用在JavaScript上,它除了还能打包网页有用到的静态资源(如JS、CSS、图片档等)外,也还能透过TypeScript的载入器(loader)来编译并打包TypeScript程序代码。

背景知识

在开始阅读这篇文章之前,您应该要先对TypeScript程序语言和Webpack打包档案的方式有所了解。可以先阅读以下几篇文章:

TypeScript 学习之路系列文章:

https://magiclen.org/tag/typescript-学习之路/

用Webpack来打包JavaScript、SCSS/CSS、HTML网页和任意档案:

https://magiclen.org/webpack/

用了TypeScript还需要用Webpack吗?

TypeScript是一种能用来编译出JavaScript程序代码的程序语言,它「本身」并没有将多个TypeScript模组编译为一个JavaScript的功能,必须要依靠System(SystemJS)或是AMD(Asynchronous Module Definition)模组系统来整合到同一个JavaScript档案上。

例如以下的TypeScript程序:

 
console .log( 'A' );
 
export default function print () {
 
console .log( 'B' );
 
}
 
import './a' ;
 
import print from './b' ;
 
 
 
print();

我们可以在tsconfig.json设定档中的compilerOptions栏位内加上outFile栏位来让TypeScript在编译TypeScript时将JavaScript程序代码输出到同一个JavaScript档案中。此时compilerOptions栏位内的module栏位要设定为System或是AMD,也就是说,编译出来的JavaScript档案必须要运作在System和AMD的Runtime上(如果是要把该JavaScript档案放在网页浏览器上执行,就需要引用额外的JavaScript套件)。但如果我们是在Webpack下用TypeScript撰写相同的程序,就不用受到模组系统的限制,自在地使用ES6的模组系统。

另外还有一点就是,TypeScript的编译器并无法帮我们最小化并混淆编译出来的JavaScript程序,但Webpack可以做到这件事。

所以,如果您的TypeScript程序所编译出来的JavaScript程序是要用于网页浏览器上的,最好还是用Webpack来打包。

建立TypeScript的Webpack专案

加入Webpack

Webpack可以被加进现有的TypeScript的Node.js专案中,在终端机执行以下指令来安装webpackwebpack-cli这两个套件。

npm i -D webpack webpack-cli

将原本存在于package.json中的build脚本和start-dev脚本删除,然后加入新的脚本指令:


{
...
 
"scripts" : {
...
 
"build" : "webpack --mode production" ,
"dev" : "webpack --mode development" ,
"start-dev" : "webpack --mode development --watch"
 
...
}
 
...
}

执行npm run start-dev可以持续监看打包的档案有没有变动,如果有的话就自动重新打包。

再来就是在Node.js专案根目录中,新增Webpack的设定档webpack.config.js,内容可以初始如下:

 
module .exports = {
 
plugins : [],
 
module : {
 
rules : []
 
}
 
};

其它常用外挂,如clean-webpack-pluginterser-webpack-plugin可以参考这篇文章加至目前的Webpack专案中。如果还是有JavaScript的需求,可以再加上Babel。

加入TypeScript载入器

TypeScript的官方载入器为ts-loader,可以在终端机执行以下指令来安装:

npm i -D ts-loader

webpack.config.js设定档中,于module栏位的rules阵列内,加入TypeScript的载入器规则,如下:


module .exports = {
...
 
module: {
rules : [
...
 
{
test : /\.ts$/ ,
loader : 'ts-loader'
}
 
...
]
}
 
...
};

设定Webpack的进入点(Entry Point)

直接使用TypeScript档案作为Webpack的进入点。例如:


module .exports = {
...
 
entry: './src/index.ts'
 
...
};

Webpack下的tsconfig.json

tsconfig.json档案中compilerOptions栏位内的outDirmodule栏位删除,因为它们的功能已经被Webpack取代了。另外,编译目标也要根据预计在哪个网页浏览器来运行JavaScript程序来设定。

Webpack下的TypeScript程序

Webpack下的TypeScript程序,或者说被ts-loader载入的TypeScript程序,其import关键字原先是用来引用TypeScrict档案和JavaScript档案,就会变成能引用任意档案。且若不撰写副档名的话,预设会是.js,而不是.ts不过,importfrom关键字还是只能用来引用TypeScript模组。

例如:

 
console .log( 'A' );
 
export default function print () {
 
console .log( 'B' );
 
}
 
import './a.ts' ;
 
import print from './b.ts' ;
 
 
 
print();

以上的src/index.ts档案,第一行不能写成import './a';,因为我们没有src/a.js档案。同理,第二行不能写成import print from './b';,因为我们没有src/b.js档案。顺带一提,如果是直接用tsc来编译TypeScript程序,而没有用Webpack的话,from关键字后的档案路径不能有副档名(连.ts都不能有)。

当然,如果不想要手动撰写.ts副档名的话,我们可以在webpack.config.js设定档中,加上resolve设定项目,其值为一个物件,将该物件加上extensions属性,属性值设定为['.ts', '.js']如下:


module .exports = {
...
 
resolve: {
extensions : [ '.ts' , '.js' ]
}
 
...
};

如此一来,import的路径就算没有写副档名,也会先以.ts副档名来尝试,如果没有这个档案,就会以.js副档名来尝试。