Git Product home page Git Product logo

modern-cljs's Introduction

Latest tutorials

Part II of a step by step reasoned porting of the Official React Tutorial to Reagent.

Part I of a step by step reasoned porting of the Official React Tutorial to Reagent.

Step by step guide for publishing a library to clojars repository by using boot.

Modern ClojureScript

ATTENTION NOTE: I'm in the process of publishing the second edition of the series. The main difference from the first edition regards the use of the Boot build tool instead of Leiningen. This second edition is still a draft version and you should be forgiving if you find errors, typos or even bugs in the code.

WARNING NOTE FOR WINDOWS USERS: At the moment boot does not run on MS Windows less than 10. If this is your case, to be able to follow the modern-cljs series you can use use a virtual machine or docker linux container.

Modern ClojureScript (modern-cljs) is a series of tutorials that guide you in creating and running ClojureScript (CLJS) projects.

CLJS is a compiler for the Clojure programming language that targets JavaScript. It emits JavaScript code which runs in web browsers and other client-side or server-side JavaScript interpreters (e.g. nodejs).

Required background

These tutorials require that you have some prior programming experience. They assume you've gotten your hands dirty by trying a little Clojure, even if you're not proficient in it yet. It will also be quite helpful if you have some experience programming for the Web using HTML, JavaScript and the browser DOM.

If you don't know anything about Clojure (or about Lisp), I recommend you learn a little bit before starting these tutorials.

There are plenty of outstanding resources on Clojure that are freely available on the Internet, and you can't overestimate the benefit of reading a book on Clojure (or another Lisp dialect) to your value as a programmer.

Here are some book recommendations:

Required tools

Many people worry about which operating system and editor/IDE are best for developing in Clojure and ClojureScript. I personally use Mac OS X, Debian and Ubuntu. I use Emacs as an editor.

Because I'm an old-timer, *nix and Emacs are the OS and editor I know best. That being said, in this series of tutorials you're not going to find any suggestions or reference to operating systems or editors. Use whatever tools you already have and know. I have too much respect for people developing IDE/plugins for Clojure/CLJS to say that one is better than another, and you don't want to combine learning a new programming language with trying to learn a new programming environment.

NOTE: If you are interested in learning more about Emacs here are some [resources to help get you started] (https://github.com/magomimmo/modern-cljs/blob/master/doc/supplemental-material/emacs-cider-references.md).

You will need to have git and Java installed and you'll need some familiarity with the basics of git.

Clojure community documentation

Community created clojure documentation sites that you may find helpful are clojuredocs and Grimoire.

Libraries and tools

Clojure Toolbox is a directory of libraries and tools for CLJ/CLJS.

Why the name Modern ClojureScript?

You might wonder why this tutorial series is named modern-cljs when ClojureScript is so recent. I started this series in 2012 while trying to port a few examples from the Modern JavaScript: Develop and Design book to ClojureScript, and now it's too late to change.

The Tutorials

As said, this is the second edition of the series and is based on the Boot build tool. I'm not going to update or support the first edition of the series which was based on the Leiningen build tool.

Introduction

This series of tutorials guides you in creating and running simple CLJS projects. The bulk of the series follows the progressive enhancement of a single project.

While working through the tutorials I strongly suggest you start at tutorial 1 and type in all the code for each tutorial yourself. In my experience this is the the best approach if you're not already very fluent with the programming language.

Create and configure a very basic CLJS project.

Approach as close as possible the Bret Victor Immediate Feedback Principle to build a very interactive development environment.

Automate the launching of the boot command to approach the Immediate Feedback Development Environment (IFDE).

Have some fun with CLJS form validation by porting the JavaScript login form example from Modern JavaScript: Develop and Design to CLJS.

Use the Domina library to make our login form validation more Clojure-ish.

Investigate and find two different ways to solve an issue from the last tutorial.

Use Domina events for a more Clojure-ish approach to handling DOM events.

Programmatically manipulate DOM elements in response to DOM events.

Use AJAX to let the CLJS client-side code communicate with the server.

Apply Domina events to the login form example from the 4th Tutorial.

Explore the highest (HTML5) and deepest (Clojure on the server) layers of the login form example from the previous tutorial.

Respect the Don't Repeat Yourself (DRY) principle by sharing validators between the client-side CLJS and the server-side Clojure.

Set the stage for unit testing by learning about the Enlive template sytem and starting the shopping calculator example. Use code refactoring to satisfy the DRY principle and to solve a cyclic namespaces dependency problem.

Add validators to the shoppingForm, and do some unit testing.

Configure a development environment that simultaneously satisfy in a single JVM the Immediate Feedback Principle by Bret Victor and the Test Driven Development (TDD).

Make the Test Driven Development Environment more customizable.

Integrate validators into a web form in such a way that the user will be notified with the corresponding help messages when they enter invalid values in the form.

Complete the client-side form validation by exploiting the TDD environment augmented with CLJ/CLJS REPLs.

Explain how to make a library compliant with the new Reader Conditionals extension on CLJ/CLJS compilers.

Step by step guide for publishing a library to clojar repository by using boot.

Part I of a step by step reasoned porting of the Official React Tutorial to Reagent.

Part II of a step by step reasoned porting of the Official React Tutorial to Reagent.

License

Copyright © Mimmo Cosenza, 2012-2016. Released under the Eclipse Public License, the same license as Clojure.

modern-cljs's People

Contributors

adsteel avatar aeosynth avatar bananaoat avatar belucid avatar bigos avatar burningtyger avatar cloojure avatar deg avatar elenacanovi avatar gborghi avatar giovanniferrari avatar groakat avatar indlin avatar j1mr10rd4n avatar learningcljs avatar lischenko avatar magomimmo avatar magopian avatar manutro avatar mikavilpas avatar moquist avatar nchurch avatar olivergeorge avatar rbxbx avatar riwsky avatar serialhex avatar sumbach avatar teodorlu avatar verdammelt avatar zacharyrsmith avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

modern-cljs's Issues

Tutorial-05 validate-form discrepency

This is related to the code at https://github.com/magomimmo/modern-cljs/blob/master/doc/tutorial-05.md#modify-validate-form

When trying to evaluate (validate-form) in the browser repl, I get a stack trace:

ClojureScript:modern-cljs.login>(validate-form)
"Error evaluating:" (validate-form) :as "modern_cljs.login.validate_form.call(null)"
#<TypeError: el is null>
goog.dom.forms.getValue@http://localhost:3000/js/modern.js:31896
value@http://localhost:3000/js/modern.js:33320
validate_form@http://localhost:3000/js/modern.js:33875
@http://localhost:3000/js/modern.js:33917
@http://localhost:3000/js/modern.js:33917
evaluate_javascript/result<@http://localhost:3000/js/modern.js:33917
evaluate_javascript@http://localhost:3000/js/modern.js:33915
connect/<@http://localhost:3000/js/modern.js:33995
goog.messaging.AbstractChannel.prototype.deliver@http://localhost:3000/js/modern.js:29674
goog.net.xpc.CrossPageChannel.prototype.xpcDeliver@http://localhost:3000/js/modern.js:31216
goog.net.xpc.NativeMessagingTransport.messageReceived_@http://localhost:3000/js/modern.js:30630
goog.events.Listener.prototype.handleEvent@http://localhost:3000/js/modern.js:23061
goog.events.fireListener@http://localhost:3000/js/modern.js:23438
goog.events.handleBrowserEvent_@http://localhost:3000/js/modern.js:23555
goog.events.getProxy/f<@http://localhost:3000/js/modern.js:23162

nil
ClojureScript:modern-cljs.login>

I don't know enough js to know if this is the cause, but when displaying validate-form in the repl, the code looks very different from the tutorial:

ClojureScript:modern-cljs.login> validate-form
#<function validate_form() {
  var email = domina.by_id.call(null, "email");
  var password = domina.by_id.call(null, "password");
  if(cljs.core.count.call(null, domina.value.call(null, email)) > 0 && cljs.core.count.call(null, domina.value.call(null, password)) > 0) {
    return true
  }else {
    alert("Please, complete the form!");
    return false
  }
}>

