iT邦幫忙

2025 iThome 鐵人賽

DAY 11
0

終於來到名為「本地開發GAS專案」的舞台劇的最後一幕,主要是因為我有實作的就只到這裡。其實原本想把這部分放到最後一週再聊,畢竟後面幾天我想分享的故事,應該都沒有esbuild和TypeScript的戲份😅

前言

前兩天(Day09&Day10)分享了我個人隨興的esbuild配置,讓我掌握自己合併文檔的主動權,快樂地在GAS專案玩起熟悉的import/export遊戲。如果還想要更痛更快樂,我們可以再加上JavaScript社群最陌生的老朋友:TypeScript。

正文

TypeScript超主觀簡介

這一小段是寫給來自Python或其他語言背景、因為我個人無法想像的原因而需要寫GAS專案的開發者,JavaScript生態系的讀者可以跳至實作步驟。[^1]

直覺上,就字面上來說,TypeScript就是JavaScript加上型別,有點類似C++之於C。我自己的心智地圖,更偏向把它們放在SCSS之於CSS的關係:

  1. 瀏覽器只看得懂、只能執行JavaScript和CSS。
  2. 開發者必須使用編譯器將SCSS與TypeScript轉換回JavaScript與CSS。
  3. 常常SCSS與TypeScript先有的feat,後來才被JavaScript與CSS納入或以另一種實作方式借鑒。

Day02提到的,撰文的當下,採用ES標準、實作JavaScript的引擎之中,市占率最高的是Google陣營的V8引擎;TypeScript則是微軟陣營為了自家生態系的需求所擴充的一系列額外機制,其中type只是TypeScript這個產品的識別特色,而不僅僅處理type。例如早年async/await的語法糖、箭頭函式等等這類現在屬於JavaScript的語法,都是TypeScript率先實作。此外,不同於社群色彩更強的SCSS,TypeScript的很多功能也依賴於微軟生態系的VS Code。就我的觀點,TypeScript不僅僅是語言,更是一套服務。

那麼,是否有必要導入TypeScript?我覺得可以由GAS環境負擔的行政自動化場景都沒必要。就算你是偏好強型別(例如Rust的開發者),也得面對靜態型別的限制與TypeScript各種workaround,它只在編譯前、編譯時檢查,無法在執行時檢查。

實作步驟

①安裝TypeScript

使用你偏好的套件管理工具進行安裝,例如pnpm或npm:

  • pnpm add -D typescript
  • npm install -D typescript

②安裝GAS環境的type

  • pnpm add -D @types/google-apps-script
  • npm install -D @types/google-apps-script

③設定tsconfig.json[^2]

{
  "compilerOptions": {
    // 只做型別檢查,編譯交給esbuild
    // 官方建議若esbuild則搭配ESNext
    "noEmit": true,
    "module": "ESNext",

    // globalThis被正式納入ECMAScript標準是在ES2020
    // GAS環境換V8引擎也是在2020年
    "target": "ES2020",
    "lib": [
      "ES2020"
    ],
    
    // 讓編譯器讀懂GAS環境特有型別
    "types": [
      "google-apps-script"
    ],

    // 啟用所有嚴格型別檢查選項,包含ES的strict mode與TS的其它檢查
    "strict": true
  },
  "include": [
    "src"
  ]
}

That's all. 把文檔貼上很快,但我每次導入TypeScript都還是設定好久。[^3]相比於esbuild,TypeScript沒什麼需要斟酌的部分,主要就是記得下載由社群整理好的GAS環境的型別。

部署腳本

包含前幾天的配置,對於.ts文檔的處理流程會是:

  1. 開發者撰寫TypeScript
  2. TypeScript編譯器檢查
  3. esbuild編譯成JavaScript
  4. esbuild打包成一個文檔
  5. clasp將文檔包進json並標註type
  6. clasp推送至GAS環境
  7. GAS環境依標註的type於雲端IDE顯示.gs

