Dart: Project

Dart: Project

Understand projects and packages in Dart.

Here is the structure of a classic Dart project represented as a tree diagram:

├──bin
│ └── main.dart
├──lib
│ ├── model
│ │ └── user.dart
│ └── services
│ └── auth.dart
├──test
│ ├── model_test.dart 
│ └── services_test.dart 
├── web
│   ├── index.html
│   ├── main.dart
│   └── styles.css 
│        ├──.analysis_options.yaml 
│        ├──.gitignore 
│        └── pubspec.yaml

Some important points to note:

  • The lib folder contains the source code files that make up your library. It is organized into sub-folders like model, services etc.

  • The bin folder contains executable Dart files like main.dart which you can run directly.

  • The test folder contains test files that test the code in the lib folder.

  • The web folder contains files specific to web apps - HTML, CSS and the Dart entry point main.dart.

  • The pubspec.yaml file contains metadata and dependencies for your project.

  • The .gitignore file tells Git which files to ignore when committing.

  • The .analysis_options.yaml file contains config for the Dart Analyzer.

Hope this tree diagram representation helps visualize the structure of a classic Dart project! Let me know if you have any other questions.


File extension

The extension .dart is only used for Dart source files, i.e. files that contain Dart code.

Other file types used in Dart projects include:

  • .html: For HTML files used in web apps

  • .css: For CSS files used in web apps

  • .js: For JavaScript files

  • .yaml: For YAML configuration files like pubspec.yaml

  • .gitignore: For the Git ignore file

  • .analysis_options.yaml: For the Dart Analyzer config file

So in summary:

  • The .dart extension is used for Dart source files only, i.e. library files, executable files, test files, web entry points and part files.

  • Other file types used in Dart projects like HTML, CSS, JS, YAML and text config files use their standard extensions like .html, .css, .js, .yaml etc.

Hope this clarifies that the .dart extension is specific to Dart source files, and is not used for all file types in a Dart project.


Project Type

You can build a wide variety of projects with the Dart programming language, including:

• Web applications - Dart can compile to JavaScript, so it's perfect for building fast and secure web apps.

• Server-side applications - Dart has a native server-side runtime called Dart VM, so you can build server-side APIs, microservices, and command-line tools.

• Desktop applications - With Dart's native desktop runtime, you can build desktop apps for Windows, macOS and Linux.

• Mobile applications - Using the Flutter framework, you can build native mobile apps for both Android and iOS from the same Dart codebase.

• Games - Dart is a great choice for building 2D and 3D games thanks to libraries like StageXL and DartFX.

• Backend services - Dart's support for asynchronous programming and its efficient runtime make it suitable for building high performance backend services.

• ML/AI applications - Libraries like Dart ML and Tensor Flow provide APIs to build machine learning and AI applications in Dart.

• IoT applications - Dart's native runtimes allow you to build apps for devices like Raspberry Pi and Arduino.

• Cross-platform applications - Since Dart can compile to JavaScript and also has native runtimes, you can build apps that run on the web, mobile and desktop from the same codebase.

So in short, you have a lot of flexibility in the types of projects you can build with Dart - from simple web apps to complex AI/ML applications, games, and cross-platform apps. The choice of project depends mainly on your requirements and preferences.


Packages & Libraries

Packages and libraries are two ways to organize Dart code. Here's the difference:

Packages:

  • Packages are self-contained units of Dart code that can be imported and used by other Dart projects.

  • They are defined in a pubspec.yaml file.

  • This file specifies the package name, version, description and dependencies.

  • Packages can contain one or more libraries.

Libraries:

  • Libraries are individual units of Dart code that define APIs using classes, functions, types, etc.

  • They are defined in .dart files.

  • Libraries are usually organized based on functionality. For example, a UI library, a utility library, etc.

  • Libraries are exposed as part of packages. A package can contain one or more libraries.

So in summary:

  • Packages are the highest level of modularity in Dart. They define the scope of an API.

  • Libraries define the actual APIs within a package. They contain the Dart code - classes, functions, enums, etc.

