Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 145 lines (112 sloc) 5.257 kb
771f2bd @emezeske Breaking down the giant monolithic README.
authored
1 # Sharing Code Between Clojure and ClojureScript
2
3 Sharing code with lein-cljsbuild is accomplished via the configuration
4 of "crossovers". A crossover specifies a Clojure namespace, the content
5 of which should be copied into your ClojureScript project. This can be any
6 namespace that is available via the Java CLASSPATH, which includes your
7 project's main :source-path by default.
8
9 When a crossover namespace is provided by your current project (either via the
443609e @emezeske Minor formatting fixes.
authored
10 main `:source-dir` or one of the `:extra-classpath-dirs` in your project.clj file),
771f2bd @emezeske Breaking down the giant monolithic README.
authored
11 the files that make up that namespace (recursively) will be monitored for changes,
12 and will be copied to the ClojureScript project whenever modified.
13
14 Crossover namespaces provided by jar files cannot be searched recursively, and
15 thus must be specified on a per-file basis. They are copied over once, when
16 lein-cljsbuild begins compilation, and are not monitored for changes.
17
18 Of course, remember that since the namespace will be used by both Clojure
19 and ClojureScript, it will need to only use the subset of features provided by
20 both languages.
21
22 Assuming that your top-level directory structure looks something like this:
23
24 <pre>
9d8d3f1 @emezeske Update the crossover documentation.
authored
25 └── src-clj
771f2bd @emezeske Breaking down the giant monolithic README.
authored
26    └── example
9d8d3f1 @emezeske Update the crossover documentation.
authored
27    ├── core.clj
28    ├── something.clj
29    └── crossover
30       ├── some_stuff.clj
31       └── some_other_stuff.clj
771f2bd @emezeske Breaking down the giant monolithic README.
authored
32 </pre>
33
34 And your `project.clj` file looks like this:
35
36 ```clj
37 (defproject lein-cljsbuild-example "1.2.3"
8aa66fb @emezeske Bump the version.
authored
38 :plugins [[lein-cljsbuild "0.1.8"]]
771f2bd @emezeske Breaking down the giant monolithic README.
authored
39 :source-path "src-clj"
40 :cljsbuild {
9d8d3f1 @emezeske Update the crossover documentation.
authored
41 ; Each entry in the :crossovers vector describes a Clojure namespace
42 ; that is meant to be used with the ClojureScript code as well.
43 ; The files that make up this namespace will be automatically copied
44 ; into the ClojureScript source path whenever they are modified.
45 :crossovers [example.crossover]
46 ; Set the path into which the crossover namespaces will be copied.
47 :crossover-path "crossover-cljs"
48 ; Set this to true to allow the :crossover-path to be copied into
49 ; the JAR file (if hooks are enabled).
50 :crossover-jar false})
771f2bd @emezeske Breaking down the giant monolithic README.
authored
51 ```
52
53 Then lein-cljsbuild would copy files from `src-clj/example/crossover`
9d8d3f1 @emezeske Update the crossover documentation.
authored
54 to `crossover-cljs`, and you'd end up with this:
771f2bd @emezeske Breaking down the giant monolithic README.
authored
55
56 <pre>
57 ├── src-clj
58 │   └── example
59 │   ├── a_file.clj
60 │   ├── core.clj
61 │   └── crossover
62 │      ├── some_stuff.clj
63 │      └── some_other_stuff.clj
9d8d3f1 @emezeske Update the crossover documentation.
authored
64 └── crossover-cljs
771f2bd @emezeske Breaking down the giant monolithic README.
authored
65    └── example
9d8d3f1 @emezeske Update the crossover documentation.
authored
66    └── crossover
67      ├── some_stuff.cljs
68      └── some_other_stuff.cljs
771f2bd @emezeske Breaking down the giant monolithic README.
authored
69 </pre>
70
9d8d3f1 @emezeske Update the crossover documentation.
authored
71 Notice that the files in the `crossover-cljs` directory have had their extensions
72 modified so that they will be seen by the ClojureScript compiler. The `crossover-cljs`
73 directory will automatically be added to the classpath for the ClojureScript compiler,
74 so your other ClojureScript code should be able to reference it via a regular `(ns)` form.
75
76 With this setup, you would probably want to add `crossover-cljs`
771f2bd @emezeske Breaking down the giant monolithic README.
authored
77 to your `.gitignore` file (or equivalent), as its contents are updated automatically
78 by lein-cljsbuild.
79
80 # Sharing Macros Between Clojure and ClojureScript
81
82 In ClojureScript, macros are still written in Clojure, and can not be written
83 in the same file as actual ClojureScript code. Also, to use them in a ClojureScript
84 namespace, they must be required via `:require-macros` rather than the usual `:require`.
85
86 This makes using the crossover feature to share macros between Clojure and ClojureScript
87 a bit difficult, but lein-cljsbuild has some special constructs to make it possible.
88
89 Three things need to be done to use lein-cljsbuild to share macros.
90
91 ## 1. Keep Macros in Separate Files
92
93 These examples assume that your project uses the `src-clj/example/crossover`
94 directory, and that all of the macros are in a file called
95 `src-clj/example/crossover/macros.clj`.
96
97 ## 2. Tell lein-cljsbuild Which Files Contain Macros
98
99 Add this magical comment to any crossover files that contain macros:
100
101 ```clj
102 ;*CLJSBUILD-MACRO-FILE*;
103 ```
104
105 This tells lein-cljsbuild to refrain from copying the `.clj` files
9d8d3f1 @emezeske Update the crossover documentation.
authored
106 into the `:crossover-path`. This step can be skipped if the
771f2bd @emezeske Breaking down the giant monolithic README.
authored
107 macro file is not included in any of the crossover namespaces.
108
109 ## 3. Use Black Magic to Require Macros Specially
110
111 In any crossover Clojure file, lein-cljsbuild will automatically erase the
9d8d3f1 @emezeske Update the crossover documentation.
authored
112 following string when copying the Clojure file into the `:crossover-path`:
771f2bd @emezeske Breaking down the giant monolithic README.
authored
113
114 ```clj
115 ;*CLJSBUILD-REMOVE*;
116 ```
117
9d8d3f1 @emezeske Update the crossover documentation.
authored
118 This magic can be used to generate a `ns` statement that can successfully
119 reference a macro namespace from both Clojure and ClojureScript:
771f2bd @emezeske Breaking down the giant monolithic README.
authored
120
121 ```clj
122 (ns example.crossover.some_stuff
123 (:require;*CLJSBUILD-REMOVE*;-macros
124 [example.crossover.macros :as macros]))
125 ```
126
127 Thus, after removing comments, Clojure will see:
128
129 ```clj
130 (ns example.crossover.some_stuff
131 (:require
132 [example.crossover.macros :as macros]))
133 ```
134
135 However, lein-cljsbuild will remove the `;*CLJSBUILD-REMOVE*;` string entirely,
136 before copying the file. Thus, ClojureScript will see:
137
138 ```clj
139 (ns example.crossover.some_stuff
140 (:require-macros
141 [example.crossover.macros :as macros]))
142 ```
143
144 And thus the macros can be shared.
Something went wrong with that request. Please try again.