我個人目前會用Node.js腳本,針對正式環境與測試環境分別放進對應的文檔:

  fs
    .copyFile("config/._appsscript.json", "dist/appsscript.json")
    .then(() => console.log("└─dist/appsscript.json")),
  fs
    .copyFile(`config/_config.${env}.ts`, "src/config/config.ts")
    .then(() => console.log("└─src/config/config.ts")),
  fs
    .copyFile(`config/._clasp-${env}.json`, ".clasp.json")
    .then(() => console.log("└─.clasp.json")),

並在package.json設定指令:[^4]

"scripts": {
    "env": "node scripts/switch-env.js",
    "build": "node scripts/build.js",
    "deploy:stag": "pnpm run env stag && tsc && pnpm run build && clasp push",
    "deploy:prod": "pnpm run env prod && tsc && pnpm run build && clasp push"
}

如此一來,就可以使用pnpm run deploy:stagpnpm run deploy:prod跑完上述的處理流程。

更多配置?

如果有讀者竟然還想繼續追加負重的話,可以參考debiruさん所配置的clasp範例庫,他甚至加上了Jest……真的不愧是主張「HTMLには魂が宿っている」的職人。身為沒有寫過單元測試的citizen developer,儘管完全不懂QA流程,但光是想像在GAS環境要用Jest模擬測試環境,那難度肯定遠比esbuild還可怕。[^5]

後話

從上週末(Day07)的後話可以看出來,我原本打算把TypeScript與esbuild的額外配置放到最後一週再來談,畢竟在常見的行政自動化場景,這些額外配置並非必要。

只是我是一邊寫稿一邊瀏覽、回顧自己既有的專案配置,就順著回憶寫完了。我個人實際使用這套配置,目前為止依然覺得TypeScript可以放到最後才導入。[^6]

是說,esbuild是用Go寫的,而半年前TypeScript開始用Go改寫[^7],感覺都是在擺脫Node.js的瓶頸。JavaScript生態系始終圍繞在如何更好地管理、整合library,包含npm這個巨大的資安弱點。從原本以自舉為主的工具鏈[^8],漸漸有轉向Go、Rust等跨語言重寫的趨勢?

Annotations

[^1]: 在這個後GenAI時代,各位有經驗的開發者們一定可以有效率地獲取各種客觀資訊,這裡索性就放大我的主觀角度。

[^2]: https://www.typescriptlang.org/tsconfig

[^3]: 突然想到前陣子看到一則關於TypeScript的貼文,底下有人留言分享他每個案子有三分之一時間都在寫config。我真的很好奇這是不是JavaScript生態系獨有的特色,其他背景的開發者們有興趣閒聊的話,歡迎DM我。

[^4]: 由於env是一個保留字,通常不推薦用來當指令名,這也是為什麼就算pnpm相比npm可以省略run,通常也不建議省略。

[^5]: 就我個人接觸到的有限資訊,主觀覺得日本社群有好多這種非主流實作嘗試。給人一種不需要急著追逐市場趨勢,不因為沒有商業價值就急著否定的オタク印象。一直以來很好奇到底是什麼支撐了這麼龐大的社群文化。

[^6]: 也正因為這篇文章的實用價值不高,所以假想受眾時,乾脆徹底預設讀者皆為前GenAI時代就有開發經驗的人,寫起來意外地比前面幾篇文章更順暢。說到底這我這系列文章的定位真的很尷尬,到底誰會Python專案或modern web寫著寫著,會突然需要碰GAS專案🫠

[^7]: https://devblogs.microsoft.com/typescript/typescript-native-port/

[^8]: 例如Babel用JavaScript寫JavaScript、Webpack用JavaScript打包JavaScript、TypeScript用TypeScript編譯TypeScript。


上一篇
Day10|本地開發GAS專案:使用esbuild打包(下)
系列文
我只是不想加班:一名客服人員的GAS自救之路11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言