When you import a package in another Dart project, you are actually importing the libraries defined within that package. For example:

import 'package:some_package/some_library.dart';

Here you are importing the some_library library which is defined within the some_package package.


main()

The main() function in Dart acts as the entry point for executing a Dart program.

The main() file in a Dart project usually has the following:

  1. The main() function - This is where the execution of the program starts. It has the following signature:
void main(){
    // program starts executing from here
}
  1. Imports - Any libraries or packages used in the project are imported atDart Libraries and Packages the top of the main file.

  2. Variables - Any global variables used throughout the program can be declared here.

  3. Function declarations - Any utility functions used in the program can be declared here.

  4. The main logic - The main logic and workflow of the program is written inside the main() function.

For example, a simple main.dart file could be:

import 'package:some_package/some_library.dart';

void main() {
  var name = 'John';

  sayHello(name);
}

void sayHello(String name) {
  print('Hello $name!');
}

Here:

  • We imported a library

  • Declared a global variable name

  • Declared a function sayHello()

  • The main logic is in the main() function which calls sayHello()

So in summary, the main.dart file:

  • Contains the main() entry point function

  • Imports any required libraries/packages

  • Declares global variables

  • Defines utility functions

  • Contains the main logic of the program

Main is unique

No, a Dart project can only have one main() function. Having multiple main() functions is not allowed and will result in an error.

The main() function acts as the entry point of the program, so logically only one main() function makes sense.

If you want to split up the logic in your program, you should:

  1. Define utility functions in libraries and import those libraries

  2. Call those utility functions from your single main() function

For example:

// util.dart
void doSomething() {
  // some logic...
}

void doSomethingElse() {
  // some other logic...  
}

// main.dart
import 'util.dart';

void main() {
  doSomething();
  doSomethingElse();
}

Here we have:

  • Defined 2 utility functions in util.dart

  • Imported util.dart in main.dart

  • Called those utility functions from our single main() function

So the best practice is to split up your logic into reusable functions and libraries, but still have a single main() function that acts as the entry point.


Public classes

There is no limit to the number of public classes you can create in a Dart file. You can have as many public classes as you want in a single file.

However, as mentioned in the previous answer, it is considered good practice to:

  • Keep related classes in the same file

  • Keep files focused - one or a few closely related classes per file

This results in code that is organized, clean and easy to navigate.

Also, note that:

  • Public classes can be used anywhere in your Dart app

  • Private classes (prefixed with _) can only be used within the file they are defined

For example:

// user.dart

class User { 
   // Public class
}

class _PrivateClass {
  // Private class - can only be used within this file 
}

You can then use the User class anywhere like this:

import 'user.dart';

void main() {
  User user = User();
}

But you cannot use the _PrivateClass outside of user.dart.

So in summary:

  • There is no limit on the number of public classes per Dart file

  • But for code organization, focus each file on 1-3 closely related public classes

  • Use private classes to encapsulate implementation details within a file


Folders

Yes, in Dart a package is closely related to a folder.

A Dart package consists of:

  • A folder - Contains the Dart files that make up the package

  • A pubspec.yaml file - Contains metadata about the package

For example, a simple Dart package structure could look like this:

my_package/
  ├── lib/
  │   ├── util.dart
  │   └── main.dart
  └── pubspec.yaml

Here:

  • my_package is the package folder

  • lib is the lib folder, which contains the Dart files that make up the package

  • util.dart and main.dart are the Dart source files

  • pubspec.yaml is the package metadata file

So in summary:

  • A Dart package consists of a folder

  • This folder contains:

    • Dart source files (in a lib folder by convention)

    • A pubspec.yaml file

  • The folder structure organizes and contains the files that make up the package

The pubspec.yaml file then provides metadata about the package like:

  • Package name

  • Version

  • Dependencies

  • Authors

  • Description


Yaml files

Yaml files in Dart use the YAML syntax. Some key points about the YAML syntax:

  • It uses indentation to indicate nesting, instead of curly braces {} or parentheses ()

  • Uses dashes - to indicate lists

  • Uses colons : to associate keys with values

