Slide 1

Slide 1 text

Michiel Borkent @borkdude 2022-03-22

Slide 2

Slide 2 text

• ClojureScript scripting tool for Node.js (14.x+) • Interpreted via SCI, similar to babashka • Developed since September 2021 • Can be used to script against any library in Node.js ecosystem, including ES6 • Included CLJS libraries: promesa, js-interop, reagent, ... $ npx nbb user=> (require '["child_process" :as cp]) nil user=> (str (cp/execSync "echo dude")) "dude\n" user=> (require '[applied-science.js-interop :as j]) 
 nil 
 user=> (j/get-in (clj->js {:a {:b {:c :foo}}}) [:a :b :c]) "foo"

Slide 3

Slide 3 text

Node.js: the good parts • Startup time Large ecosystem: many useful libraries • Quickly write small web apps • Browser testing: Playwright, Puppeteer • CLI/TUI apps • Cron jobs (bots), cloud functions (AWS, Google), gulp ClojureScript...

Slide 4

Slide 4 text

CLJS scripting options • Planck • Self-hosted CLJS on JSCore • time planck -e '(+ 1 2 3)' => ~350-500ms • No NPM / Node.js integration

Slide 5

Slide 5 text

CLJS scripting options • Lumo • Self-hosted CLJS on Node.js • time lumo -e '(+ 1 2 3)' => ~150-270ms • Uses custom Node.js version/image (v11.13.0) • Does have NPM / Node.js integration • No ES6 modules support • Unmaintained

Slide 6

Slide 6 text

CLJS scripting options • Nbb • Interpreted CLJS (SCI) on Node.js • time nbb -e '(+ 1 2 3)' => ~120-180ms 
 (could be reduced by eliding docstrings, etc.) • Uses Node.js version from system (14+ recommended) • ES6 modules support • Currently actively developed and maintained

Slide 7

Slide 7 text

Nbb use cases • Command line apps / scripts • TUI apps (text ui) • Small web applications (sitefox) • UI testing (Playwright, Puppeteer) • AWS Lambda / Google Cloud Functions • Learning Clojure! • Basically anything Node.js but using Clojure

Slide 8

Slide 8 text

TUIs (ink + Reagent)

Slide 9

Slide 9 text

Ad hoc scripting: 
 parse ical fi le

Slide 10

Slide 10 text

Sitefox: nbb-compatible CLJS web framework

Slide 11

Slide 11 text

Playwright (UI tests) See https://github.com/nextjournal/clerk/blob/main/ui_tests/playwright_tests.cljs

Slide 12

Slide 12 text

https://www.loop-code-recur.io/simple-site-analytics-with-serverless-clojure/

Slide 13

Slide 13 text

Learning Clojure: Exercism

Slide 14

Slide 14 text

Babashka vs nbb • Does nbb replace bb? 
 > No, complementary. • Does nbb mean bb is less actively developed? 
 > No. Both based on SCI, bene fi t from shared code-base. • Use case for nbb > bb:
 
 "Does bb have a library / pod for ...?" • Parsing excel sheets? • Parsing iCal fi les? • > Not currently, but nbbjs + a Node.js library might do the trick!

Slide 15

Slide 15 text

Projects using SCI • Babashka (JVM / GraalVM) • Nbb (Node.js) • Scittle (browser) • Obb (macOS) • ...

Slide 16

Slide 16 text

Macros

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Promises: promesa • Ubiquitous in JavaScript and Node.js • Trend: APIs tend to become more promise-based than callback based • Doable via raw JS interop • But there's an awesome library with convenient macros/ functions which makes it easier: promesa • Built-in to nbb: "the way" to deal with promises

Slide 20

Slide 20 text

Promesa

Slide 21

Slide 21 text

nREPL • Built-in nREPL implementation, initial implementation by viesti • $ nbb nrepl-server :port 1337 • cider-connect localhost 1337
 + use clojure-mode (see issue) • Calva has a built-in nbb jack-in!

