Skip to content

Live article on ClojureDart development introduction

Notifications You must be signed in to change notification settings

D00mch/HowToClojureDart

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 

Repository files navigation

Introduction

On April 16th, the ClojureDart release made it possible for Clojure developers to create mobile, web, and desktop apps using Flutter.

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 (update: widget macro can do the same) and compare similar clj-code vs dart. I've also written a post about the benefits of using Clojure: Why Flutter needs Clojure.

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.

The tools

For the ClojureDart journey you would need to set up Flutter on your machine, Clojure cli, and additionally I would recommend Clj-kondo (note that it's already built in lsp). The last would be helpful for widget macro warnings:

clj-kondo-warnings

Choose your the editor

VSCode — easy to start

The easiest option to start (docs). Just install Calva, and you are ready to go:

vscode-calva.mp4

I would also recommend installing the Flutter extension (docs).

Pros:

  • fast and easy to set up;
  • Dart->Clojure converter support;
  • unique Joyride plugin, that allows to run editor scripts with Clojure REPL.

Intellij Idea — no support yet

The result you would get (typing reduce- to show clojure-autocompletion):

idea example

As you see, there are warnings on dart-interop, and it's impossible to get rid of them without turning on "Power Safe Mode".

Pros:

  • almost nothing to set up;
  • support will be there, and everything will get to work.

Cons:

  • Extremely slow startup (could be more than 1 minute until syncing, indexing, resolutions, etc. is completed on my air);
  • No way to turn off dart-interop warnings.

Anyway, for setting the Idea up you would need 3 things: Cursive plugin. Flutter plugin (to be able to search through the dart code). Clojure-extras plugin (for Clj-kondo linting support).

Also don't forget to set up \*.cljd files as Clojure files: preferences -> editor -> filetypes -> clojure file -> file patterns -> + -> \*.cljd

Vim

Same example with reduce-:

vim example

Pros:

  • speed, the ability to open tens (and hundreds) of projects at the same time in milliseconds;
  • extended customization;
  • REPL will be integrated out of the box with ClojureDart REPL release;
  • the ability to write config in Lisp (Fennel).

Cons:

  • need to learn how to use vim;
  • need to spend some time on setting everything up;
  • sometimes need to fix things after updates.

Below there are several options on how to set up Vim for ClojureDart.

Nvim with lsp

Need to set up a lsp-plugin and 2 lsp servers: for Clojure and for Flutter (for the ability to search through the dart code). Need to add one line to set up *.cljd:

au! BufRead,BufNewFile *.cljd setfiletype clojure

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.

My config 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 plugin and the authors dotfiles. As the first config you could use this project or try nyoom setup.

Vim with the VimIced plugin

You would need to set up everything with the plugin's wiki and use Clj-Kondo as the linter (use this instruction). Until ClojureDart REPL is released, lots of features will not be supported.

Vim with Fireplace

I haven't used Fireplace recently (last 3 years). I guess the experience will be somewhat of VimIced. Be sure to write:

au! BufRead,BufNewFile *.cljd setfiletype clojure

Emacs

ClojureDart authors are using Emacs, and Clojure-mode 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.

The workflow

Good to start with the hello-world and get comfortable with the tools. Here is a video with the workflow.

I would open 3 windows:

  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.
  2. Terminal to see the logs and to interact with the hot-reload;
  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.

After you launch a watcher:

clj -M -m cljd.build flutter

Go to the loop: write code, save file, see feedback, repeat.

  • Need a hot-reload, save file.
  • Need a hot-restart, press Enter in the terminal.
  • Need to cold-reborn, remove .clojuredart/ dir and restart the watcher.

Using Libraries

As in the Flutter project, add libs in the pubspec.yaml file. Import it as a string like you would in the *.dart files:

(:require
    [clojure.string :refer [join]]
    ["package:graphql/client.dart" :as g])

And currently it's impossible to import a dart class without having it as a dependency in pubspec.yml.

Building widget tree approach

In most of the cases you should write a function like here in the authors' examples; and not declare a class with deftype like I did here. And StatefulWidgets should be created with the alpha/widget macro. Take a look at the commit where I fixed it. Less code, and the code is more clear.

There is also a tool to convert Dart code to Clojure code, which helps to rewrite widgets (not general Dart).

Screen Recording 2022-05-29 at 19 38 44

ClojureDart differs from Clojure

First, consider reading the docs from authors upon the subject.

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 I wrote a function to convert dart Map into clojure PersistentHashMap.

Resources

  1. Official docs on ClojureDart
  2. ClojureDart roadmap
  3. Samples by the authors
  4. GraphQL + MVU sample
  5. Custom widgets with deftype sample
  6. Community: Clojurians channel, #clojuredart
  7. YouTube channel.
  8. Dev's Twitter: cgrand, BaptisteDupuch
  9. DartClojure Workshop

About

Live article on ClojureDart development introduction

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published