TypeScript 用 Webpack/ts-node 運行的配置記錄

公司項目代碼是用 TypeScript 寫的, 中間遇到有些代碼不要放到 Node 裏面去跑.
具體場景一些路由配置, 比較大的一塊 JSON 數據定義在 TypeScript 裏.
我另外有增長腳本, 基於這些 JSON 數據用來生成切換路由的函數.
這就須要運行 TypeScript 了, 並且可能包含一些額外的業務代碼.前端

首先 Node 運行 TypeScript 有提供 ts-node 用來處理.
ts-node 會先編譯 TypeScript 代碼到 JavaScript, 再調用 Node 運行.
不過這個辦法有一些問題, 一個是 TypeScript 定義的路徑配置不成功,
另外一個問題更麻煩點, 就是引用到的其餘的瀏覽器端代碼由於觸發運行而引發報錯.node

Webpack 打包 TypeScript Node 代碼

我先想到了一個相對省事的方案, 就是用 Webpack 對 TypeScript 進行打包.
打包完成之後輸出 JavaScript 代碼. 而瀏覽器代碼打包進去, 但不必定運行.
因爲 TypeScript 配置在 Webpack 當中引用有比較成熟的方案, 整個配置也寫好:react

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 模塊.
運行就知足需求了.git

這個方式對於其餘的服務端渲染的 TypeScript 代碼打包也是相似的.
一些特殊的依賴若是很差處理, 能夠放在 Webpack 當中進行打包和映射, 獲得 js.github

ts-node 運行

Webpack 配置相對直接運行 TypeScript 來講會複雜一點, 因此仍是 ts-node 簡單.
在依賴少的項目當中, 我改爲了用 ts-node 來進行編譯運行. 配置以下json

{
  "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 改寫之後, 查找模塊就能正確進行了.app

其餘

另外 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


其餘關於積夢前端的模塊和工具能夠查看咱們的 GitHub 主頁 https://github.com/jimengio .
目前團隊正在擴充, 招聘文檔見 GitHub 倉庫 https://github.com/jimengio/h... .

相關文章
相關標籤/搜索