I haven’t played with Dart since – oh, I don’t know, 2013 or so. It was nice, but nothing felt compelling compared to the languages I already used. I stopped hearing about Dart when I stopped using Google+.
Nowadays, Dart is a bit more interesting.
The language itself has evolved, of course. So have all the other languages. What’s interesting is that Dart powers Flutter, Google’s cross-platform application development framework. You can write Flutter applications for Windows, macOS, Linux, iOS, Android, and oh yeah Web frontends.
That’s pretty dang cool.
I want to look at the Dart language itself – figure out how to use it for basic command line applications before I confuse myself with multi-platform GUI development.
Writing a Dart script
I start exploring a new or forgotten language by answering a few questions:
- How do I print something out in a terminal?
- How do I get user input in a terminal?
- How do I print variables such as user input?
There are nearly always multiple answers to each, but here’s a start.
The basic answers to my basic questions:
- dart:io gives us handles for standard output, standard error, and standard input
print()
prints a string of text on its own line- Stdin.readLineSync() gets us a line of input from the user
- Dart strings support variable interpolation
The big question though is how do I even run the dang thing
Running my Dart script
I could give it a #!/usr/bin/env
shebang line at the top and chmod 755 hello.dart
. Then I’d have a nice traditional script executable on any machine with the Dart runtime. But there’s a better way, and that starts with using the Dart compiler.
Using the Dart compiler
Compiling this Dart code into an executable for my current machine takes one line.
Dart’s executable compilation adds an .exe
extension to the output file regardless of platforn by default. That extension doesn’t matter to macOS or Linux – a filename is just a filename on those platforms – but I dislike seeing a .exe
anywhere but on Windows.
Anyways! I have an executable file. I can run it.
I can put that on any macOS device and run it without installing Dart on it. Of course, I only have one macOS device, and it has Dart installed on it. But the idea is the important part.
And the idea here is a simpler one: the same commands will compile the same code, regardless of what machine I’m on. I wrote most of this post on a Windows desktop. I edited and fine-tuned on an Apple laptop. The code worked as-is. The only invocation change I made was the -o
option for personal taste.
[!NOTE] Compile Targets Dart cannot cross-compile for other platforms yet. Compiling an executable on Windows gets you a Windows executable. But
dart compile
subcommands provide multiple targets in a Dart context. Some will run on any device. Some can run without a Dart runtime.
Subcommand Explanation Run without Dart? Multi-Platform? exe
standalone executable yes no jit-snapshot
just-in-time snapshot with hot reloading no no aot-snapshot
ahead-of-time snapshot no no kernel
intermediate representation of code no yes js
JavaScript 1 yes yes Oh, and trivia:
dart run greet_me.dart
compiles a JIT snapshot in the background and runs that.
Next problem: I’m coming in from Python and Rich for CLI applications. That name prompt should look so much better. I’m not ready to port Rich and Textual to Dart just yet. Maybe somebody has put some kind of console prompt handler on pub.dev, the Dart package repository?
Looks like DCli has what I’m looking for today, and functions for stuff I want to do later as well. Let’s try it out!
Time to move from a standalone script file to a project, so I can more easily manage dependencies.
Building a Dart Project
dart create
generates a project scaffold. It needs at least a project name. By default it creates what you need for a command line application, and those defaults are exactly what I need today. More than I need today, really.
There’s a lot going on in there, most of which I ignore in my dedicated pursuit of “running some Dart code.”
Add a project dependency
The dart pub
commands handle dependency management and publishing your project to Pub. So let’s use that to add Dcli as a dependency.
Since this is a pub
command, it does not surprise me that this dependency detail has been added to pubspec.yaml
. That’s where I’ll find most information about the project.
Back to the code! I’ll write a cute little greeter function in lib/greet_me.dart
which adds a lightly formatted prompt to my name request.
I can just have main
use that greeter function. When I start thinking in terms of projects rather than scripts, I tend to make the application entrypoint minimal, with the logic out in project library files where they’re easier to test.
Not that I’m writing any test code today.
Run the project application
dart run
works without arguments here, probably because I only have a single file with main()
defined.
Neat. Okay there’s not much in a straight paste of output. Here’s a screenshot, so you can see the visual effect from red()
.
That’s better than what I had.
Compile the project application
What if I want to compile it? That’s pretty much the same process as with the script. Dart doesn’t make any assumptions about files when it comes to compiling an executable.
I’m sure there’s some kind of build tool out there to simplify the process, but my knowledge hasn’t gotten that far yet. Until then, this invocation could be put in a justfile`` for my normal project flow.
What now?
I’m still early in my exploration of Dart and Flutter, learning not just what Dart code looks like but what it should look like. I may add some notes about linting and code analysis tools later. I’m sure to explore DCli, which has a wealth of functions relevant to command line utility scripts. And I definitely want to learn more about how big cross-platform Dart projects are handled.
Meanwhile, I need to see more of the Dart world.
- connect to some Dart community resources
- check out the Awesome Dart repository to see cool things other folks do with the language
Backlinks
Got a comment? A question? More of a comment than a question?
Added to vault 2024-01-15. Updated on 2024-02-01