iT邦幫忙

2025 iThome 鐵人賽

DAY 10
0
佛心分享-IT 人自學之術

我只是不想加班:一名客服人員的GAS自救之路系列 第 10

Day10|本地開發GAS專案:使用esbuild打包(下)

  • 分享至 

  • xImage
  •  

今天這篇文章就只是流水帳地閒聊我當時試著打包side project時的心路歷程。算是拋個堪用的磚頭,如果觸及到這篇散文的讀者剛好有興趣,也可以到下文提到的開源庫,一起研究更好的方案。(我個人是挺期待能否乾脆用Deno建置GAS專案)

前言

昨天(Day09)分享了我的esbuild打包配置方案。然而,儘管GAS專案也是用JavaScript寫,由於esbuild畢竟是一個服務網頁開發的工具,比較正規的做法應該是去詳讀官方文件並寫個插件,但我這裡用了比較隨意粗暴的做法,反正它暫時works fine😎

正文

遇到問題

就我對於esbuild粗淺的認識,當前理想上format就是選esm,如果要相容於legacy專案,才依瀏覽器或Node.js端選用iifecjs

已知GAS環境不支援ES modules,於是直覺上先嘗試用iife,結果被打包成:

(() => {
  function onOpen() {
    createMenu();
  }
})();

這導致了試算表在開啟時,GAS環境call不到onOpen

嘗試社群方案

卡住了。當下我就覺得就不要自己瞎摸索,我應該要相信不是只有我會想試著用esbuild在GAS專案上。於是我找到了很多文章[^1]推薦的esbuild-gas-plugin插件。

這個esbuild插件受到gas-webpack-plugin啟發,這給我更多信心,顯然我遇到的問題,長期以來已經有一套解決方案並被實作成package。

在我查閱到esbuild插件的當下,作者英明(ひであき)さん剛好三個月內有做更新,還有人開issue提醒peer dependency的版本有已知漏洞與workaround,顯然是有受到一定人數使用並協作的插件。[^2]

遺憾的是,我當下實際使用後,並不work。雖然我相信應該是我哪裡配置錯誤,畢竟其他人都能成功使用;又或者我根本沒確認清楚這個插件是否服務我的場景。不過如同上週(Day03)聊到的,GAS環境已經實作globalThis標準,插件的let global = this是舊的解題方案。於是我就選擇不繼續探索這個插件與其相關的解法。

好的,繞了一圈,對於我自己當下的問題沒有直接幫助。[^3]

暴力解題

讓我回到問題點:simple triggers。前端專案通常入口點是main.js,並把UI作為元件單位。既然GAS專案的simple triggers在打包時會是個問題,那就把它們作為入口點,而非其它ui.js

entryPoints: ["src/triggers.js"]

雖然決定了GAS專案的入口點,對我原本僵硬的腦迴路來說算是個大突破,但依然沒有解決掉iife的問題。那這邊並沒有什麼縝密的思考,僅僅就是無腦trial and error,選擇了剩下的選項:

format: "cjs"

接下是對我而言最大的問題:我對於treeShaking的實作細節一無所知。GAS專案尷尬的是,simple triggers並不會像前端專案被引用,就算把它們集中於入口文檔,並關閉treeShaking

treeShaking: false

悲傷的是,就結果來說,當在使用SpreadsheetApp這個GAS特有全域變數來建立自定義選單時,打包後仍然會被esbuild移除handlers。

我目前比較取巧採用以下的workaroud:

import { pullFromCalendar } from "../logic/pull";
import { pushToCalendar } from "../logic/push";

(globalThis as any).pullFromCalendar = pullFromCalendar;
(globalThis as any).pushToCalendar = pushToCalendar;  

export function createMenu(): void {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu("Sync")
    .addItem("pull from calendar", "pullFromCalendar")
    .addItem("push to calendar", "pushToCalendar")
    .addToUi();
}

很醜、有any,但works fine。

總之,如此一來,我就成功把文檔拆開、又主動合併回去。雖然繞了幾圈,但至少我可以不用擔心GAS環境無法完全預料的「合併邏輯」,又能使用相對熟悉的文檔架構,讓專案可以繼續擴展。

後話

是的,今天這篇就只是個流水帳,昨天分享的配置方案的背後並沒有任何solid的原因,僅在對esbuild不夠了解的情況下,拼湊出暫時沒有bug的打包配置。

撰文時實測了一下,把它format設為esm也是一樣的output,畢竟neutral預設就是esm,而且我暴力地把treeShaking關了。不過秉持著能動就先不要改,可能等專案出現預期外的錯誤時我才會再調整打包設定。

當然,這個配置是為了我個人長期使用的專案能更舒適地擴展,如果回歸到處理行政流程自動化等工作場景,如前天(Day08)提到的,我自己是覺得沒有必要做到這麼繁重的配置。

Annotations

[^1]: 例如REALITY株式会社《Google Apps Scriptの開発体験を向上させる Now in REALITY Tech #114》

[^2]: 英明さん甚至在README.md提到了Deno。身為剛入Deno教的信徒,當下親切值+100。

[^3]: 作為side project,不同於work project,相對沒有時間壓力,至少有探索到新的社群,稍微看一下別人在做什麼,我覺得還是挺有趣的。


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

尚未有邦友留言

立即登入留言