user1338952
user1338952

Reputation: 3391

how to have libraries import libraries from the same package?

The dart page http://pub.dartlang.org/doc/#adding-a-dependency describes how you can have a dart file (parser_test.dart) import files from its own package using the 'import "package:..." style of import. It seems to imply this is a good thing - better than using relative paths. This example shown is for a file in test which appears to be special. But, then why does it not make sense for importing same package lib files from a lib in the package. Maybe it does make sense, but if so the pub update does not make it convenient.

foo/
   /lib/
        foo_lib_1.dart
        foo_lib_2.dart
        src/
           foo_lib_1/
                     foo_lib_1_impl.dart
           foo_lib_2/
                     foo_lib_2_impl.dart

Assume foo_lib_2 uses foo_lib_1. There are two options for foo_lib_2.dart:

My guess is the suggested approach is the first for any such import that resides under lib. The reason I think this is pub update seems to automagically provide a soft link in the packages folder of any of bin, test, or example to foo, like foo -> ../lib. Yet, it does not do the same for the packages folder in top level foo. This means to get the second type of import (i.e. the packages import) to work you need to add:

foo:
  path: lib

to the dependencies of foo in the pubspec.yaml. Is there any advantage or disadvantage for a library to use the package style import to import another library (not in test, bin, or example) from its own package? Is there a reason for the apparent inconsistency?


After accepting the answer below, I still am not seeing it. Here is what I'm seeing in a shell session and I would like to reconcile this behavior with the answer. Any explanations appreciated. I am using emacs instead of DartEditor, thus the old-school command line approach here.

### Show all files, one dart library file and one yaml, plus empty
### lib and test folders

user@user-thinkpad:/tmp/uml_codegen_sample$ ls -R
.:
lib  pubspec.yaml  test

./lib:
plusauri.dart

./test:

### Show contents of pubspec

user@user-thinkpad:/tmp/uml_codegen_sample$ cat pubspec.yaml 
name: domain_model
version: 0.0.1
description: >
  Auto-generated support from /home/user/plusauri/modeling/plusauri.xmi.json
dependencies:
  ebisu:
    path: /home/user/open_source/codegen/dart/ebisu

### Run pub install and show the changes. Note there is a soft
### link to packages from test, but not lib.

user@user-thinkpad:/tmp/uml_codegen_sample$ pub install
Resolving dependencies...
Dependencies installed!
Some packages that were installed are not compatible with your SDK version 0.4.7+5.r21658 and may not work:
- 'pathos' requires >=0.5.0+1

You may be able to resolve this by upgrading to the latest Dart SDK
or adding a version constraint to use an older version of a package.
user@user-thinkpad:/tmp/uml_codegen_sample$ ls -R
.:
lib  packages  pubspec.lock  pubspec.yaml  test

./lib:
plusauri.dart

./packages:
domain_model  ebisu  pathos

./test:
packages

### Note here the program does not work, and suspiciously pub
### install put no packages link under lib like it did test

user@user-thinkpad:/tmp/uml_codegen_sample$ dart lib/plusauri.dart 
Unable to open file: /tmp/uml_codegen_sample/lib/packages/ebisu/ebisu_utils.dart'file:///tmp/uml_codegen_sample/lib/plusauri.dart': Error: line 5 pos 1: library handler failed
import "package:ebisu/ebisu_utils.dart" as EBISU_UTILS;
^

### Copy the same dart file to test to show that it can run there
### just fine

user@user-thinkpad:/tmp/uml_codegen_sample$ cp lib/plusauri.dart test/
user@user-thinkpad:/tmp/uml_codegen_sample$ dart test/plusauri.dart 
Main for library plusauri
user@user-thinkpad:/tmp/uml_codegen_sample$ 

### Finally, manually create the soft link in lib, to show it will
### then run

user@user-thinkpad:/tmp/uml_codegen_sample$ ln -s ../packages lib/packages 
user@user-thinkpad:/tmp/uml_codegen_sample$ dart lib/plusauri.dart 
Main for library plusauri

Upvotes: 3

Views: 3497

Answers (1)

Juniper Belmont
Juniper Belmont

Reputation: 3564

Actually, you can definitely import using the package:foo/foo_lib_1.dart syntax without needing to change your pubspec.yaml or even creating a pubspec.yaml in the first place!

You can see that this is true from a language level, in this test: https://github.com/dart-lang/bleeding_edge/blob/master/dart/tests/standalone/package/packages/package1.dart

and an example of this in the wild is: https://github.com/kevmoo/hop.dart/blob/master/lib/hop_tasks.dart#L17


I do not think there is any benefit from writing one way or another except that writing relative paths is slightly shorter.

From a project structure point of view, I would use relative path imports when I am drilling into subdirectories that are not going to be exposed to the user. src is generally seen as implementation specific details that won't be visible to external users, so use relative paths to your heart's content.

However, if you're working within multiple directories, then you should use package: imports to reinforce the idea that the parts are stand-alone and interchangeable. Within the lib directory itself, you want to say that these two libraries, although they might rely on each other, can live separately and are not bound by their physical location.

I would recommend not ever using ../ in your imports, as that is fragile and may break in strange ways if/when you modify directory structure or deploy.

Upvotes: 3

Related Questions