淺談TypeScript 用 Webpack/ts-node 執行的配置記錄
公司專案程式碼是用 TypeScript 寫的, 中間遇到有些程式碼不要放到 Node 裡面去跑.
具體場景一些路由配置, 比較大的一塊 JSON 資料定義在 TypeScript 裡.
我另外有增加指令碼, 基於這些 JSON 資料用來生成切換路由的函式.
這就需要執行 TypeScript 了, 而且可能包含一些額外的業務程式碼.
首先 Node 執行 TypeScript 有提供 ts-node 用來處理.
ts-node 會先編譯 TypeScript 程式碼到 JavaScript, 再呼叫 Node 執行.
不過這個辦法有一些問題, 一個是 TypeScript 定義的路徑配置不成功,
另一個問題更麻煩點, 就是引用到的其他的瀏覽器端程式碼因為觸發執行而引起報錯.
Webpack 打包 TypeScript Node 程式碼
我先想到了一個相對省事的方案, 就是用 Webpack 對 TypeScript 進行打包.
打包完成以後輸出 JavaScript 程式碼. 而瀏覽器程式碼打包進去, 但不一定執行.
由於 TypeScript 配置在 Webpack 當中引用有比較成熟的方案, 整個配置也寫好:
module.exports = { mode: "development", target: "node", entry: ["./example/gen-router.ts"], output: { filename: "gen-router.js", path: path.join(__dirname, "../", distFolder), }, devtool: "none", module: { rules: [ // 正常的 TypeScript 編譯方式, 我這份是拷貝的. { test: /\.tsx?$/, exclude: [/node_modules/, path.join(__dirname, "scripts")], use: [ { loader: "cache-loader" }, { loader: "thread-loader", options: { workers: require("os").cpus().length - 1, }, }, { loader: "ts-loader", options: { happyPackMode: true, transpileOnly: true, }, }, ], }, ], }, // Node 模組, 寫在 external 裡面表明不需要進行打包. 注意 commonjs 字首 externals: { prettier: "commonjs prettier", "@jimengio/router-code-generator": "commonjs @jimengio/router-code-generator", fs: "commonjs fs", path: "commonjs path", }, resolve: { extensions: [".tsx", ".ts", ".js"], modules: [path.join(__dirname, "example"), "node_modules"], // 引用 Plugin 用於讀取 tsconfig.json 檔案的配置 plugins: [new TsconfigPathsPlugin({ configFile: path.join(__dirname, "../tsconfig.json") })], }, };
基於這個配置打包以後, TypeScript 的程式碼被打包好, 並且引用響應的 Node 模組.
執行就滿足需求了.
這個方式對於其他的服務端渲染的 TypeScript 程式碼打包也是類似的.
一些特殊的依賴如果不好處理, 可以放在 Webpack 當中進行打包和對映, 得到 js.
ts-node 執行
Webpack 配置相對直接執行 TypeScript 來說會複雜一點, 所以還是 ts-node 簡單.
在依賴少的專案當中, 我改成了用 ts-node 來進行編譯執行. 配置如下
{ "compilerOptions": { "allowSyntheticDefaultImports": true, "experimentalDecorators": true, "sourceMap": true, "noImplicitAny": false, "noImplicitThis": true, "strictNullChecks": false, "moduleResolution": "node", // Node 當前還沒有支援直接執行 import/export 語法, 需要編譯到 CommonJS "module": "commonjs", "target": "es2016", "jsx": "react", "lib": ["es2016"], "types": ["node"], "baseUrl": "./example/", "paths": { "models": ["./example/models"] }, "plugins": [] } }
其實主要修改就 commonjs 那一行, 然後就是加上引數執行
ts-node -P tsconfig-node.json -r tsconfig-paths/register example/gen-router.ts
注意命令當中的 tsconfig-paths. 這裡的 -r 是指定 register.
ts-node 是先進行編譯再執行的, 但是引用的路徑沒有全都替換掉.
比如我在 tsconfig.json 裡設定了 baseUrl 然後內部引用是簡寫的, a/b/c,
拿到 Node 本身去執行的時候是不知道這個 a/b/c 對應到哪裡,
所以 tsconfig-paths/register 就提供 Node 執行時的方案, 動態查詢依賴.
至少這樣 Node register 改寫以後, 查詢模組就能正確進行了.
其他
另外 TypeScript 編譯 import 語法時會產生一個 .default 屬性.
對於 CommonJS 的模組, 這個 .default 屬性是多餘的. 所以引用的寫法要做調整.
import * as fs from "fs"; import * as path from "path"; import * as prettier from "prettier";
這個可能跟 tsconfig.json 裡其他的配置有關聯, 我沒繼續深挖.
整體的程式碼參考 https://github.com/jimengio/meson-form/pull/62/files
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援碼農教程。