怠惰的下大雨的週一晚上,吃完麥當勞大薯後,才趕在半夜前交付這篇文章😅 今天除了介紹clasp的
filePushOrder
功能以外,也會分享我自己對於GAS專案的檔案拆分偏好。
在上週(Day02)有提到,儘管GAS環境已於2020年從Rhino引擎轉移到V8引擎,但仍有部分標準尚未支援,例如ES6 modules就不能在GAS環境使用。[^1]今天打算進一步談GAS環境的這個特性,還有分享我個人的應對方案。
為什麼GAS環境明明已改用V8引擎,卻仍不支援ES6 modules呢?
其實,GAS環境會默默做一件事:把所有.gs
與.js
文件合併成一個大文件。或者更精確地說,以Day06聊到的GAS環境的文檔類型定義,會將type
是SERVER_JS
這個類型的文檔都視為共享同一個全域命名空間的整體。
所以,拆分成多個文件僅僅只是視覺上的區隔,如果複數文件裡定義了同名的函式或變數,較晚被合併的會覆蓋前面的;如果合併順序錯誤,也可能導致函式無法正確觸發。
對習慣瀏覽器環境和Node.js環境的開發者來說,可能會稍微不習慣這個特性。換言之,通常我們拆成很多個文檔與目錄,是為了可維護性和更方便協作,但在GAS環境下,過度拆分文檔反而可能造成維護困難。
那GAS環境會如何決定文件合併的先後順序呢?原則上是依據檔名升冪排序,也有很多開發者分享可以在檔名前標上編號。由於我不太信賴GAS環境會完全依這個原則[^2],所以這裡依我個人開發過的專案規模,分享偏好的應對方案:
首先是小型專案,例如單一或數個試算表的自動化操作,我通常只會拆成main.js
、helper.js
與ui.js
。
接著是中型專案,我會使用這幾天分享的clasp工具的filePushOrder
功能[^3],在.clasp.json
上寫入設定,將部分檔案指定為優先上傳。例如:
{
"scriptId": "scriptId",
"rootDir": "dist",
"filePushOrder": [
"dist/config.js",
"dist/helper.js",
"dist/ui.js"
]
}
至於大型專案,我在完成TypeScript配置後,通常會再用esbuild打包,這樣就可以正常使用ES modules。不過目前只有於僅供自己使用的長期專案有做到這麼重的配置,以個人於前公司實作過的專案,都還沒有複雜到需要配置TypeScript與esbuild。
回顧我最初剛開始寫GAS專案時,並沒有意識到它不支援ES6 modules,可能是因為當時同時有在寫VBA,儘管覺得哪裡怪怪的、但又說不出哪裡怪,直到拆分比較多文件後,才突然察覺不對勁😅。如果觸及到這篇文章的你剛好也是先有前後端開發經驗,希望可以幫助到你少踩一個坑。
[^1]: 官方文件:「Caution: ES6 modules are not yet supported.」
[^2]: 畢竟合併文件只是一個助於理解的形象化的說法,我還沒有找到關於此機制實作細節的官方文件。換言之,這些討論都是源自於Stack Overflow等社群的觀察,而非官方對於底層實作的contract。
[^3]: 官方文件:「Specifies the files that should be pushed first, useful for scripts that rely on order of execution. All other files are pushed after this list of files, sorted by name. Note that file paths are relative to directory containing .clasp.json. If rootDir
is also set, any files listed should include that path as well」