└── README.md
/README.md:
--------------------------------------------------------------------------------
1 | # Introduction
2 |
3 | On April 16th, the [ClojureDart](https://github.com/Tensegritics/ClojureDart) release made it possible for Clojure developers to create mobile, web, and desktop apps using Flutter.
4 |
5 | While tools are not yet fully developed, with the absence of a REPL and autocompletion for dart-interop, it is still possible to use ClojureDart. Also, some of the Clojure magic is being shown already, for example, check [the `nest` macro](https://github.com/Tensegritics/ClojureDart/blob/main/doc/flutter-helpers.md#nest-macro) (update: `widget` macro can do the same) and compare [similar clj-code vs dart](https://twitter.com/cgrand/status/1517652416396730369?t=T2md7PwYw8kfbulzAlVhUQ&s=09). I've also written a post about the benefits of using Clojure: [Why Flutter needs Clojure](https://functional.works-hub.com/learn/why-flutter-needs-clojure-45b93).
6 |
7 | The goal of this article is to show how to write your first Flutter app with Clojure, what tools to use, and where to ask questions. The reader should keep in mind that minor clojure experience is required.
8 |
9 | # The tools
10 |
11 | For the ClojureDart journey you would need to [set up Flutter](https://docs.flutter.dev/get-started/install) on your machine, [Clojure cli](https://clojure.org/guides/deps_and_cli), and additionally I would recommend [Clj-kondo](https://github.com/clj-kondo/clj-kondo) (note that it's already built in lsp). The last would be helpful for [widget macro](https://github.com/Tensegritics/ClojureDart/blob/main/doc/flutter-helpers.md#widget-macro) warnings:
12 |
13 | 
14 |
15 | # Choose your the editor
16 |
17 | ## VSCode — easy to start
18 |
19 | The easiest option to start ([docs](https://calva.io/clojuredart)). Just install Calva, and you are ready to go:
20 |
21 | https://user-images.githubusercontent.com/14236531/166266488-75e3d9ef-7e0a-421f-b87d-87d727195280.mp4
22 |
23 | I would also recommend installing the Flutter extension ([docs](https://docs.flutter.dev/development/tools/vs-code)).
24 |
25 | Pros:
26 | - fast and easy to set up;
27 | - Dart->Clojure converter support;
28 | - unique [Joyride](https://marketplace.visualstudio.com/items?itemName=betterthantomorrow.joyride) plugin, that allows to run editor scripts with Clojure REPL.
29 |
30 | ## Intellij Idea — no support yet
31 |
32 | The result you would get (typing `reduce-` to show clojure-autocompletion):
33 |
34 |
35 |
36 | As you see, there are warnings on dart-interop, and it's impossible to get rid of them without turning on "Power Safe Mode".
37 |
38 | Pros:
39 | - almost nothing to set up;
40 | - support will be there, and everything will get to work.
41 |
42 | Cons:
43 | - Extremely slow startup (could be more than 1 minute until syncing, indexing, resolutions, etc. is completed on my air);
44 | - No way to turn off dart-interop warnings.
45 |
46 | Anyway, for setting the Idea up you would need 3 things:
47 | [Cursive plugin](https://cursive-ide.com/).
48 | [Flutter plugin](https://docs.flutter.dev/development/tools/android-studio) (to be able to search through the dart code).
49 | [Clojure-extras](https://plugins.jetbrains.com/plugin/18108-clojure-extras) plugin (for Clj-kondo linting support).
50 |
51 | Also don't forget to set up `\*.cljd` files as Clojure files:
52 | `preferences -> editor -> filetypes -> clojure file -> file patterns -> + -> \*.cljd`
53 |
54 | ## Vim
55 |
56 | Same example with `reduce-`:
57 |
58 |
59 |
60 | Pros:
61 | - speed, the ability to open tens (and hundreds) of projects at the same time in milliseconds;
62 | - extended customization;
63 | - REPL will be integrated out of the box with ClojureDart REPL release;
64 | - the ability to write config in Lisp (Fennel).
65 |
66 | Cons:
67 | - need to learn how to use vim;
68 | - need to spend some time on setting everything up;
69 | - sometimes need to fix things after updates.
70 |
71 | Below there are several options on how to set up Vim for ClojureDart.
72 |
73 | ### Nvim with lsp
74 |
75 | Need to set up a [lsp-plugin](https://github.com/neovim/nvim-lspconfig) and 2 lsp servers: for [Clojure](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#clojure_lsp) and for [Flutter](https://github.com/akinsho/flutter-tools.nvim) (for the ability to search through the dart code). Need to add one line to set up `*.cljd`:
76 | ```vimscript
77 | au! BufRead,BufNewFile *.cljd setfiletype clojure
78 | ```
79 | I am using this config at the moment and besides dart-interop there are almost everything: refactorings, goto definition, find usages, autocompletion, docs, namespace cleaning.
80 |
81 | [My config](https://github.com/d00mch/dotfiles/blob/master/.config/nvim/fnl/plugin/lspconfig.fnl) is written in Fennel. Going through this is out of the scope of this article. If you want to try using Lisp for configuration yourself, I would recommend starting with [aniseed](https://github.com/Olical/aniseed) plugin and the authors dotfiles. As the first config you could use [this project](https://github.com/rafaeldelboni/nvim-fennel-lsp-conjure-as-clojure-ide) or try [nyoom](https://github.com/shaunsingh/nyoom.nvim) setup.
82 |
83 | ### Vim with the VimIced plugin
84 |
85 | You would need to set up everything with the plugin's [wiki](https://liquidz.github.io/vim-iced/) and use Clj-Kondo as the linter (use this [instruction](https://github.com/clj-kondo/clj-kondo/blob/master/doc/editor-integration.md#ale)). Until ClojureDart REPL is released, lots of features will not be supported.
86 |
87 | Vim with Fireplace
88 |
89 | I haven't used [Fireplace](https://github.com/tpope/vim-fireplace) recently (last 3 years). I guess the experience will be somewhat of VimIced. Be sure to write:
90 |
91 | `au! BufRead,BufNewFile *.cljd setfiletype clojure`
92 |
93 | ## Emacs
94 |
95 | ClojureDart authors are using Emacs, and [Clojure-mode](https://github.com/clojure-emacs/clojure-mode/blob/master/clojure-mode.el) has already added cljd (don't need to do anything yourself). I think the pros and cons will be similar to vim, with some details that are out of the scope.
96 |
97 | # The workflow
98 |
99 | Good to start with the [hello-world](https://github.com/Tensegritics/ClojureDart/blob/main/doc/flutter-quick-start.md) and get comfortable with the tools. Here is a [video](https://www.youtube.com/watch?v=dfmRNTmfYVg&t=743s&ab_channel=ClojureDart) with the workflow.
100 |
101 | I would open 3 windows:
102 | 1. Dart file (could be a `\*.dart` file inside `lib/` directory) to be able to experiment with dart code, to check signatures, fields and methods.
103 | 2. Terminal to see the logs and to interact with the hot-reload;
104 | 3. Emulator, in my experience Android is the good one. The easiest way to set up one is to install AndroidStuod and use Tools->DeviceManagement.
105 |
106 | After you launch a watcher:
107 | ```shell
108 | clj -M -m cljd.build flutter
109 | ```
110 | Go to the loop: write code, save file, see feedback, repeat.
111 |
112 | - Need a *hot-reload*, save file.
113 | - Need a *hot-restart*, press Enter in the terminal.
114 | - Need to *cold-reborn*, remove `.clojuredart/` dir and restart the watcher.
115 |
116 | ## Using Libraries
117 |
118 | As in the Flutter project, add libs in the `pubspec.yaml` file. Import it as a string like you would in the \*.dart files:
119 | ```clojure
120 | (:require
121 | [clojure.string :refer [join]]
122 | ["package:graphql/client.dart" :as g])
123 | ```
124 | And currently it's impossible to import a dart class without having it as a dependency in `pubspec.yml`.
125 |
126 | ## Building widget tree approach
127 |
128 | In most of the cases you should write a function like [here](https://github.com/Tensegritics/ClojureDart/tree/main/samples) in the authors' examples; and not declare a class with deftype like I did [here](https://github.com/d00mch/minataurus/blob/custom-widget/src/minataurus/fab.cljd). And StatefulWidgets should be created with the [alpha/widget macro](https://github.com/Tensegritics/ClojureDart/blob/main/doc/flutter-helpers.md#widget-macro). Take a look at the [commit](https://github.com/d00mch/minataurus/commit/4102ae4b8c38e4fd0721a3a1ffac9d091c589be8) where I fixed it. Less code, and the code is more clear.
129 |
130 | There is also a [tool](https://github.com/d00mch/DartClojure) to convert Dart code to Clojure code, which helps to rewrite widgets (not general Dart).
131 |
132 | 
133 |
134 | ## ClojureDart differs from Clojure
135 |
136 | First, consider reading [the docs](https://github.com/Tensegritics/ClojureDart/blob/main/doc/differences.md) from authors upon the subject.
137 |
138 | Next, you would definitely stumble upon the lack of libraries that return plain old Clojure PersistentHashMap. Instead you will have to deal with dart Maps. Here in the [GraphQL example](https://github.com/d00mch/ClojureDartTeaExample/blob/main/src/tea/api.cljd) I wrote a function to convert dart Map into clojure PersistentHashMap.
139 |
140 | # Resources
141 |
142 | 1. [Official docs](https://github.com/Tensegritics/ClojureDart/tree/main/doc) on ClojureDart
143 | 2. [ClojureDart roadmap](https://github.com/Tensegritics/ClojureDart/projects/1)
144 | 3. [Samples](https://github.com/Tensegritics/ClojureDart/tree/main/samples) by the authors
145 | 4. [GraphQL + MVU sample](https://github.com/d00mch/ClojureDartTeaExample)
146 | 5. Custom widgets with deftype [sample](https://github.com/d00mch/minataurus/blob/custom-widget/src/minataurus/fab.cljd)
147 | 6. Community: Clojurians [channel](https://clojurians.slack.com), #clojuredart
148 | 7. YouTube [channel](https://www.youtube.com/channel/UCCkvOkh6pXzYqkFKDgoyWRg).
149 | 8. Dev's Twitter: [cgrand](https://twitter.com/cgrand), [BaptisteDupuch](https://twitter.com/BaptisteDupuch)
150 | 9. DartClojure [Workshop](https://clojure.stream/workshops/clojuredart)
151 |
--------------------------------------------------------------------------------