Slide 22

Slide 22 text

REPL completions

Slide 23

Slide 23 text

Console REPL $ npx nbb 
 Welcome to nbb v0.2.4! 
 user=> (range) 
 ^C"Error: Script execution was interrupted by `SIGINT`" • Uses Node VM which can be killed with SIGINT • Technique could also be applied to nREPL server

Slide 24

Slide 24 text

Require JS libs: ES modules • Trend: CJS modules -> ES module s • Not supported in CLJS Compiler with Node target since that compiles into js/require • Not supported in lumo

Slide 25

Slide 25 text

Require JS libs: ES modules

Slide 26

Slide 26 text

Require JS libs • Always use string to denote npm library (shadow-cljs convention adopted by nbb):
 
 (require '["fs" :as fs]) 
 
 (ns example (:require ["asciidoctor$default" :as asciidoctor])) • Implemented using dynamic import: (js/import ...) to support ES module s • Which means that ns and require must be asyn c • Which means all (top level) eval must be async

Slide 27

Slide 27 text

Async eval • SCI's eval-string and other APIs fns are synchronou s • Solution: nbb reads every top level expression + custom eva l • If expression matches (ns ...): 
 - eval every :require clause manually
 - if string lib name, use async js/import
 - built-in namespaces (reagent.core, promesa.core, ...) are loaded lazily, async for better startup tim e • SCI's clojure.core/require is patched to use an async variant, wrapped in nbb.core/await • Every other expression is evaluated synchronously and wrapped in promis e • All top level expressions are now evaluated as chained promise

Slide 28

Slide 28 text

Require JS libs: ES6 • (require '["fs" :as fs]) evaluated as (js/ import "fs") + alias def 
 user=> (def fs (nbb.core/await (js/import "fs"))) 
 #'user/fs 
 user=> (js/console.log fs) 
 { Dir: [class Dir], Dirent: [class Dirent], F_OK: 0, 
 ... 
 }

Slide 29

Slide 29 text

Require JS libs: ES6 • JS: export default ... • nbb: (require '["library$default" :as lib]) • JS: export { foo }; • nbb: (require '["library$foo" :as foo])

Slide 30

Slide 30 text

To use ES6 is to be ES6... • Regular ClojureScript compiler only emits CJS for Node.js • Shadow-cljs to the rescue: :target :esm • nbb is available as library from JS as ESM: import { loadFile } from nbb

Slide 31

Slide 31 text

JS API

Slide 32

Slide 32 text

Misc • Publish your nbb project on npm: npx nbb-project • Self-contained executable with caxa

Slide 33

Slide 33 text

Future • Many improvements to be made: • Load .cljs fi les from npm modules? (hammock) • Performance improvements in SCI • Your contributions? • If deno catches on: dbb

Slide 34

Slide 34 text

Nbb + Node.js! • Startup time • Large ecosystem: many useful libraries • Quickly write small web apps • Browser testing: Playwright, Puppeteer • CLI/TUI apps • Cron jobs (bots), cloud functions (AWS, Google) • ClojureScript 💖

Slide 35

Slide 35 text

Thanks! • Thomas Heller (shadow-cljs) • Mauricio Szabo (advice, promesa) • Kimmo Koskinen (initial nREPL) • Chris McCormick (early adopter, sitefox) • Jay Zawrotny (eccentric-j) (early adopter, contributor) • Andrey Antukh (promesa) • Valtteri Harmainen (AWS Lambda) • Michaël Salihi (cool projects) • Peter Strömberg (Calva) • Benjamin Scherdtner, Bobby Towers (contributions) • Nextjournal (Martin, Jack, ...) (improvements while developing UI tests, google cloud) • Many others!

Slide 36

Slide 36 text

Thanks to sponsors! https://opencollective.com/babashka/contribute https://github.com/sponsors/borkdude

Slide 37

Slide 37 text

Thank you!