解析 TypeScript 宣告檔案中的路徑別名 - Resolve path alias in TypeScript declaration files
在使用 TypeScript 開發 library 或應用的過程中,會為了簡化、清楚 import 的路徑
從原本的相對路徑
import { MyClass } from '../../classes/my-class';
改為使用別名 (path alias)
定義在 tsconfig 檔案中,如:
{
"compilerOptions": {
"paths": {
"@classes/*": ["classes/*"],
"@interfaces/*": ["interfaces/*"],
"@enums/*": ["enums/*"],
"@types/*": ["types/*"],
"@services/*": ["services/*"]
}
}
}
便可將 import 路徑調整為
import { MyClass } from '@classes/my-class';
在 compile 階段,就需要能產出,讓 JS / TS 在 import 時能夠正確找到對應的路徑方式
因此,這裡以使用 TypeScript 開發套件,透過 webpack 建置的使用為情境,介紹可能遇到的解析路徑的情況與解決方式。
Webpack - Resolve Alias
為了在 JS 檔案中能 import/require 使用,會透過 webpack config 的 resolve 區塊定義 alias [參考 webpack 官方文件]
或透過套件 tsconfig-paths-webpack-plugin 便可直接以 tsconfig.json 的設定為主
如:
module.exports = {
...
resolve: {
// `extensions` is required, if `allowJs` is set in tsconfig
extensions: ['.ts', '.tsx', '.js'],
plugins: [
new TsconfigPathsPlugin({
configFile: 'tsconfig.prod.json',
extensions: ['.ts', '.js'],
}),
],
}
...
}
configFile
預設為tsconfig.json
但是,僅僅以此設定 compile 並無法直接在 TypeScript 應用中使用
會在某個.d.ts
中出現這樣的錯誤:Cannot find module '@classes/my-class' or its corresponding type declarations
因此我們需要一個酷東西
TypeScript Transformer
將產出的 .d.ts 檔案中 import 的路徑做轉換
使用的 transformer 是:typescript-transform-paths
而這個功能會需要使用 ttypescript (Tranformer TypeScript)
ttypescript 在 repository 上的說明 中描述,提供 typescript 在 compile 階段執行 transformer:
"Currently TypeScript doesn't support custom transformers in the tsconfig.json, but supports it programmatically.
And there is no way to compile your files using custom transformers using tsc command.
TTypescript (Transformer TypeScript) solves this problem by patching on the fly the compile module to use transformers from tsconfig.json."
因此,需要安裝他,並調整一下 tsconfig 與 webpack config,設定使用的 transformer (這裡就是 typescript-transform-paths)
參見 typescript-transform-paths 套件的設定說明:
{
"compilerOptions": {
// Note: To transform paths for both the output .js and .d.ts files, you need both of the below entries
"plugins": [
// Transform paths in output .js files
{ "transform": "typescript-transform-paths" },
// Transform paths in output .d.ts files (Include this line if you output declarations files)
{ "transform": "typescript-transform-paths", "afterDeclarations": true }
]
}
}
若 plugins 中兩個設定都有加上,則 webpack config 中 resolve 就不需要定義 alias 了
相對的,若 tsconfig 中 plugins 只使用
{ "transform": "typescript-transform-paths", "afterDeclarations": true }
則 webpack config 就需要處理 js 中使用的 alias
此外,webpack config 需要調整 typescript loader 使用的 compiler 為 ttypescript
module.exports = {
...
module: {
rules: [
{
test: /\.tsx?$/,
loader: require.resolve('ts-loader'),
exclude: /node_modules/,
options: {
compiler: 'ttypescript',
configFile: 'tsconfig.prod.json',
},
},
],
},
...
};
都調整好以後, compile 完成,可以查看 .d.ts 中 import 的路徑都有被替換
如此就能正常在 TypeScript 應用中使用了
References
1. "Resolve path alias in declaration files (d.ts)" - issue
2. ttypescript