I don't know if it's related, but If I diff vs. the tutorial-05 branch and my tutorial-05-step-1 there are no differences in the login.cljs file:

Peters-MacBook-Pro:modern-cljs peter$ git diff tutorial-05..tutorial-05-step-1 src/cljs/modern_cljs/login.cljs

I'm so bad...

I'd like to beg your pardon. I was not able in the last month to add any new tutorial to the series. I was too busy with my daily job and now with my visit in Boston. Hope to be back on track starting from May with the following new tutorials:

  • clojurescript test. Thanks to Chas Emerick I could now be more sound on this topic.
  • Don't Repeat Yourself while crossing the border part2 (enlive and enfocus)
  • Don't Repeat Chas Emerick (authentication/autohoriation with friend).

I feel so sorry, but sometimes I need to pay the bills as everyone else.

Mimmo

Tutorial 1 compilation error: clojure.lang.Symbol cannot be cast to java.lang.Boolean

Any idea what I've missed? Thanks!

bash-3.2$ lein cljsbuild clean
Deleting files generated by lein-cljsbuild.
bash-3.2$ tree
.
├── LICENSE
├── README.md
├── doc
│   └── intro.md
├── project.clj
├── resources
│   └── public
│   ├── css
│   ├── js
│   └── simple.html
├── src
│   ├── clj
│   │   └── modern_cljs
│   │   └── core.clj
│   └── cljs
│   └── modern_cljs
│   └── modern.cljs
├── target
└── test
└── modern_cljs
└── core_test.clj

13 directories, 8 files
bash-3.2$ cat project.clj
(defproject modern-cljs "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:source-paths ["src/clj" "src/cljs"]
:dependencies [[org.clojure/clojure "1.5.1"]
[org.clojure/clojurescript "0.0-2069"]]
:plugins [[lein-cljsbuild "1.0.0"]]
:cljsbuild {:builds
[{
:source-paths ["src/cljs"]
:compiler {
:output-to "resources/public/js/modern.js"
:optimizations :whitespace
:pretty-print tue}}]})
bash-3.2$ cat src/cljs/modern_cljs/modern.cljs
(ns modern-cljs.modern)
(.write js/document "Hello, ClojureScript!")
bash-3.2$ lein cljsbuild once
Compiling ClojureScript.
Compiling "resources/public/js/modern.js" from ["src/cljs"]...
�[31mCompiling "resources/public/js/modern.js" failed.�[0m
java.lang.ClassCastException: clojure.lang.Symbol cannot be cast to java.lang.Boolean
at cljs.closure$set_options.invoke(closure.clj:89)
at cljs.closure$make_options.invoke(closure.clj:111)
at cljs.closure$optimize.doInvoke(closure.clj:713)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invoke(core.clj:619)
at cljs.closure$build.invoke(closure.clj:1100)
at cljs.closure$build.invoke(closure.clj:1047)
at cljsbuild.compiler$compile_cljs$fn__3018.invoke(compiler.clj:58)
at cljsbuild.compiler$compile_cljs.invoke(compiler.clj:57)
at cljsbuild.compiler$run_compiler.invoke(compiler.clj:158)
at user$eval3144$iter__3147__3151$fn__3152$fn__3164.invoke(form-init4190560175504781944.clj:1)
at user$eval3144$iter__3147__3151$fn__3152.invoke(form-init4190560175504781944.clj:1)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:60)
at clojure.lang.RT.seq(RT.java:484)
at clojure.core$seq.invoke(core.clj:133)
at clojure.core$dorun.invoke(core.clj:2780)
at clojure.core$doall.invoke(core.clj:2796)
at user$eval3144.invoke(form-init4190560175504781944.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6619)
at clojure.lang.Compiler.eval(Compiler.java:6609)
at clojure.lang.Compiler.load(Compiler.java:7064)
at clojure.lang.Compiler.loadFile(Compiler.java:7020)
at clojure.main$load_script.invoke(main.clj:294)
at clojure.main$init_opt.invoke(main.clj:299)
at clojure.main$initialize.invoke(main.clj:327)
at clojure.main$null_opt.invoke(main.clj:362)
at clojure.main$main.doInvoke(main.clj:440)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:419)
at clojure.lang.AFn.applyToHelper(AFn.java:163)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.main.main(main.java:37)
Subprocess failed
bash-3.2$