For example:

name: my_package    # String value
version: 1.0.0      # String value

description: A useful Dart package  # String value

authors:            # List of strings
  - John Doe
  - Jane Doe

dependencies:       # Map  
  crypto: ^2.0.0    
  http: any

Here:

  • name, version, description are keys associated with string values using :

  • authors is a list denoted by the dash -

  • dependencies is a map with package names as keys and version constraints as values

The indentation indicates nesting, so the list items under authors are indented once, and the map values under dependencies are indented twice.

Some other points:

  • Strings can be single/double quoted

  • Boolean values are true and false (no quotes)

  • Comments start with #


CLI Create

You can use the Dart CLI (command line interface) to create a new Dart project using the dart create command.

To create a new Dart project from the CLI, follow these steps:

  1. Open your terminal or command prompt.

  2. Run the dart create command with the project name:

dart create <project_name>

For example:

dart create my_first_app
  1. This will create a folder with that name and generate the basic project structure:
  • A lib folder containing a main.dart file

  • A test folder for tests

  • A pubspec.yaml file

  • A .gitignore file

  1. Change directory into your new project:
cd <project_name>
  1. You can then run Dart commands from within your project folder, for example:
dart run bin/main.dart  # Runs your app
dart test              # Runs unit tests
dart pub get          # Downloads dependencies
  1. You can also use VS Code or any IDE to open your new Dart project folder.

So in summary, the basic steps are:

  1. Run dart create <project_name>

  2. cd <project_name>

  3. Run Dart commands from the project folder

  4. Open in VS Code or IDE


Interpretor

Dart is an interpreted language. This means that Dart code is not compiled to machine code before execution. Instead, Dart code is compiled to an intermediate bytecode which is then interpreted at runtime.

This is in contrast to compiled languages like C++ and Java, where the code is first compiled to machine code, and then the machine code is executed directly by the CPU.

Some benefits of Dart being an interpreted language are:

  • Faster development cycle: Since the code does not need to be compiled before each run, developers can make changes and run the code quickly.

  • Easier debugging: Since the original source code is available at runtime, debugging is simpler compared to compiled languages.

  • Cross-platform: The Dart bytecode can be interpreted to run on different platforms.

However, interpreted languages also tend to be slower than compiled languages, since the interpretation layer introduces some overhead.

To overcome this, Dart uses an optimizing compiler called "Just-in-Time (JIT) compiler" which compiles Dart bytecode to machine code at runtime. This helps improve the performance of Dart applications.

So in summary, yes Dart is an interpreted language. Dart code is first compiled to an intermediate bytecode which is then interpreted at runtime (with some JIT compilation optimizations). This allows Dart to have a fast development cycle while still achieving good performance.


Execution

You can execute a Dart project from the command line and pass parameters using the dart run command.

To pass parameters when running a Dart project, you use the syntax:

dart run [options] <entry-point> -- [arguments]

Where:

  • options are optional Dart VM options

  • <entry-point> is the path to your Dart file to run, usually bin/main.dart

  • -- is used to separate Dart options from your program arguments

  • [arguments] are the arguments you want to pass to your Dart program

For example, if you have a bin/main.dart file like this:

void main(List<String> arguments) {
  print(arguments);
}

You can run it and pass arguments like this:

dart run bin/main.dart -- hello world

The output will be:

[hello, world]

You can pass as many arguments as you want, separated by spaces:

dart run bin/main.dart -- arg1 arg2 arg3

The arguments will be available in the arguments list that is passed to your main() function.

You can also define a --help option in your program to print usage information:

void main(List<String> arguments) {
  if (arguments.contains('--help')) {
    print('Usage: dart_program arg1 arg2');
  } 
}

And then invoke it with:

dart run bin/main.dart -- --help

So in summary, you use dart run <entry-point> -- [arguments] to execute a Dart program from the command line and pass arguments to it.


Disclaim: I have used Rix (AI) to create this article. If you have reach this article, congratulation. Many other do not. Please do not tell anybody about my article. These are my private notes to learn Dart.