Webpack是JavaScript的模組建置工具,運行在Node.js上,它可以將零散的JavaScript檔案用各式工具優化並打包起來,加快網頁的載入時間。Webpack也並不限於用在JavaScript上,它除了還能打包網頁有用到的靜態資源(如JS、CSS、圖片檔等)外,也還能透過TypeScript的載入器(loader)來編譯並打包TypeScript程式碼。



背景知識

在開始閱讀這篇文章之前,您應該要先對TypeScript程式語言和Webpack打包檔案的方式有所了解。可以先閱讀《TypeScript學習之路》系列文章

還要會使用Webpack來打包JavaScript、SCSS/CSS、HTML網頁和任意檔案,可以參考以下文章:

用了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.js";
import print from "./b.js";

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中的腳本指令,如下:

{
    ...

    "scripts": {
        ...

        "build:webpack": "webpack --mode production",

        ...
    }
  
    ...
}

再來就是在Node.js專案根目錄中,新增Webpack的設定檔webpack.config.ts,內容可以初始如下:

import { Configuration } from "webpack";

const config: Configuration = {
    plugins: [],
    module: { rules: [] },
    resolve: { extensionAlias: { ".js": [".ts", ".js"] } },
};

export default config;

若您的ESlint有使用import/no-extraneous-dependencies規則,記得一定要將webpack.config.ts設為devDependencies的例外。

resolve: { extensionAlias: { ".js": [".ts", ".js"] } }可以讓Webpack看到副檔名為.js的檔案路徑時,先以.ts作為副檔名來嘗試,如果不存在,再以.js來嘗試。如果您的TypeScript不是使用Node16模組設定,要在resolve中加上extensions: [".ts", ".js"]以支援import的路徑無副檔名時的情形。

Webpack預設的輸出目錄為專案根目錄下的dist目錄,如果您的Typescript原先也是輸出到這個目錄的話,要換成別的。

加入TypeScript載入器

TypeScript的官方載入器為ts-loader,不過筆者偏好直接使用Babel來載入TypeScript和JavaScript。

在終端機執行以下指令來安裝Babel:

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

webpack.config.ts設定檔中,於module欄位的rules陣列內,加入TypeScript的載入器規則,如下:

const config: Configuration = {
    ...

    module: {
        rules: [
            ...

            {
                test: /\.ts$/i,
                use: [
                    {
                        loader: "babel-loader",
                        options: { presets: ["@babel/preset-env", "@babel/preset-typescript"] },
                    },
                ],
            },
            {
                test: /\.js$/i,
                use: [
                    {
                        loader: "babel-loader",
                        options: { presets: ["@babel/preset-env"] },
                    },
                ],
            },

            ...
        ]
    }

    ...
};

設定Webpack的進入點(Entry Point)

直接使用TypeScript檔案作為Webpack的進入點。例如:

const config: Configuration = {
    ...

    entry: "./src/index.ts"

    ...
};