Chapter 5 is broken?

It instructs to pull in domina by adding it to the project.clj:

:dependencies [[org.clojure/clojure "1.4.0"]
               [compojure "1.1.5"]
               [domina "1.0.0"]]

And then use it in your script by referencing it in the ns form

(ns cljstut.login
  (:use [domina :only [by-id value]]))

However, when I actually run this in a browser, I see the following in the console log.

goog.require could not find: domina

Seems like I'm missing some declaration somewhere? But as a newb, this whole build process is rather opaque. Any troubleshooting tips are greatly appreciated.

Following the tutorial, and the brepl failed.

Hi Magomimmo,

Thanks for writing the clojurescript tutorials. I have been following them, but got stuck.

I posted the problem on the clojure mailing list, but no response yet. Maybe this was not the place to post clojurescript problems, but that is what the clojurescript site referred me to.

https://groups.google.com/forum/?fromgroups=#!topic/clojure/StwbZ9BHHvo

Basically, following the brepl tutorial hangs with the errors I described. The problem, is that until this is sorted my (and I suspect other's ) clojurescript adventures are on hold. :)

Do you have any ideas on how this can be solved?

Thanks,

Rohan

Add a note to tutorial 04 about Chrome being annoying

Chrome (at least my version, Version 26.0.1410.65) appears to intercept the events for this form:

Screen Shot 2013-04-24 at 6 16 41 PM

Firefox does something similar:

Screen Shot 2013-04-24 at 6 18 23 PM

There's a different message for blank entries, but you get the idea. It threw me for a bit of a loop, though. Not sure what the best way to handle the explanation would be, or whether it warrants actually changing the tutorial code itself?

Tutorial 5 should also use domina for event handling

I think tutorial 4 should also use addEventListener instead of setting attributes (and in the spirit of progressive enhancements noValidate should be added in javascript when the submit hook is added, so JS-less users still get native form validation).

But even keeping tutorial 4's translation straight, tutorial 5 could make use of domina's listen! and prevent-default.

lein-cljsbuild :plugins

I'm building a small cljs app, based on this tutorial. Today, I tried deploying it, and discovered that "lein trampoline ring server" silently fails.

A regression test against your project showed that my problem was that I had the line ":hooks [leiningen.cljsbuild]" in my project.clj.

It looks like you originally had this line too, but you removed it three months ago, in commit 6ea9780.

What's the full story here? Do you remember if you hit the same problem? Is this line no longer needed, or is this a bug in cljsbuild, or something else altogether?

Puzzled,
David

"lein cljsbuild once" fails

Hey guys,

After a successful lein ring server-headless, I ran lein cljsbuild once (in another terminal) which failed with the following error:

➜  modern-cljs git:(master) lein cljsbuild once
Compiling ClojureScript.
Compiling "resources/public/js/modern_pre.js" from ["src/brepl" "src/cljs" "target/test/cljs"]...
Compiling "resources/public/js/modern_pre.js" failed.
java.io.FileNotFoundException: target/test/cljs (No such file or directory)
         (Unknown Source) java.io.FileInputStream.open
 FileInputStream.java:138 java.io.FileInputStream.<init>
               io.clj:233 clojure.java.io/fn
                io.clj:73 clojure.java.io/fn[fn]
               io.clj:169 clojure.java.io/fn
                io.clj:73 clojure.java.io/fn[fn]
               io.clj:106 clojure.java.io/reader
          RestFn.java:410 clojure.lang.RestFn.invoke
         compiler.clj:746 cljs.compiler/forms-seq
          closure.clj:366 cljs.closure/compile-file
          closure.clj:407 cljs.closure/eval1525[fn]
          closure.clj:276 cljs.closure/eval1452[fn]
          closure.clj:420 cljs.closure/eval1512[fn]
          closure.clj:276 cljs.closure/eval1452[fn]
          compiler.clj:43 cljsbuild.compiler.SourcePaths/fn
            core.clj:2485 clojure.core/map[fn]
          LazySeq.java:42 clojure.lang.LazySeq.sval
          LazySeq.java:60 clojure.lang.LazySeq.seq
              RT.java:484 clojure.lang.RT.seq
             core.clj:133 clojure.core/seq
             core.clj:617 clojure.core/apply
            core.clj:2514 clojure.core/mapcat
          RestFn.java:423 clojure.lang.RestFn.invoke
          compiler.clj:43 cljsbuild.compiler/cljsbuild.compiler.SourcePaths
          closure.clj:900 cljs.closure/build
          compiler.clj:57 cljsbuild.compiler/compile-cljs[fn]
          compiler.clj:56 cljsbuild.compiler/compile-cljs
         compiler.clj:140 cljsbuild.compiler/run-compiler
         NO_SOURCE_FILE:1 user/eval1835[fn]
          LazySeq.java:42 clojure.lang.LazySeq.sval
          LazySeq.java:60 clojure.lang.LazySeq.seq
              RT.java:484 clojure.lang.RT.seq
             core.clj:133 clojure.core/seq
            core.clj:2780 clojure.core/dorun
            core.clj:2796 clojure.core/doall
         NO_SOURCE_FILE:1 user/eval1835
       Compiler.java:6619 clojure.lang.Compiler.eval
       Compiler.java:6609 clojure.lang.Compiler.eval
       Compiler.java:6582 clojure.lang.Compiler.eval
            core.clj:2852 clojure.core/eval
             main.clj:308 clojure.main/eval-opt
             main.clj:327 clojure.main/initialize
             main.clj:362 clojure.main/null-opt
             main.clj:440 clojure.main/main
          RestFn.java:421 clojure.lang.RestFn.invoke
             Var.java:419 clojure.lang.Var.invoke
             AFn.java:163 clojure.lang.AFn.applyToHelper
             Var.java:532 clojure.lang.Var.applyTo
             main.java:37 clojure.main.main
Compiling "resources/public/js/modern_dbg.js" from ["src/brepl" "src/cljs" "target/test/cljs"]...
Compiling "resources/public/js/modern_dbg.js" failed.
java.io.FileNotFoundException: target/test/cljs (No such file or directory)
         (Unknown Source) java.io.FileInputStream.open
 FileInputStream.java:138 java.io.FileInputStream.<init>
               io.clj:233 clojure.java.io/fn
                io.clj:73 clojure.java.io/fn[fn]
               io.clj:169 clojure.java.io/fn
                io.clj:73 clojure.java.io/fn[fn]
               io.clj:106 clojure.java.io/reader
          RestFn.java:410 clojure.lang.RestFn.invoke
         compiler.clj:746 cljs.compiler/forms-seq
          closure.clj:366 cljs.closure/compile-file
          closure.clj:407 cljs.closure/eval1525[fn]
          closure.clj:276 cljs.closure/eval1452[fn]
          closure.clj:420 cljs.closure/eval1512[fn]
          closure.clj:276 cljs.closure/eval1452[fn]
          compiler.clj:43 cljsbuild.compiler.SourcePaths/fn
            core.clj:2485 clojure.core/map[fn]
          LazySeq.java:42 clojure.lang.LazySeq.sval
          LazySeq.java:60 clojure.lang.LazySeq.seq
              RT.java:484 clojure.lang.RT.seq
             core.clj:133 clojure.core/seq
             core.clj:617 clojure.core/apply
            core.clj:2514 clojure.core/mapcat
          RestFn.java:423 clojure.lang.RestFn.invoke
          compiler.clj:43 cljsbuild.compiler/cljsbuild.compiler.SourcePaths
          closure.clj:900 cljs.closure/build
          compiler.clj:57 cljsbuild.compiler/compile-cljs[fn]
          compiler.clj:56 cljsbuild.compiler/compile-cljs
         compiler.clj:140 cljsbuild.compiler/run-compiler
         NO_SOURCE_FILE:1 user/eval1835[fn]
          LazySeq.java:42 clojure.lang.LazySeq.sval
          LazySeq.java:60 clojure.lang.LazySeq.seq
             Cons.java:39 clojure.lang.Cons.next
          LazySeq.java:92 clojure.lang.LazySeq.next
              RT.java:598 clojure.lang.RT.next
              core.clj:64 clojure.core/next
            core.clj:2781 clojure.core/dorun
            core.clj:2796 clojure.core/doall
         NO_SOURCE_FILE:1 user/eval1835
       Compiler.java:6619 clojure.lang.Compiler.eval
       Compiler.java:6609 clojure.lang.Compiler.eval
       Compiler.java:6582 clojure.lang.Compiler.eval
            core.clj:2852 clojure.core/eval
             main.clj:308 clojure.main/eval-opt
             main.clj:327 clojure.main/initialize
             main.clj:362 clojure.main/null-opt
             main.clj:440 clojure.main/main
          RestFn.java:421 clojure.lang.RestFn.invoke
             Var.java:419 clojure.lang.Var.invoke
             AFn.java:163 clojure.lang.AFn.applyToHelper
             Var.java:532 clojure.lang.Var.applyTo
             main.java:37 clojure.main.main
Compiling "resources/public/js/modern.js" from ["src/cljs" "target/test/cljs"]...
Compiling "resources/public/js/modern.js" failed.
java.io.FileNotFoundException: target/test/cljs (No such file or directory)
         (Unknown Source) java.io.FileInputStream.open
 FileInputStream.java:138 java.io.FileInputStream.<init>
               io.clj:233 clojure.java.io/fn
                io.clj:73 clojure.java.io/fn[fn]
               io.clj:169 clojure.java.io/fn
                io.clj:73 clojure.java.io/fn[fn]
               io.clj:106 clojure.java.io/reader
          RestFn.java:410 clojure.lang.RestFn.invoke
         compiler.clj:746 cljs.compiler/forms-seq
          closure.clj:366 cljs.closure/compile-file
          closure.clj:407 cljs.closure/eval1525[fn]
          closure.clj:276 cljs.closure/eval1452[fn]
          closure.clj:420 cljs.closure/eval1512[fn]
          closure.clj:276 cljs.closure/eval1452[fn]
          compiler.clj:43 cljsbuild.compiler.SourcePaths/fn
            core.clj:2485 clojure.core/map[fn]
          LazySeq.java:42 clojure.lang.LazySeq.sval
          LazySeq.java:60 clojure.lang.LazySeq.seq
              RT.java:484 clojure.lang.RT.seq
             core.clj:133 clojure.core/seq
             core.clj:617 clojure.core/apply
            core.clj:2514 clojure.core/mapcat
          RestFn.java:423 clojure.lang.RestFn.invoke
          compiler.clj:43 cljsbuild.compiler/cljsbuild.compiler.SourcePaths
          closure.clj:900 cljs.closure/build
          compiler.clj:57 cljsbuild.compiler/compile-cljs[fn]
          compiler.clj:56 cljsbuild.compiler/compile-cljs
         compiler.clj:140 cljsbuild.compiler/run-compiler
         NO_SOURCE_FILE:1 user/eval1835[fn]
          LazySeq.java:42 clojure.lang.LazySeq.sval
          LazySeq.java:60 clojure.lang.LazySeq.seq
             Cons.java:39 clojure.lang.Cons.next
              RT.java:598 clojure.lang.RT.next
              core.clj:64 clojure.core/next
            core.clj:2781 clojure.core/dorun
            core.clj:2796 clojure.core/doall
         NO_SOURCE_FILE:1 user/eval1835
       Compiler.java:6619 clojure.lang.Compiler.eval
       Compiler.java:6609 clojure.lang.Compiler.eval
       Compiler.java:6582 clojure.lang.Compiler.eval
            core.clj:2852 clojure.core/eval
             main.clj:308 clojure.main/eval-opt
             main.clj:327 clojure.main/initialize
             main.clj:362 clojure.main/null-opt
             main.clj:440 clojure.main/main
          RestFn.java:421 clojure.lang.RestFn.invoke
             Var.java:419 clojure.lang.Var.invoke
             AFn.java:163 clojure.lang.AFn.applyToHelper
             Var.java:532 clojure.lang.Var.applyTo
             main.java:37 clojure.main.main

Note:

➜  modern-cljs git:(master) lein -v
Leiningen 2.1.3 on Java 1.7.0_21 Java HotSpot(TM) 64-Bit Server VM

Regards.

add aliases

Add :aliases to project.cljs to chain clean/compile/test lifecycle.

mamp alternative

Hello,

Nice tutorials!

Just a suggestion about mamp, you could just use python -m SimpleHTTPServer 8888 instead.
It seems more portable and easier to use.

pls upgrade [domina "1.0.0"] dependency

Hi Mimmo,

Love your tutorials!

Noticed that you depend on [domina "1.0.0"], which in turn depends on [goog-jar "1.0.0"], which can cause all kinds of nasty conflicts with the closure libs included by clojurescript...

Anything higher than 1.0.0 for Domina will take that risk away.

Regards, Frank.

Tutorial 18, bRepl on nRepl, BindException

Hi,

Leiningen 2.3.1 on Java 1.7.0_25 OpenJDK 64-Bit Server VM

I added

             [org.clojure/clojurescript "0.0-1847"]
             [com.cemerick/piggieback "0.1.0"]

to my project.clj

This is what happens when I try to launch the piggieback repl:

nREPL server started on port 57794 on host 127.0.0.1
REPL-y 0.2.1
Clojure 1.5.1
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)

