1

一般前端代码崔主要是为了在浏览器环境运行,
在有服务端渲染的需求的时候, 也会兼容一下代码的加载,
比如同一个 React 组件, 同样可以用于服务端渲染,
而其中涉及到浏览器 API 的代码, 可以选择不执行, 经典的:

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

如果是 ClojureScript 当中遇到此类的代码, 也类似:

(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 的,

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

至少在我没搞清楚 ns 到底展开称为什么样的代码的情况下..

解决方案

于是我想到说用 shadow-cljs 对 js 模块做重定向的功能的做法,
我在打包 :node-script 这个执行脚本的时候, 不要使用 alertify.js 的代码了,
转而使用一个空的 js 文件, 这样就不会去访问 document 然后出错.
参考文档上的用法, 应该是这样写的:

: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 是生效的地方, 我把模块指向了一个本地的文件.

不过实际使用遇到的问题, 问了作者, 他在 :node-script 这个环境没开这个选项,
https://clojureverse.org/t/ho...
然后升级到了 2.3.22 版本就支持了, 所以就搞定了.


题叶
17.3k 声望2.6k 粉丝

Calcit 语言作者


引用和评论

0 条评论