Skip to content

Commit

Permalink
Merge branch 'main' into nrepl-wip
Browse files Browse the repository at this point in the history
  • Loading branch information
borkdude committed Oct 25, 2023
2 parents 595fc0b + f68f08c commit 6a07a8a
Show file tree
Hide file tree
Showing 37 changed files with 736 additions and 255 deletions.
3 changes: 2 additions & 1 deletion .clj-kondo/config.edn
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
{:lint-as {squint.core/defclass clj-kondo.lint-as/def-catch-all}}
{:lint-as {squint.core/defclass clj-kondo.lint-as/def-catch-all}
:linters {:discouraged-var {clojure.core/gensym {:message "gensym makes compiler not deterministic"}}}}
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,41 @@

[Squint](https://github.com/squint-cljs/squint): ClojureScript syntax to JavaScript compiler

## 0.3.35 (2023-10-25)

- [#347](https://github.com/squint-cljs/squint/issues/347): Add `:pre` and `:post` support in `fn`
- Add `number?`
- Support `docstring` in `def`

## 0.3.34 (2023-10-24)

- Handle multipe source `:paths` in a more robust fashion

## 0.3.33 (2023-10-24)

- [#344](https://github.com/squint-cljs/squint/issues/344): macros can't be used via aliases

## 0.3.32 (2023-10-17)

- Add `squint.edn` support, see [docs](README.md#squintedn)
- Add `watch` subcommand to watch `:paths` from `squint.edn`
- Make generated `let` variable names in JS more deterministic, which helps hot reloading in React
- Added a [vite + react example project](examples/vite-react).
- Resolve symbolic namespaces `(:require [foo.bar])` from `:paths`

## 0.2.31 (2023-10-09)

- Add `bit-and` and `bit-or`

## 0.2.30 (2023-10-04)

- Include `lib/squint.core.umd.js` which defines a global `squint.core` object (easy to use in browsers, see [docs](README.md#compile-on-a-server-use-in-a-browser))

## 0.2.29 (2023-10-03)

- Add `subs`, `fn?`, `re-seq`
- Add `squint.edn` with `:paths` to resolve macros from (via `:require-macros`)

## 0.2.28 (2023-09-18)

- Fix `and` and `or` with respect to CLJS truthiness
Expand Down
77 changes: 77 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,87 @@ REPL. REPL away!

Squint respect CLJS truth semantics: only `null`, `undefined` and `false` are non-truthy, `0` and `""` are truthy.

## Macros

To load macros, add a `squint.edn` file in the root of your project with
`{:paths ["src-squint"]}` that describes where to find your macro files. Macros
are written in `.cljs` or `.cljc` files and are executed using
[SCI](https://github.com/babashka/sci).

The following searches for a `foo/macros.cljc` file in the `:paths` described in `squint.edn`.

``` clojure
(ns foo (:require-macros [foo.macros :refer [my-macro]]))

(my-macro 1 2 3)
```

## `squint.edn`

In `squint.edn` you can describe the following options:

- `:paths`: the source paths to search for files. At the moment, only `.cljc` and `.cljs` are supported.
- `:extension`: the preferred extension to output, which defaults to `.mjs`, but can be set to `.jsx` for React(-like) projects.

See [examples/vite-react](examples/vite-react) for an example project which uses a `squint.edn`.

## Watch

Run `npx squint watch` to watch the source directories described in `squint.edn` and they will be (re-)compiled whenever they change.
See [examples/vite-react](examples/vite-react) for an example project which uses this.

## Svelte

A svelte pre-processor for squint can be found [here](https://github.com/jruz/svelte-preprocess-cljs).

## Vite

See [examples/vite-react](examples/vite-react).

## Compile on a server, use in a browser

This is a small demo of how to leverage squint from a JVM to compile snippets of
JavaScript that you can use in the browser.

``` clojure
(require '[squint.compiler])
(-> (squint.compiler/compile-string* "(prn (map inc [1 2 3]))" {:core-alias "_sc"}) :body)
;;=> "_sc.prn(_sc.map(_sc.inc, [1, 2, 3]));\n"
```

The `:core-alias` option takes care of prefixing any `squint.core` function with an alias, in the example `_sc`.

In HTML, to avoid any async ES6, there is also a UMD build of `squint.core`
available. See the below HTML how it is used. We alias the core library to our
shorter `_sc` alias ourselves using

``` html
<script>globalThis._sc = squint.core;</script>
```

to make it all work.

``` html
<!DOCTYPE html>
<html>
<head>
<title>Squint</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/squint.core.umd.js"></script>
<!-- rename squint.core to a shorter alias at your convenience: -->
<script>globalThis._sc = squint.core;</script>
<!-- compile JS on the server using: (squint.compiler/compile-string* "(prn (map inc [1 2 3]))" {:core-alias "_sc"}) -->
<script>
_sc.prn(_sc.map(_sc.inc, [1, 2, 3]));
</script>
</head>
<body>
<button onClick="_sc.prn(_sc.map(_sc.inc, [1, 2, 3]));">
Click me
</button>
</body>
</html>
```

License
=======

Expand Down
29 changes: 19 additions & 10 deletions bb/tasks.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,8 @@
[babashka.fs :as fs]
[babashka.process :refer [shell]]
[cheshire.core :as json]
[clojure.edn :as edn]
[clojure.java.io :as io]
[node-repl-tests]))

(defn munge* [s reserved]
(let [s (str (munge s))]
(if (contains? reserved s)
(str s "$")
s)))
[node-repl-tests]
[clojure.string :as str]))

(def test-config
'{:compiler-options {:load-tests true}
Expand Down Expand Up @@ -42,6 +35,7 @@
(defn publish []
(build-squint-npm-package)
(run! fs/delete (fs/glob "lib" "*.map"))
(shell "esbuild src/squint/core.js --minify --format=iife --global-name=squint.core --outfile=lib/squint.core.umd.js")
(shell "npm publish"))

(defn watch-squint []
Expand All @@ -51,10 +45,25 @@
(bump-core-vars)
(shell "npx shadow-cljs --aliases :dev --config-merge .work/config-merge.edn watch squint"))

(defn test-project [_]
(let [dir "test-project"]
(fs/delete-tree (fs/path dir "lib"))
(shell {:dir dir} "npx squint compile")
(let [output (:out (shell {:dir dir :out :string} "node lib/main.mjs"))]
(println output)
(assert (str/includes? output "macros2/debug 10"))
(assert (str/includes? output "macros2/debug 6"))
(assert (str/includes? output "macros/debug 10",))
(assert (str/includes? output "macros/debug 6"))
(assert (str/includes? output "my-other-src")))))

(defn test-squint []
(fs/create-dirs ".work")
(spit ".work/config-merge.edn" (shadow-extra-test-config))
(bump-core-vars)
(shell "npx shadow-cljs --config-merge .work/config-merge.edn compile squint")
(shell "node lib/squint_tests.js")
(node-repl-tests/run-tests {}))
(node-repl-tests/run-tests {})
(test-project {}))


49 changes: 49 additions & 0 deletions examples/vite-react/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Vite-react example

To set up a project with vite + react, go through the following steps:

- Install dependencies:

```
$ npm install --save-dev vite
$ npm install react-dom
$ npm install squint-cljs
```

- Create a `viteconfig.js` with the React plugin

See [viteconfig.js](viteconfig.js)

- Create a `squint.edn` to specify the source directories and to use the `.jsx`
extension for outputted files

See [squint.edn](squint.edn)

- Run `npx squint watch` to start compiling `.cljs` -> `.jsx`

E.g. see [src/MyComponent.cljs](src/MyComponent.cljs):

``` clojure
(ns my-component
(:require ["react" :refer [useState]]))

(defn MyComponent []
(let [[state setState] (useState 0)]
#jsx [:div "You clicked " state "times"
[:button {:onClick #(setState (inc state))}
"Click me"]]))
```

- Run `npx vite --config viteconfig.js public` to start a webserver and to hot-reload your React project!

## Babashka tasks

To run all of the above using one command, run `bb dev`. See [bb.edn](bb.edn).

## Production

To build your production website:

```
$ npx vite --config viteconfig.js build public
```
5 changes: 5 additions & 0 deletions examples/vite-react/bb.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{:tasks
{dev:squint (shell "npx squint watch")
dev:vite (shell "npx vite --config=viteconfig.js public")
-dev {:depends [dev:vite dev:squint]}
dev (run '-dev {:parallel true})}}
11 changes: 11 additions & 0 deletions examples/vite-react/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"devDependencies": {
"@vitejs/plugin-react": "^4.1.0",
"chokidar": "^3.5.3",
"vite": "^4.4.11"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
3 changes: 3 additions & 0 deletions examples/vite-react/squint.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{:paths ["src"]
:output-dir "public/js"
:extension "jsx"}
10 changes: 10 additions & 0 deletions examples/vite-react/src/MyComponent.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
(ns MyComponent
(:require ["react" :refer [useState]]))

(defn MyComponent []
#jsx [:div
(let [[state setState] (useState 0)]
#jsx [:div "You clicked " state "times"
[:button {:onClick (fn [[_ _ _ ]]
(setState (inc state)))}
"Click me!"]])])
8 changes: 8 additions & 0 deletions examples/vite-react/src/index.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
(ns index
(:require
[MyComponent :as MyComponent]
["react-dom/client" :as rdom]))

(def root (rdom/createRoot (js/document.getElementById "app")))
(.render root #jsx [MyComponent/MyComponent])

7 changes: 7 additions & 0 deletions examples/vite-react/viteconfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
plugins: [react()]
});
18 changes: 18 additions & 0 deletions index.umd.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<title>Squint</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/squint.core.umd.js"></script>
<!-- rename squint.core to a shorter alias at your convenience: -->
<script>globalThis._sc = squint.core;</script>
<!-- compile JS on the server using: (squint.compiler/compile-string* "(prn (map inc [1 2 3]))" {:core-alias "_sc"}) -->
<script>
_sc.prn(_sc.map(_sc.inc, [1, 2, 3]));
</script>
</head>
<body>
<button onClick="_sc.prn(_sc.map(_sc.inc, [1, 2, 3]));">
Click me
</button>
</body>
</html>
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "squint-cljs",
"type": "module",
"sideEffects": false,
"version": "0.2.28",
"version": "0.3.35",
"files": [
"core.js",
"src/squint/core.js",
Expand All @@ -29,5 +29,9 @@
"react": "^18.2.0",
"shadow-cljs": "^2.19.8",
"squint-cljs": "."
},
"dependencies": {
"chokidar": "^3.5.3",
"glob": "^10.3.10"
}
}
4 changes: 4 additions & 0 deletions resources/squint/core.edn
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
filter
filterv
first
fn_QMARK_
fnil
frequencies
get
Expand Down Expand Up @@ -90,6 +91,7 @@
not_any_QMARK_
not_every_QMARK_
nth
number_QMARK_
odd_QMARK_
partial
partition
Expand All @@ -102,6 +104,7 @@
rand_nth
range
re_matches
re_seq
reduce
reduce_kv
reduced
Expand All @@ -128,6 +131,7 @@
split_at
split_with
str
subs
subvec
swap_BANG_
system_time
Expand Down
Loading

0 comments on commit 6a07a8a

Please sign in to comment.