user=> 

user=> (require 'cljs.repl.browser)
nil
user=> 

user=> (cemerick.piggieback/cljs-repl :repl-env (cljs.repl.browser/repl-env :port 9000))
Type `:cljs/quit` to stop the ClojureScript REPL
nil
cljs.user=> (+ 1 1)
2
cljs.user=> :cljs/quit
:cljs/quit
user=> 
        cemerick.piggieback/cljs-repl :repl-env (doto (cljs.repl.browser/repl-env :port 9000) cljs.repl/-setup))

BindException Address already in use  java.net.PlainSocketImpl.socketBind (PlainSocketImpl.java:-2)
user=> 

user=> (cemerick.piggieback/cljs-repl :repl-env (cljs.repl.browser/repl-env :port 9000))
"Error evaluating:" (cemerick.piggieback/cljs-repl :repl-env (cljs.repl.browser/repl-env :port 9000)) :as "cemerick.piggieback.cljs_repl.call(null,\"\\uFDD0:repl-env\",cljs.repl.browser.repl_env.call(null,\"\\uFDD0:port\",9000));\n"
#<ReferenceError: cemerick is not defined>
ReferenceError: cemerick is not defined
    at eval (eval at <anonymous> (http://localhost:3000/js/modern.js:34494:125), <anonymous>:1:65)
    at eval (eval at <anonymous> (http://localhost:3000/js/modern.js:34494:125), <anonymous>:6:3)
    at http://localhost:3000/js/modern.js:34494:120
    at evaluate_javascript (http://localhost:3000/js/modern.js:34507:4)
    at Object.callback (http://localhost:3000/js/modern.js:34572:132)
    at goog.messaging.AbstractChannel.deliver (http://localhost:3000/js/modern.js:31590:13)
    at goog.net.xpc.CrossPageChannel.xpcDeliver (http://localhost:3000/js/modern.js:33124:14)
    at Function.goog.net.xpc.NativeMessagingTransport.messageReceived_ (http://localhost:3000/js/modern.js:32538:13)
    at goog.events.Listener.handleEvent (http://localhost:3000/js/modern.js:26538:26)
    at Object.goog.events.fireListener (http://localhost:3000/js/modern.js:26915:19)
nil
cljs.user=> (+ 1 1)
2
cljs.user=> 

For good measure, I also checked if there was something else using up port 9000 with sudo lsof -i :9000, but my clojure repl was the only thing running that was using it

cljsbuild :builds, map vs vector

Up to tutorial 15 the :builds property for cljsbuild is coded as a vector:

  :cljsbuild {:builds [
  {:id ...
   ...}
  {:id ...
   ...}
  ... ] ...}

Starting from tutorial 16 the map sysntax is used, without the reader being warned:

  :cljsbuild {:builds {
  "id1"
  { ... }
  "id2"
  { ... }
  ... }

We should decide which of the two to choose and use it consistently.

Error Running lein test: no class def found javax/servlet/http/HttpServletRequest

When completing tutorial 15, I encountered the following error running lein test:

Exception in thread "main" java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest, compiling:(ring/middleware/multipart_params.clj:39:5)

After some searching, I found the following on the compojure site: weavejester/compojure#98.

As the note suggested, I added an explicit dependency on ring 1.2.1 and resolved the error.

Here's the diff of my project.clj. It includes both the changes indicated in the tutorial and the explicit dependency on ring:

diff --git a/project.clj b/project.clj
index 0d1bbba..7f11013 100644
--- a/project.clj
+++ b/project.clj
@@ -6,6 +6,11 @@

;; Clojure and ClojureScript source code paths
:source-paths ["src/clj" "src/cljs" "src/brepl"]
+

  • ;; Unit test paths
  • :test-paths ["test/clj"]
  • ;; Project dependencies
    :dependencies [[org.clojure/clojure "1.6.0"]
    [org.clojure/clojurescript "0.0-2202"]
    [compojure "1.1.6"]
    @@ -16,7 +21,8 @@
    [org.clojars.magomimmo/shoreleave-remote
    "0.3.1-SNAPSHOT"]
    [com.cemerick/valip "0.3.2"]

  •             [enlive "1.1.5"]]
    
  •             [enlive "1.1.5"]
    
  •             [ring "1.2.1"]]
    

    ;; Leiningen plugin to help building ClojureScript projects.
    :plugins [[lein-cljsbuild "1.0.3"]
    @@ -24,7 +30,9 @@

    ;; ClojureScript build configuration
    :cljsbuild {:crossovers

  •          [valip.core valip.predicates modern-cljs.login.validators]  
    
  •          [valip.core valip.predicates
    
  •           modern-cljs.login.validators
    
  •           modern-cljs.shopping.validators]
           :builds 
           {:dev
            ;; For development, remove extraneous whitespace and
    

More consistent and descriptive commits

Hi Mimmo

Perhaps since you're showing best practice it's a good idea to tidy up your suggested git commands and git messages.

Some thoughts below...

Since the tutorials do a pretty good job of focusing on one feature at a time I think the commits are pretty atomic. No big issues here.

Descriptions start out good but further on they are "finished step 2" etc. This is a pain when you type git log to find out what tutorial you're up to.

git commit -am makes me cringe for two reasons. Firstly it doesn't encourage a review of changes so it's easy to commit experiments / testing etc by mistake. Also it doesn't add new files so only updated files are committed.

I seem to recall some tutorials suggest branching commands without an explanation as to why. Perhaps they are remnants from an older style. (Or I could just be getting confused with the checkout commands for those loading up from your repo)

Thanks again for sharing these with us.

cheers, Oliver

Form Validation Doesn't Work

Sadly, it appears that Chrome and Firefox contain out-of-the-box form validation, leading to the following:

screen-shot

So sadly, Tutorial 4 is broken, because it's impossible to get to the sad path in modern-cljs.login/validate-form

Chrome v. 34.0.1847.116, Firefox v. 28.0

exlusionary and generally useless note

NOTE 1: I'm of the opinion that CLJS should be easier to set up not only to use, as server-side devs, but for smart client-side devs as well. Application logic is moving fast from server-side to client-side and all of us, as server-side devs, never had much love for that LISP dressed in C running in the browser and named JS. We now have the opportunity to see the best LISP ever running in the browser and we should try to bring client-side programmers with us. Otherwise, we risk seeing said LISP in C's clothing running on the server-side too.

As somebody who has pretty much only written JavaScript for browsers in my career I read this and feel like I'm in the side of the room while you talk to the "other smart server devs".

Us client-side devs are going to get into clojure via clojurescript, might want to reconsider your audience :)

Ideas for future directions

Here are some ideas I've had for useful topics for future chapters:

  • How to deploy a CLJS/CLJ project, e.g. to Heroku or AWS
  • Best practices on using NREPL from Emacs (or other editors?) with a CLJ/CLJS project
  • Debugging tips
    • How to debug in the browser
    • Logging trace output to the Javascript console or files
    • What version of the code is visible where, when I'm working in a browser REPL (e.g., when do I need to refresh the web page in the browser; when can I compile straight from the buffer; etc.)
  • Working with libraries
    • cljsbuild crossovers vs cljx
    • Debugging clj code used in cljs (log output from crossover files, etc.)

typo on tutorial-08

Perhaps change this:
"function, wich allows to attach an handling function"

To something like this:
"function, which allows us to attach a handling function"

switch to jayq?

looking at the table of contents, it seems like this is a tutorial series on domina, instead of clojurescript. if jayq is used, you won't have to spend so much time describing how a library works, and can spend more time describing the real topic, clojurescript

Exception (nrepl)

Hello,

Running lein cljx once I get the following exception

Exception in thread "main" java.io.FileNotFoundException: Could not locate clojure/tools/nrepl__init.class or clojure/tools/nrepl.clj on classpath:

If I add [org.clojure/tools.nrepl "0.2.3"] to the dependencies the error goes away.

Thanks

Exception when runnning lein

I was trying to get the project setup. Running lein ring server throws an exception.
I get a similar error when I run lein deps. I'm using lein 1.7. Could that be the cause?

$ lein ring server
Exception in thread "main" java.lang.ExceptionInInitializerError (ring.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:5440)
    at clojure.lang.Compiler.eval(Compiler.java:5415)
    at clojure.lang.Compiler.load(Compiler.java:5857)
    at clojure.lang.RT.loadResourceScript(RT.java:340)
    at clojure.lang.RT.loadResourceScript(RT.java:331)
    at clojure.lang.RT.load(RT.java:409)
    at clojure.lang.RT.load(RT.java:381)
    at clojure.core$load$fn__4519.invoke(core.clj:4915)
    at clojure.core$load.doInvoke(core.clj:4914)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:4729)
    at clojure.core$load_lib.doInvoke(core.clj:4766)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:542)
    at clojure.core$load_libs.doInvoke(core.clj:4800)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:542)
    at clojure.core$require.doInvoke(core.clj:4881)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at leiningen.core$resolve_task.invoke(core.clj:208)
    at leiningen.core$apply_task.invoke(core.clj:258)
    at leiningen.core$_main.doInvoke(core.clj:329)
    at clojure.lang.RestFn.applyTo(RestFn.java:139)
    at clojure.core$apply.invoke(core.clj:542)
    at leiningen.core$_main.invoke(core.clj:332)
    at user$eval42.invoke(NO_SOURCE_FILE:1)
    at clojure.lang.Compiler.eval(Compiler.java:5424)
    at clojure.lang.Compiler.eval(Compiler.java:5391)
    at clojure.core$eval.invoke(core.clj:2382)
    at clojure.main$eval_opt.invoke(main.clj:235)
    at clojure.main$initialize.invoke(main.clj:254)
    at clojure.main$script_opt.invoke(main.clj:270)
    at clojure.main$main.doInvoke(main.clj:354)
    at clojure.lang.RestFn.invoke(RestFn.java:482)
    at clojure.lang.Var.invoke(Var.java:381)
    at clojure.lang.AFn.applyToHelper(AFn.java:178)
    at clojure.lang.Var.applyTo(Var.java:482)
    at clojure.main.main(main.java:37)
Caused by: java.lang.ExceptionInInitializerError
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at clojure.lang.RT.loadClassForName(RT.java:1578)
    at clojure.lang.RT.load(RT.java:399)
    at clojure.lang.RT.load(RT.java:381)
    at clojure.core$load$fn__4519.invoke(core.clj:4915)
    at clojure.core$load.doInvoke(core.clj:4914)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:4729)
    at clojure.core$load_lib.doInvoke(core.clj:4766)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:542)
    at clojure.core$load_libs.doInvoke(core.clj:4800)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:544)
    at clojure.core$use.doInvoke(core.clj:4892)
    at clojure.lang.RestFn.invoke(RestFn.java:482)
    at leiningen.ring$eval68$loading__4414__auto____69.invoke(ring.clj:1)
    at leiningen.ring$eval68.invoke(ring.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:5424)
    ... 37 more
Caused by: java.lang.RuntimeException: java.util.zip.ZipException: error in opening zip file
    at clojure.lang.LazySeq.sval(LazySeq.java:47)
    at clojure.lang.LazySeq.seq(LazySeq.java:56)
    at clojure.lang.RT.seq(RT.java:450)
    at clojure.core$seq.invoke(core.clj:122)
    at clojure.core$apply.invoke(core.clj:540)
    at clojure.core$mapcat.doInvoke(core.clj:2122)
    at clojure.lang.RestFn.invoke(RestFn.java:423)
    at leiningen.util.ns$namespaces_matching.invoke(ns.clj:68)
    at leiningen.help__init.load(Unknown Source)
    at leiningen.help__init.<clinit>(Unknown Source)
    ... 57 more
Caused by: java.util.zip.ZipException: error in opening zip file
    at java.util.zip.ZipFile.open(Native Method)
    at java.util.zip.ZipFile.<init>(ZipFile.java:131)
    at java.util.jar.JarFile.<init>(JarFile.java:150)
    at java.util.jar.JarFile.<init>(JarFile.java:114)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:532)
    at clojure.lang.Reflector.invokeConstructor(Reflector.java:160)
    at leiningen.util.ns$namespaces_in_jar.invoke(ns.clj:52)
    at clojure.core$map$fn__3699.invoke(core.clj:2096)
    at clojure.lang.LazySeq.sval(LazySeq.java:42)
    ... 66 more

[REQUEST] Coverage of <strike>ClojureScript One</strike> Pedestal?

EDIT: changed title to reflect @magomimmo's comment pointing out that Pedestal supersedes CS1.

In my search to learn the best way to do modern clojure web development, I found this project, and ClojureScript One (CS1).

Some of these tutorials reference that project, and it would be really nice if an expert could explain the differences between them.

I've read through most of the modern-cljs tutorials (up to 13), and am now beginning to explore CS1 (via its M003 branch which supports Leiningen 2). The differences between them are striking, and CS1 seems to support some very neat workflow features not covered or taught in these tutorials.

Whereas the workflow recommended here involves having three terminals open, CS1 only needs one (or optionally, two). Its project.clj file is also radically different as it doesn't use cljsbuild! At the same time, it even seems to support recompiling and reloading both clj and cljs files upon modification!

It would be awesome if a tutorial could discuss CS1 and incorporate some of its neat features.

Thoughts?

Two issues immediately preventing me from running the tutorial

Hi, great work on the tutorial. But I immediately got stuck on two issues. First, I'm running the tutorial on a server, not "localhost". Second, my port 9000 was already taken. This is a pity, considering the amount of effort that was (supposedly) put into making this whole tutorial run out of the box.

Adjust the main source-paths

From the 15th tutorial included, ddjust the main :source-paths in the project.clj to allow the cljs pathnames used in the :cljsbuild :source-paths setting to be added to the project classpath. This has been done only

Tutorial 11 - Don't need to wrap validate-form

I'm just going through this tutorial, but noticed that validate-form seems to be wrapped in an anonymous function unnecessarily. Apologies if this is fixed in a subsequent tutorial, or I'm otherwise missing something.

Very informative tutorial. Thanks!

Tutorial-18 Review Profiles

The content of the second part of the tutorial-18 which introduced profiles.clj to simplify the project.clj is based on a misunderstanding of the features of lein profiles. It will be updated as soon as possibile. Sorry about that.

Pointless anonymous fn?

Am I wrong, or is the modification below meaningless?

It would seem that an anonymous 1-argument function which calls validate-form is exactly the same thing as validate-form, no? what would we gain from making the switch?

One last code modification in the init function and we're done.

(defn ^:export init []
  ;; verify that js/document exists and that it has a getElementById
  ;; property
  (if (and js/document
           (aget js/document "getElementById"))
    (listen! (by-id "submit") :click (fn [e] (validate-form e)))))

Here we just wrap inside an anonymous function the validate-form listener by passing it the fired event (i.e.:click).

Using the REPL doesn't really work very well....

I am having problems using the REPL. Sometimes it doesn't connect, sometimes it doesn't react until I reload the page and in chapter 5 calling (calculate) only results in this error:

ClojureScript:modern-cljs.shopping> (calculate)
"Error evaluating:" (calculate) :as "modern_cljs.shopping.calculate.call(null)"

<TypeError: Object # has no method 'call'>

TypeError: Object # has no method 'call'
at calculate (http://localhost:3000/js/modern.js:28812:16)
at eval (eval at (http://localhost:3000/js/modern.js:33937:260), :1:96)
at eval (eval at (http://localhost:3000/js/modern.js:33937:260), :5:3)
at http://localhost:3000/js/modern.js:33937:255
at evaluate_javascript (http://localhost:3000/js/modern.js:33950:4)
at Object.callback (http://localhost:3000/js/modern.js:34015:181)
at goog.messaging.AbstractChannel.deliver (http://localhost:3000/js/modern.js:31764:13)
at goog.net.xpc.CrossPageChannel.xpcDeliver (http://localhost:3000/js/modern.js:33306:14)
at Function.goog.net.xpc.NativeMessagingTransport.messageReceived_ (http://localhost:3000/js/modern.js:32720:13)
at goog.events.Listener.handleEvent (http://localhost:3000/js/modern.js:26716:26)
nil

Does anybody have any idea what the problem might be? This is all local on one machine so I assume it should run more smoothly.

Magic dependency number in Tutorial #1?

I've just completed the first tutorial and so far very nicely done.

However, I think I missed how you determined the dependency version for clojurescript. The feedback before it is set was

You're using [lein-cljsbuild "1.0.0"], which is known to work well with ClojureScript 0.0-2014 - *.

And in the update edit, you've used "0.0-2069", but it isn't clear to me how you determined that this was the correct version.

XSS & BREPL

I was banging my head trying to understand why I couldn't get the BREPL to work, when I finally tried in Safari (on OS X) and got XSS errors.

Can anyone else reproduce or corroborate this?

Anyhow, disabling XSS in a browser does the trick:
http://stackoverflow.com/a/23986416/586893

Should this be mentioned in Tutorial 2?

Progressive Enhancements & form validation

The tutorial makes a number of references to PE, yet completely breaks a core native behavior: letting the browser validate forms when JS is not available.

the noValidate form attribute should be set in clojurescript (when the submit event is bound), and the button should remain a submit button, so that JS-less users whose browser natively implements form validation still gets working validation instead of having to rely on server-side validation only.

Compiling after making easy changes produces class not found message

Thanks for the great work on these tutorials. Not only do I better understand ClojureScript, but I also better understand modern Javascript.

I made the "easy" changes from Tutorial 06. However, once I begin editing the project.clj, file, I receive the following error message when running either "lein cljsbuild clean" or "lein cljsbuild once":

java.lang.Exception: Error loading D:\cygwin\home\l.jones\professional\projects\modern-cljs\project.clj
at leiningen.core.project$read$fn__3326.invoke(project.clj:696)
at leiningen.core.project$read.invoke(project.clj:693)
at leiningen.core.project$read.invoke(project.clj:703)
at leiningen.core.main$_main$fn__3092.invoke(main.clj:294)
at leiningen.core.main$_main.doInvoke(main.clj:290)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:419)
at clojure.lang.AFn.applyToHelper(AFn.java:163)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.core$apply.invoke(core.clj:617)
at clojure.main$main_opt.invoke(main.clj:335)
at clojure.main$main.doInvoke(main.clj:440)
at clojure.lang.RestFn.invoke(RestFn.java:457)
at clojure.lang.Var.invoke(Var.java:427)
at clojure.lang.AFn.applyToHelper(AFn.java:172)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.main.main(main.java:37)
Caused by: java.lang.ClassNotFoundException: modern-cljs.core, compiling:(D:\cygwin\home\l.jones\professional\projects\modern-cljs\p
roject.clj:0:0)
(other stuff elided)

Here's my project.clj file:

(defproject modern-cljs "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}

;; Clojure and ClojureScript source code paths
:source-paths ["src/clj", "src/cljs"]
:dependencies [[org.clojure/clojure "1.5.1"]
[org.clojure/clojurescript "0.0-2173"]
[compojure "1.1.6"]
[domina "1.0.3-SNAPSHOT"]]

;; Leiningen plugin to help building ClojureScript projects.
:plugins [[lein-cljsbuild "1.0.2"]
[lein-ring "0.8.10"]]

;; ClojureScript build configuration
:cljsbuild {:builds
;; Generate login.js
{:login
{:source-paths ["src/cljs/login"]
:compiler
{:output-to "resources/public/js/login.js"
:optimization :whitespace
:pretty-print true}}}})

;; Ring configuration
:ring {:handler modern-cljs.core/handler})

Although this file only has the "login target," I originally encountered this issue when I had both the "login target" and the "shopping target."

I only find a core file in the Clojure source (the line beginning with ./src):

$ find . -name 'core*'
./out/cljs/core.cljs
./out/cljs/core.js
./src/clj/modern_cljs/core.clj
./target/cljsbuild-compiler-0/cljs/core.cljs
./target/cljsbuild-compiler-0/cljs/core.js
./test/modern_cljs/core_test.clj

Because I'm on Windows and because I'm learning ClojureScript (although I'm familiar with Linux and use cygwin and I am familiar with Clojure), it is possible that this issue is caused by "user error."

Thanks.

DRY Principle

Try to be as focus as possibile on the DRY principle. I prefer much more that a chip makes multiple times the same calculation, than my self writing twice the same things

Tutorial 2: clojure.browser.repl doesn't exist?

I'm at Tutorial 2, and this part doesn't seem to work:

(ns modern-cljs.connect
  (:require [clojure.browser.repl :as repl]))
(repl/connect "http://localhost:9000/repl")

I tried on the repl and clojure.browser.repl is not found.

Tutorial 4 : To add what happens if novalidate is missing/incorrect.

By mistake I had added nonvalidate instead of novalidate and I never got that alert. And I was very confused what happened.

Just around this :
"If you're using an HTML5 browser, instruct the form to deactivate input validation by adding novalidate as the last attribute of the form"

It would be nice if you add what is the default popup you get and if you are getting it, to check if one has added novalidate correctly.

Also a minor mistake :
"We're almost done. Copy styless.css file from ch02/css of Modern JS Code to resources/public/css directory."

s/styless.css/style.css

Thanks for this great series. :)

Error in tutorial 18 - Dev profile

I belive I've spotted an error in:
https://github.com/magomimmo/modern-cljs/blob/master/doc/tutorial-18.md#dev-profile

This is wrong (look at the provided comments inside the code):

(defproject
  ...
  :profiles {:dev {:dependencies [[com.cemerick/piggieback "0.1.0"]]} ; <- notice the curly bracket at the end
                   :repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}
                   :injections [(require '[cljs.repl.browser :as brepl]
                                         '[cemerick.piggieback :as pb])
                                (defn browser-repl []
                                  (pb/cljs-repl :repl-env
                                                (brepl/repl-env :port 9000)))]} ; <- I should be here in stead

gzipping in Tutorial 7

The tutorial states:

We reached 183KB and, if you gzip it, you'll reach 41KB

It would be helpful to say something here about how to serve up gzipped files in a way the browser can decode them, since the reader will inevitably try it, and simply gzipping the js file at the command line doesn't work.

There's this blog post from Cemerick about how to do it through Ring:

http://cemerick.com/2011/04/22/adding-gzip-compression-to-a-clojure-webapp-in-30-seconds/

(see also the comment from Kevin Lynagh at the bottom)

But it assumes more knowledge of Ring and Jetty than this tutorial does.

Source maps

It seems the biggest thing to happen in ClojureScript recently is source maps. It's a fairly dramatic improvement, and not using them isn't "modern" :-)

I'd love to see a tutorial on enabling them and using them in debugging.

Tut 14 clarification (updated route)

In the first part of "Step Two", which introduces Enlive, the last part of the "Let's Code" section has the student try out the new template that returns the templated HTML with all the original default values.

It hasn't changed the route yet at that point (unless I just totally missed a step). So it's still returning the original "You entered ..." string.

The updated route does show up near the bottom, just under Note 7.

BTW, I think it's awesome that this tutorial is so well-written that this is really the first minor glitch I've noticed. Thanks so much for it!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.