遵循shadow-cljs文档执行watch后,Hello World输出位置及REPL问题咨询
问题描述
按照shadow-cljs快速开始文档搭建最小项目,配置文件shadow-cljs.edn内容如下:
;; shadow-cljs configuration {:source-paths ["src/dev" "src/main" "src/test"] :dev-http {8080 "public"} :dependencies [] :builds {:frontend {:target :browser :modules {:main {:init-fn acme.frontend.app/init}} }}}
源码路径/Users/pedro/projects/acme-app/src/main/acme/frontend/app.cljs中的代码:
(ns acme.frontend.app) (defn init [] (println "Hello World"))
执行npx shadow-cljs watch frontend构建成功,但在终端、localhost:8080页面、浏览器控制台均未看到Hello World输出;执行npx shadow-cljs node-repl调用函数也失败:
cljs.user=> (acme.frontend.app/init) ------ WARNING - :undeclared-var ----------------------------------------------- Resource: <eval>:1:2 Use of undeclared Var acme.frontend.app/init -------------------------------------------------------------------------------- cljs.user=> (main.acme.frontend.app/init) ------ WARNING - :undeclared-ns ------------------------------------------------ Resource: <eval>:1:2 No such namespace: main.acme.frontend.app, could not locate main/acme/frontend/app.cljs, main/acme/frontend/app.cljc, or JavaScript source providing "main.acme.frontend.app" --------------------------------------------------------------------------------
疑问:Hello World应该在哪里显示?是否只能在IDE的REPL中由开发者手动调用?
解答
1. Hello World的正确输出位置
浏览器控制台。因为你的build目标是:browser,配置的:init-fn会在浏览器加载编译后的JavaScript文件时自动执行,ClojureScript中的println对应浏览器的console.log,所以输出会出现在浏览器开发者工具(F12打开)的控制台面板中。
2. 当前看不到输出的原因
你缺少了关键步骤:在public目录下创建index.html文件,并引入shadow-cljs编译后的JS文件。shadow-cljs默认会将:frontend构建的:main模块编译到public/js/main.js,所以需要在public/index.html中添加:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> </head> <body> <script src="/js/main.js"></script> </body> </html>
当你访问localhost:8080时,页面会加载这个脚本,acme.frontend.app/init函数会自动执行,浏览器控制台就能看到Hello World了。
3. node-repl调用失败的原因
node-repl是用于Node.js环境的REPL,而你的build目标是:browser,编译后的代码是针对浏览器环境的,Node.js环境无法直接加载浏览器目标的命名空间。如果需要在REPL中调用这个函数,应该使用npx shadow-cljs browser-repl,连接到浏览器页面后,就能在REPL中执行(acme.frontend.app/init),此时输出会同时出现在浏览器控制台和REPL终端中。
4. 是否需要手动调用函数
不需要手动调用。只要页面正确引入了编译后的JS文件,配置的:init-fn会在脚本加载完成后自动执行。只有当你需要在开发过程中调试、重复调用函数时,才需要在browser REPL中手动调用。
内容的提问来源于stack exchange,提问作者Pedro Delfino

