關於在 ClojureScript 當中引入依賴 document 對象的包(筆記)

通常前端代碼崔主要是爲了在瀏覽器環境運行,
在有服務端渲染的需求的時候, 也會兼容一下代碼的加載,
好比同一個 React 組件, 一樣能夠用於服務端渲染,
而其中涉及到瀏覽器 API 的代碼, 能夠選擇不執行, 經典的:前端

if (typeof window != undefined) {
  // do something
}

若是是 ClojureScript 當中遇到此類的代碼, 也相似:node

(if (exists? js/window)
  (comment "do soemthing"))

問題

這一次是我引用了一個 https://alertifyjs.org/ 的模塊,
這個 js 模塊沒有處理好. 對, 我是從 ClojureScript 引用了 js 模塊,
而後, 在 shadow-cljs 打包完成運行的時候遇到了這樣的問題,瀏覽器

ReferenceError: document is not defined

若是是 js, 我在 require("alertify.js") 的寫法前面加 if 就行了.
雖然對於 import 語法不能用 if, 可是打包工具通常都支持 CommonJS 的.
而在 ClojureScript 當中問題比較明顯, 由於 ns 是個 Macro,
意味着代碼在執行以前會被代碼再進行處理, 我是不能隨便加 if 的,app

(ns app.main
  (:require ["alertify.js" :as alertify]))

至少在我沒搞清楚 ns 到底展開稱爲何樣的代碼的狀況下..工具

解決方案

因而我想到說用 shadow-cljs 對 js 模塊作重定向的功能的作法,
我在打包 :node-script 這個執行腳本的時候, 不要使用 alertify.js 的代碼了,
轉而使用一個空的 js 文件, 這樣就不會去訪問 document 而後出錯.
參考文檔上的用法, 應該是這樣寫的:ui

:page {:target :node-script
       :output-to "target/page.js"
       :js-options {:resolve {"alertify.js" {:target :file
                                             :file "entry/alert-ssr.js"}}}
       :main app.page/main!
       :devtools {:after-load app.page/main!}}}}

:js-options 是生效的地方, 我把模塊指向了一個本地的文件.ssr

不過實際使用遇到的問題, 問了做者, 他在 :node-script 這個環境沒開這個選項,
https://clojureverse.org/t/ho...
而後升級到了 2.3.22 版本就支持了, 因此就搞定了.code

相關文章
相關標籤/搜索