{"id":13393100,"url":"https://github.com/babashka/nbb","last_synced_at":"2025-05-14T03:10:50.242Z","repository":{"id":37491938,"uuid":"389997586","full_name":"babashka/nbb","owner":"babashka","description":"Scripting in Clojure on Node.js using SCI","archived":false,"fork":false,"pushed_at":"2025-05-08T11:51:34.000Z","size":1936,"stargazers_count":882,"open_issues_count":13,"forks_count":54,"subscribers_count":12,"default_branch":"main","last_synced_at":"2025-05-08T12:39:44.106Z","etag":null,"topics":["babashka","clojure","clojurescript","interpreter","javascript","nodejs","scripting"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/babashka.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"borkdude","open_collective":"babashka","ko_fi":"borkdude","tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2021-07-27T13:39:37.000Z","updated_at":"2025-05-04T03:52:02.000Z","dependencies_parsed_at":"2022-07-12T16:19:41.806Z","dependency_job_id":"eaa7e133-f52a-4a95-9eda-54105bd3b2e8","html_url":"https://github.com/babashka/nbb","commit_stats":{"total_commits":1046,"total_committers":38,"mean_commits":"27.526315789473685","dds":0.07170172084130022,"last_synced_commit":"42399e20a72d9690779bc19c4b279a0ce094da61"},"previous_names":[],"tags_count":199,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/babashka%2Fnbb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/babashka%2Fnbb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/babashka%2Fnbb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/babashka%2Fnbb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/babashka","download_url":"https://codeload.github.com/babashka/nbb/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253074198,"owners_count":21849715,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["babashka","clojure","clojurescript","interpreter","javascript","nodejs","scripting"],"created_at":"2024-07-30T17:00:43.079Z","updated_at":"2025-05-14T03:10:45.233Z","avatar_url":"https://github.com/babashka.png","language":"Clojure","readme":"\u003cimg src=\"logo/nbb-with-name-green.svg\" width=\"250px\"\u003e\n\nNot [babashka](https://babashka.org/). Node.js babashka!?\n\nAd-hoc CLJS scripting on Node.js.\n\n## Try it out\n\nRun `npx nbb` to run nbb on your own machine, or try it in a browser on\n[Replit](https://replit.com/@eccentric-j/Node-Babashka-With-Redefs-Examples#src/cli/core.cljs)!\n\n## Goals and features\n\nNbb's main goal is to make it _easy_ to get started with ad hoc CLJS scripting\non Node.js.\n\nAdditional goals and features are:\n\n- Fast startup without relying on a custom version of Node.js.\n- Small artifact (current size is around 1.2MB).\n- First class [macros](#macros).\n- Support building small TUI apps using [Reagent](#reagent).\n- Complement [babashka](https://babashka.org/) with libraries from the Node.js ecosystem.\n\n## Community\n\n- Submit bugs at [Github Issues](https://github.com/borkdude/nbb/issues).\n- Join [Github Discussions](https://github.com/borkdude/nbb/discussions) for proposing ideas, show and tell and Q\u0026A.\n-  Join the [channel](https://app.slack.com/client/T03RZGPFR/C029PTWD3HR) on Clojurians Slack.\n- Follow news or tweet using the Twitter hashtag\n  [#nbbjs](https://twitter.com/hashtag/nbbjs?f=live).\n\n## Requirements\n\nNbb requires Node.js v14 or newer.\n\nAdditionally, in the case of downloading [Clojure\ndependencies](#Clojure-dependencies), it requires the installation of\n[babashka](https://babashka.org/).\n\n## How does this tool work?\n\nCLJS code is evaluated through [SCI](https://github.com/borkdude/sci), the same\ninterpreter that powers [babashka](https://babashka.org/). Because SCI works\nwith advanced compilation, the bundle size, especially when combined with other\ndependencies, is smaller than what you get with self-hosted CLJS. That makes\nstartup faster. The trade-off is that execution is less performant and that only\na subset of CLJS is available (e.g. no deftype, yet).\n\n## Usage\n\nInstall `nbb` from NPM:\n\n```\n$ npm install nbb -g\n```\n\nOmit `-g` for a local install.\n\nTry out an expression:\n\n``` clojure\n$ nbb -e '(+ 1 2 3)'\n6\n```\n\nAnd then install some other NPM libraries to use in the script. E.g. with the following `package.json`:\n\n``` json\n{\n  \"dependencies\": {\n    \"csv-parse\": \"^5.3.0\",\n    \"shelljs\": \"^0.8.5\",\n    \"term-size\": \"^3.0.2\",\n    \"zx\": \"^7.1.1\"\n  }\n}\n```\n\nCreate a script which uses the NPM libraries:\n\n``` clojure\n(ns example\n  (:require [\"csv-parse/sync\" :as csv]\n            [\"fs\" :as fs]\n            [\"path\" :as path]\n            [\"shelljs$default\" :as sh]\n            [\"term-size$default\" :as term-size]\n            [\"zx\" :refer [$]]\n            [\"zx$fs\" :as zxfs]\n            [nbb.core :refer [*file*]]))\n\n(prn (path/resolve \".\"))\n\n(prn (term-size))\n\n(println (count (str (fs/readFileSync *file*))))\n\n(prn (sh/ls \".\"))\n\n(prn (csv/parse \"foo,bar\"))\n\n(prn (zxfs/existsSync *file*))\n\n($ #js [\"ls\"])\n```\n\nCall the script:\n\n```\n$ nbb script.cljs\n\"/private/tmp/test-script\"\n#js {:columns 216, :rows 47}\n510\n#js [\"node_modules\" \"package-lock.json\" \"package.json\" \"script.cljs\"]\n#js [#js [\"foo\" \"bar\"]]\ntrue\n$ ls\nnode_modules\npackage-lock.json\npackage.json\nscript.cljs\n```\n\n## What does $default mean?\n\nThe `:default foo` syntax is shadow-cljs only and not supported by vanilla CLJS\n(and nbb doesn't support it either). The `$default` syntax is a recent addition\nto CLJS and should work in shadow-cljs too: this is why nbb supports it too.\n\nSee\n[here](https://clojurescript.org/news/2021-04-06-release#_library_property_namespaces)\nfor more info on that syntax.\n\nNbb implements `:require` via dynamic import (`import()` in JS). This is why you\nneed to add `$default` to imports when you want to import the default object\nfrom a module.\n\n## Macros\n\nNbb has first class support for macros: you can define them right inside your `.cljs` file, like you are used to from JVM Clojure. Consider the `plet` macro to make working with promises more palatable:\n\n\n``` clojure\n(defmacro plet\n  [bindings \u0026 body]\n  (let [binding-pairs (reverse (partition 2 bindings))\n        body (cons 'do body)]\n    (reduce (fn [body [sym expr]]\n              (let [expr (list '.resolve 'js/Promise expr)]\n                (list '.then expr (list 'clojure.core/fn (vector sym)\n                                        body))))\n            body\n            binding-pairs)))\n```\n\nUsing this macro we can make async code look more like sync code. Consider this puppeteer example:\n\n``` clojure\n(-\u003e (.launch puppeteer)\n      (.then (fn [browser]\n               (-\u003e (.newPage browser)\n                   (.then (fn [page]\n                            (-\u003e (.goto page \"https://clojure.org\")\n                                (.then #(.screenshot page #js{:path \"screenshot.png\"}))\n                                (.catch #(js/console.log %))\n                                (.then #(.close browser)))))))))\n```\n\nUsing `plet` this becomes:\n\n``` clojure\n(plet [browser (.launch puppeteer)\n       page (.newPage browser)\n       _ (.goto page \"https://clojure.org\")\n       _ (-\u003e (.screenshot page #js{:path \"screenshot.png\"})\n             (.catch #(js/console.log %)))]\n      (.close browser))\n```\n\nSee the [puppeteer\nexample](https://github.com/borkdude/nbb/blob/main/examples/puppeteer/example.cljs)\nfor the full code.\n\nSince v0.0.36, nbb includes [promesa](#promesa) which is a library to deal with\npromises. The above `plet` macro is similar to `promesa.core/let`.\n\n## Startup time\n\n``` clojure\n$ time nbb -e '(+ 1 2 3)'\n6\nnbb -e '(+ 1 2 3)'   0.17s  user 0.02s system 109% cpu 0.168 total\n```\n\nThe baseline startup time for a script is about 170ms seconds on my laptop. When\ninvoked via `npx` this adds another 300ms or so, so for faster startup, either\nuse a globally installed `nbb` or use `$(npm bin)/nbb script.cljs` to bypass\n`npx`.\n\n## Libraries\n\nSee [API](doc/api.md) documentation with a list of built-in Clojure libraries.\n\n## Dependencies\n\n### NPM dependencies\n\nAll NPM libraries loaded by a script are resolved relative to that script. When\nusing the [Reagent](#reagent) module, React is resolved in the same way as any\nother NPM library.\n\n### Clojure dependencies\n\nNote: this feature relies on the presence of the\n[babashka](https://github.com/babashka/babashka) `bb` executable in\nthe system's PATH.\n\nTo load dependencies from the Clojure ecosystem, you can create an `nbb.edn`:\n\n``` clojure\n{:deps {com.github.seancorfield/honeysql {:mvn/version \"2.2.868\"}}}\n```\n\nSimilar to `node_modules`, nbb will unpack these dependencies in an `.nbb`\ndirectory and will load them from there.\n\n### Classpath\n\nTo load `.cljs` files from local paths or dependencies, you can use the\n`--classpath` argument. The current dir is added to the classpath automatically.\nSo if there is a file `foo/bar.cljs` relative to your current dir, then you can\nload it via `(:require [foo.bar :as fb])`. Note that `nbb` uses the same naming\nconventions for namespaces and directories as other Clojure tools: `foo-bar` in\nthe namespace name becomes `foo_bar` in the directory name.\n\n## Current file\n\nThe name of the file that is currently being executed is available via\n`nbb.core/*file*` or on the metadata of vars:\n\n``` clojure\n(ns foo\n  (:require [nbb.core :refer [*file*]]))\n\n(prn *file*) ;; \"/private/tmp/foo.cljs\"\n\n(defn f [])\n(prn (:file (meta #'f))) ;; \"/private/tmp/foo.cljs\"\n```\n\nIn Python scripts there is a well-known pattern to check if the current file was the file invoked from the command line, \nor loaded from another file: the __name__ == \"__main__\" pattern. In nbb this pattern can be implemented with:\n\n```clojure\n(= nbb.core/*file* (nbb.core/invoked-file))\n```\n\n## Reagent\n\nNbb includes `reagent.core` which will be lazily loaded when required. You\ncan use this together with [ink](https://github.com/vadimdemedes/ink) to create\na TUI application:\n\n```\n$ npm install ink\n```\n\n`ink-demo.cljs`:\n``` clojure\n(ns ink-demo\n  (:require [\"ink\" :refer [render Text]]\n            [reagent.core :as r]))\n\n(defonce state (r/atom 0))\n\n(def count\n  (js/setInterval\n   #(if (\u003c @state 10)\n      (swap! state inc)\n      (js/clearInterval count))\n   500))\n\n(defn hello []\n  [:\u003e Text {:color \"green\"} \"Hello, world! \" @state])\n\n(render (r/as-element [hello]))\n```\n\n\u003cimg src=\"img/ink.gif\"/\u003e\n\n## Working with promises\n\n### Promesa\n\nWorking with callbacks and promises can become tedious. Since nbb v0.0.36 the\n`promesa.core` namespace is included with the `let` and `do!` macros. An example:\n\n``` clojure\n(ns prom\n  (:require [promesa.core :as p]))\n\n(defn sleep [ms]\n  (js/Promise.\n   (fn [resolve _]\n     (js/setTimeout resolve ms))))\n\n(defn do-stuff\n  []\n  (p/do!\n   (println \"Doing stuff which takes a while\")\n   (sleep 1000)\n   1))\n\n(p/let [a (do-stuff)\n        b (inc a)\n        c (do-stuff)\n        d (+ b c)]\n  (prn d))\n```\n\n``` clojure\n$ nbb prom.cljs\nDoing stuff which takes a while\nDoing stuff which takes a while\n3\n```\n\nAlso see [API docs](doc/api.md#promesa).\n\n### REPL\n\nIn the REPL it can be convenient to bind the resolved value of promises to a\nvar. You can do that like this:\n\n``` clojure\n(defmacro defp [binding expr]\n  `(-\u003e ~expr (.then (fn [val]\n                     (def ~binding val)))))\n\n(defp browser (.launch puppeteer #js {:headless false}))\n(defp page (.newPage browser))\n(.goto page \"https://clojure.org\")\n```\n\n## Cljs-bean\n\nSince nbb v0.1.0 [cljs-bean](https://github.com/mfikes/cljs-bean) is available.\n\nSee the [example](examples/cljs-bean/example.cljs) for an example.\n\n## Js-interop\n\nSince nbb v0.0.75 [applied-science/js-interop](https://github.com/applied-science/js-interop) is available:\n\n``` clojure\n(ns example\n  (:require [applied-science.js-interop :as j]))\n\n(def o (j/lit {:a 1 :b 2 :c {:d 1}}))\n\n(prn (j/select-keys o [:a :b])) ;; #js {:a 1, :b 2}\n(prn (j/get-in o [:c :d])) ;; 1\n```\n\nMost of this library is supported in nbb, except the following:\n\n- destructuring using `:syms`\n- property access using `.-x` notation. In nbb, you must use keywords.\n\nSee the [example](examples/js-interop/example.cljs) of what is currently supported.\n\n\u003c!-- ## Prismatic/schema --\u003e\n\n\u003c!-- Since nbb v0.5.110 [prismatic/schema](https://github.com/plumatic/schema) is --\u003e\n\u003c!-- available, if you install one additional dependency in your `package.json`: --\u003e\n\n\u003c!-- ``` clojure --\u003e\n\u003c!-- {\"dependencies\": --\u003e\n\u003c!--  {\"nbb\":\"^0.5.110\", --\u003e\n\u003c!--   \"@babashka/nbb-prismatic-schema\":\"^0.5.110\" --\u003e\n\u003c!--  } --\u003e\n\u003c!-- } --\u003e\n\u003c!-- ``` --\u003e\n\n\u003c!-- The dependency version of this library should always be the same as the version --\u003e\n\u003c!-- of nbb. --\u003e\n\n\u003c!-- After installation you can require `schema.core`: --\u003e\n\n\u003c!-- ``` clojure --\u003e\n\u003c!-- $ npx nbb -e \"(require '[schema.core :as s]) (s/validate {:a s/Int} {:a 1})\" --\u003e\n\u003c!-- {:a 1} --\u003e\n\u003c!-- ``` --\u003e\n\n\u003c!-- See [examples/prismatic-schema](examples/prismatic-schema) for an example that --\u003e\n\u003c!-- you can run directly. --\u003e\n\n\u003c!-- ## Metosin/malli --\u003e\n\n\u003c!-- Since nbb v0.5.115 [metosin/malli](https://github.com/metosin/malli) is --\u003e\n\u003c!-- available, if you install one additional dependency in your `package.json`: --\u003e\n\n\u003c!-- ``` clojure --\u003e\n\u003c!-- {\"dependencies\": --\u003e\n\u003c!--  {\"nbb\":\"^0.5.115\", --\u003e\n\u003c!--   \"@babashka/nbb-metosin-malli\":\"^0.5.115\" --\u003e\n\u003c!--  } --\u003e\n\u003c!-- } --\u003e\n\u003c!-- ``` --\u003e\n\n\u003c!-- After installation you can require `malli.core`: --\u003e\n\n\u003c!-- ``` clojure --\u003e\n\u003c!-- $ npx nbb --\u003e\n\u003c!-- Welcome to nbb v0.5.115! --\u003e\n\u003c!-- user=\u003e (require '[malli.core :as m]) --\u003e\n\u003c!-- nil --\u003e\n\u003c!-- user=\u003e (m/validate :string \"foo\") --\u003e\n\u003c!-- true --\u003e\n\u003c!-- ``` --\u003e\n\n\u003c!-- See [examples/metosin-malli](examples/metosin-malli) for an example that you --\u003e\n\u003c!-- can run directly. --\u003e\n\n## Reader conditionals\n\nNbb supports the following reader conditional platform tags: `:org.babashka/nbb` and\n`:cljs`.  Whichever is first takes priority:\n\n``` clojure\n#?(:org.babashka/nbb 1 :cljs 2) ;;=\u003e 1\n#?(:cljs 2 :org.babashka/nbb 1) ;;=\u003e 2\n```\n\n## Main function\n\nIt is possible to use the `-main` function as the software (script) start point when using the `m` parameter of `nbb` passing your software namespace.\n\n```clj\n(ns example)\n\n(defn -main\n  [\u0026 args]\n  (prn \"print in -main\"))\n```\n\nExecute:\n```\nnbb -m example\n```\n\n## Testing\n\nSee [doc/testing](https://github.com/babashka/nbb/tree/main/doc/testing).\n\n## REPL\n\n### Console REPL\n\nTo start a console REPL, simply run `nbb`.\n\n### Socket REPL\n\nTo start a socket server REPL, run:\n\n``` clojure\n$ nbb socket-repl :port 1337\n```\n\n### REPL API\n\nNbb exposes the `nbb.repl` namespace to programmatically start a REPL. See\n[API](doc/api.md#nbbrepl) for more info. An example:\n\n``` clojure\n(ns example\n  (:require [nbb.repl :as repl]\n            [promesa.core :as p]))\n\n(defn available-in-repl [] :yolo)\n\n(p/do!\n (repl/repl)\n ;; type (available-in-repl) in the REPL and it will return :yolo\n (println \"The end\"))\n```\n\nThe `repl` function returns a promise. The `promesa.core/do!` macro waits for the REPL to finish and after that `\"The end\"` is printed:\n\n``` clojure\n$ nbb example.cljs\nexample=\u003e (available-in-repl)\n:yolo\nexample=\u003e The end\n```\n\nTo launch a REPL from a Node.js script, you can use `loadString` or `loadFile`:\n\n``` javascript\nimport { loadString } from 'nbb'\nawait loadString(`\n(require '[nbb.repl :refer [repl]])\n(repl)\n`)\nconsole.log('The end!')\n```\n\n``` clojure\n$ node repl.mjs\nuser=\u003e (+ 1 2 3)\n6\nuser=\u003e The end!\n```\n\n### nREPL\n\nThe nREPL server probably still has rough edges. Please report issues\n[here](https://github.com/borkdude/nbb/issues).\n\n\nAn nREPL server can be started with:\n\n``` shell\n$ nbb nrepl-server :port 1337\n```\n\nAfter that you can connect using an nREPL client:\n\n``` clojure\n$ lein repl :connect 1337\n```\n\nand evaluate expressions.\n\nRunning nREPL in Docker container is supported with the optional `:host` argument.\n\n``` clojure\n$ nbb nrepl-server :port 1337 :host 0.0.0.0\n```\n\n#### Calva\n\nIn Calva connect to the REPL with:\n\n- Connect to a Running REPL Server not in Project \u003e ClojureScript nREPL server\n\n#### CIDER\n\nUse `cider-jack-in-cljs` as usual to start the nbb nREPL server from within an nbb project\n\nor start an nREPL server from the command line with\n\n``` shell\n$ nbb nrepl-server\n```\n\nand use `cider-connect-cljs` with a ClojureScript REPL type of `nbb` to connect to it.\n\nCIDER prior to v1.6.0, needs the following\n[workaround](https://github.com/clojure-emacs/cider/issues/3061).\n\nSee also [this article](https://benjamin-asdf.github.io/faster-than-light-memes/jacking-nbb.html) by Benjamin Scherdtner.\n\n#### Vim Iced\n\nSee [this](https://twitter.com/uochan/status/1444417505506721793) tweet.\n\n### nREPL API\n\nYou can programmatically start and stop an nREPL server through:\n\n``` clojure\n(require '[nbb.nrepl-server :as nrepl])\n(nrepl/start-server! {:port 1337})\n(nrepl/stop-server!)\n```\n\nIn a JavaScript project you can do the above through:\n\n``` javascript\nimport { loadString } from 'nbb'\n\nglobalThis.inspectMyProcess = () =\u003e {\n  return {version: process.version};\n}\n\nawait loadString(`\n\n(require '[nbb.nrepl-server :as nrepl])\n(nrepl/start-server! {:port 1337})\n\n`)\n```\n\nIf you calling this from a CommonJS module, you can use dynamic import:\n\n``` javascript\nasync function nREPL() {\n  const { loadString } = await import('nbb');\n  await loadString(`\n  (require '[nbb.nrepl-server :as nrepl])\n  (nrepl/start-server! {:port 1337})\n`);\n}\n\nnREPL();\n```\n\nAnd then you can connect with an nREPL client:\n\n``` shell\n$ node scratch.mjs \u0026\nnREPL server started on port 1337 on host 127.0.0.1 - nrepl://127.0.0.1:1337\n\n$ lein repl :connect 1337\nConnecting to nREPL at 127.0.0.1:1337\nuser=\u003e js/process.argv\n#js [\"/Users/borkdude/.nvm/versions/node/v17.8.0/bin/node\" \"/Users/borkdude/dev/nbb/scratch.mjs\"]\nuser=\u003e (js/inspectMyProcess)\n#js {:version \"v17.8.0\"}\n```\n\n## Projects using nbb\n\nThe following projects are using nbb or are supporting it as a development platform:\n\n- [nbb-test-runner](https://github.com/nextjournal/nbb-test-runner): Test runner to run nbb tests, like cognitect-labs/test-runner.\n- [publish-spa](https://github.com/logseq/publish-spa): Github action to publish Logseq SPAs using nbb-logseq.\n- [obsidian-babashka](https://github.com/filipesilva/obsidian-babashka): Run Obsidian Clojure(Script) codeblocks in Babashka and Nbb.\n- [c64core](https://github.com/chr15m/c64core): retrocompute aesthetics twitter bot.\n- [sitefox](https://github.com/chr15m/sitefox): Node.js + CLJS backend web framework.\n- [unminify](https://github.com/xfthhxk/unminify): unminifies JS stacktrace errors.\n- [nbb-serverless-example](https://github.com/vharmain/nbb-serverless-example): AWS serverless example using nbb\n- [clojure-quiz](https://github.com/prestancedesign/clojure-quiz): ClojureScript fancy terminal game\n- [monotropic](https://github.com/avelino/monotropic-theme-vscode): Monochromatic light theme for VSCode\n- [devsoutinho/labs](https://github.com/devsoutinho/labs): Flutter universal project + CLJS as backend web framework on top of GraphQL\n- [nbb-logseq](https://github.com/logseq/nbb-logseq): A custom version of nbb with additional features enabled\n- [graph-validator](https://github.com/logseq/graph-validator): Github action to validate logseq notes using nbb-logseq\n- [pg-unused-index-tui](https://github.com/darky/pg-unused-index-tui): TUI for showing unused indexes of Postgres\n\n## Examples\n\n- See the [examples](examples) directory for small examples.\n- [gallery.cljs](https://gist.github.com/borkdude/05c4f4ce81a988f90917dc295d8f306e): script to download walpapers from [windowsonearth.org](https://www.windowsonearth.org).\n- [nbb-action-example](https://github.com/borkdude/nbb-action-example): example\n  of a Github action built with nbb.\n\n## Calling nbb from JavaScript\n\nYou can load `nbb` from JavaScript. Exposed functions are `loadFile`, `loadString`, `addClassPath`, `getClassPath` and `printErrorReport`.\n\nAn example:\n\nClojure:\n``` clojure\n(ns example)\n\n(defn foo [] \"Hello\")\n\n;; this JS object is the return value of loadFile:\n#js {:foo foo}\n```\n\nJavaScript:\n``` javascript\nimport { loadFile } from 'nbb'\n\n// destructure JS object returned from .cljs file:\nconst { foo } = await loadFile('example.cljs')\n\n// execute the foo function\nfoo();\n```\n\n### Printing errors\n\nHere's an example of how to print errors from the JS API:\n\n``` javascript\nimport { loadString, printErrorReport } from 'nbb'\n\ntry {\n  await loadString(`(assoc :foo :bar)`)\n}\ncatch (e) {\n  printErrorReport(e);\n  process.exit(1);\n}\n```\n\n## Videos\n\n- [Write Node using Clojure and deploy to NPM!](https://youtu.be/_-G9EKaAyuI) by Daniel Amber and Michiel Borkent\n- [Nbb: ad-hoc scripting for Clojure on Node.js](https://youtu.be/7DQ0ymojfLg) by Michiel Borkent\n- [Create a Clojure web app using nbb and the Express node framework](https://youtu.be/uzy5ARQP3tA) by Bobby Towers\n- [🇧🇷 - Get Started: Segunda Linguagem ROUBANDO mais CORAÇÃO Dos Devs Mundialmente ](https://youtu.be/OURGmV_sG6w) by Mario Souto (DevSoutinho)\n\n## Articles\n\n- [Making a resume with nbb](https://yogthos.net/posts/2023-05-12-nbb-resume.html) by Dmitri Sotnikov\n- [Post an image to mastodon using nbb](https://mccormick.cx/news/entries/post-an-image-to-mastodon-using-nbb) by Chris McCormick\n- [Jack-in nbb](https://benjamin-asdf.github.io/faster-than-light-memes/jacking-nbb.html)\n- [Implementing a comments feature for my blog with nbb, htmx, Serverless Framework, and DynamoDB](https://nickcellino.com/blog/2022-09-03-nbb-comments.html) by Nick Cellino\n- [AWS Lambda, now with first class parentheses](https://www.juxt.pro/blog/nbb-lambda) by Ray McDermott\n- [Create a blog with Clojure, nbb, and MarkDoc](https://www.alexandercarls.de/markdoc-nbb-clojure/) by Alexander Carls\n- [Sentiment analysis with nbb](https://slimslenderslacks.github.io/nbb-sentiment) by Jim Clark\n- [Reloaded workflow with nbb and Express.js](https://dev.to/crinklywrappr/reloaded-workflow-with-nbb-expressjs-31f3) by Daniel Fitzpatrick\n- [Serverless site analytics with Clojure nbb and AWS](https://www.loop-code-recur.io/simple-site-analytics-with-serverless-clojure) by Cyprien Pannier\n- [Creating an AWS Lambda function with\n  nbb](https://blog.michielborkent.nl/aws-lambda-nbb.html) by Michiel Borkent\n- [Prerendering React in ClojureScript\n  land](https://www.arthurbrrs.me/prerendering-react-clojurescript-land.html) by\n  Arthur Barroso\n\n## Podcasts\n\n- [Nbb with Michiel\n  Borkent](https://soundcloud.com/clojurestream/nbb-with-michiel-borkent) on the\n  ClojureStream podcast with Jacek Schae\n\n## Migrating to shadow-cljs\n\nSee this\n[gist](https://gist.github.com/borkdude/7e548f06fbefeb210f3fcf14eef019e0) on how\nto convert an nbb script or project to\n[shadow-cljs](https://github.com/thheller/shadow-cljs).\n\n## Publishing an nbb project to npm\n\nSee [Publishing an nbb project to npm](doc/publish/README.md).\n\n## Creating a standalone executable with caxa\n\nSee [Creating a standalone executable with caxa](doc/caxa/README.md).\n\n## Nbb on AWS Lambda\n\nSee [Nbb on AWS Lambda](doc/aws_lambda.md).\n\n## Nbb on Google Cloud Functions\n\nSee [Nbb on Google Cloud Functions](doc/gcloud_functions.md).\n\n## [Develop](doc/dev.md)\n\n## Nbb on fly.io\n\nSee [Deploying an nbb app to fly.io](doc/fly_io).\n\n## Build\n\nPrequisites:\n\n- [babashka](https://babashka.org/) \u003e= 0.4.0\n- [Clojure CLI](https://clojure.org/guides/getting_started#_clojure_installer_and_cli_tools) \u003e= 1.10.3.933\n- Node.js 16.5.0 (lower version may work, but this is the one I used to build)\n\nTo build:\n\n- Clone and cd into this repo\n- `bb release`\n\nRun `bb tasks` for more project-related tasks.\n\n## Credits\n\n- Original babashka logo by Nikita Prokopov. Node.js modifications by MnRa.\n\n## License\n\nCopyright © 2021-2022 Michiel Borkent\n\nDistributed under the EPL License. See LICENSE.\n","funding_links":["https://github.com/sponsors/borkdude","https://opencollective.com/babashka","https://ko-fi.com/borkdude"],"categories":["Clojure","clojure"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbabashka%2Fnbb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbabashka%2Fnbb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbabashka%2Fnbb/lists"}