-
Notifications
You must be signed in to change notification settings - Fork 215
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix fn instrumentation errors for ClojureScript in a browser
- Print all output from the pretty printer in one string - Add documentation for working on function instrumentation in the malli codebase - Add documentation for using malli.dev.cljs as a user of malli
- Loading branch information
Showing
11 changed files
with
152 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
To work on the function instrumentation for ClojureScript clone the malli repository and: | ||
|
||
```bash | ||
npm i | ||
./node_modules/.bin/shadow-cljs watch instrument | ||
``` | ||
|
||
Open an nREPL connection from your favorite editor to the port located in `.shadow-cljs/nrepl.port` | ||
|
||
Open a browser to `http://localhost:8000` | ||
|
||
the port is set in the `shadow-cljs.edn` file should you wish to change it. | ||
|
||
|
||
In your editor evaluate: | ||
|
||
`(shadow/repl :instrument)` | ||
|
||
The dev-time code is located in the file: `app/malli/instrument_app.cljs`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
# ClojureScript Function Instrumentation | ||
|
||
Function instrumentation is also supported when developing ClojureScript browser applications. | ||
|
||
Things work differently from the Clojure version of instrumentation because there are no runtime Vars in ClojureScript and thus the | ||
instrumentation must happen at compile-time using macros. | ||
The macro will emit code that `set!`s the function at runtime with a version that validates the function's inputs and outputs | ||
against its declare malli schema. | ||
|
||
# Dev Setup | ||
|
||
For the best developer experience make sure you install the latest version of binaryage/devtools and use a chromium based browser: | ||
|
||
https://clojars.org/binaryage/devtools | ||
|
||
if you are using shadow-cljs just ensure this library is on the classpath. | ||
|
||
For an application that uses React.js such as Reagent you will typically declare an entry namespace and init function in your `shadow-cljs.edn` config like so: | ||
|
||
```clj | ||
{... | ||
:modules {:app {:entries [your-app.entry-ns] | ||
:init-fn your-app.entry-ns/init}} | ||
...} | ||
``` | ||
|
||
In your init namespace require `malli.dev.cljs`: | ||
|
||
```clj | ||
(require [malli.dev.cljs :as md]) | ||
``` | ||
|
||
and invoke `start!` in your init function before rendering your application: | ||
|
||
```clj | ||
(defn ^:export init [] | ||
(md/start!) | ||
(my-app/mount!) | ||
``` | ||
|
||
When you save source code files during development and new code is hot-reloaded the non-instrumented versions will now | ||
overwrite any instrumented versions. | ||
|
||
To instrument the newly loaded code with shadow-cljs we can use the [lifecylce hook](https://shadow-cljs.github.io/docs/UsersGuide.html#_lifecycle_hooks) | ||
`:after-load` by adding metadata to a function and invoking `malli.dev.cljs/start!` again: | ||
|
||
```clj | ||
(defn ^:dev/after-load reload [] | ||
(md/start!) | ||
(my-app/mount!)) | ||
``` | ||
|
||
It is useful to understand what is happening when you invoke `(malli.dev.cljs/start!)` | ||
|
||
The line where `start!` lives in your code will be replaced by a block of code that looks something like: | ||
|
||
```clj | ||
(set! your-app-ns/a-function | ||
(fn [& args] | ||
:; validate the args against the input schema | ||
;; invoke the function your-app-ns/a-function and validate the output against the output schema | ||
;; return the output | ||
) | ||
;; assuming an implementation in your-app-ns like: | ||
(defn a-function | ||
{:malli/schema [:=> [:cat :int] :string]} | ||
[x] | ||
(str x)) | ||
``` | ||
|
||
(you can see what is actually output here: https://github.com/metosin/malli/blob/400dc0c79805028a6d85413086d4d6d627231940/src/malli/instrument/cljs.clj#L69) | ||
|
||
And this is why the order of loaded code will affect the instrumented functions. If the code for `your-app-ns/a-function` | ||
is hot-reloaded and the `start!` call is never invoked again, the function will no longer be instrumented. | ||
|
||
## Errors in the browser console | ||
|
||
When you get a schema validation error and instrumentation is on you will see an exception in the browser devtools. | ||
|
||
A validation error looks like this: | ||
|
||
<img src="img/cljs-instrument/cljs-instrument-error-collapsed.png"/> | ||
|
||
If you click the arrow that is highlighted in the above image you will see the error message: | ||
|
||
<img src="img/cljs-instrument/cljs-instrument-error-expanded.png"/> | ||
|
||
and if you click the arrow highlighted in this above image you will see the stracktrace: | ||
|
||
<img src="img/cljs-instrument/cljs-instrument-stacktrace-expanded.png"/> | ||
|
||
the instrumented function is the one with the red rectangle around it in the image above. | ||
|
||
If you click the filename (`instrument_app.cljs` in this example) the browser devtools will open a file viewer at the problematic call-site. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters