Wednesday, October 31, 2012

Deprecated Dart Pub Application Layout

‹prev | My Chain | next›

Last night, I revisited Dart Pub after managing to get Hipster MVC added as an official pub package. All seems quite nice—managing package dependencies for client-side libraries is a huge step forward for web development.

There is one problem that I would like to explore tonight. When I installed hipster_mvc from Pub, I was told that my web application's public/scripts was in an improper format. Indeed, even today, we I try to update my dependencies, I am still told the same thing:
➜  scripts git:(M1) ~/local/dart/dart-sdk/bin/pub update                                       
Resolving dependencies...
Warning: Package "scripts" is using a deprecated layout.
See http://www.dartlang.org/docs/pub-package-manager/package-layout.html for details.
Dependencies updated!
This is not really a "script" package, that is just the name that I gave in my application's pubspec.yaml:
name: scripts
dependencies:
  hipster_mvc: any
I think that the deprecated layout message means that I do not have my Dart files in a lib sub-directory. Since this is my public/scripts directory on the web server, I have everything directly in here:
➜  scripts git:(M1) ✗ tree
.
├── Collections.Comics.dart
├── dart.js
├── main.dart
├── ModalDialog.dart
├── Models.ComicBook.dart
├── packages
│   └── hipster_mvc -> /home/chris/.pub-cache/hosted/pub.dartlang.org/hipster_mvc-0.1.0/lib
├── pubspec.lock
├── pubspec.yaml
├── Views.AddComic.dart
├── Views.AddComicForm.dart
└── Views.Comics.dart

2 directories, 10 files
The first thing that I try is to simply create a lib sub-directory. Perhaps the mere presence of that sub-directory will eliminate the warning. It does not:
➜  scripts git:(M1) ✗ mkdir lib
➜  scripts git:(M1) ✗ ~/local/dart/dart-sdk/bin/pub update
Resolving dependencies...
Warning: Package "scripts" is using a deprecated layout.
See http://www.dartlang.org/docs/pub-package-manager/package-layout.html for details.
Dependencies updated!
My next step is to see if my hypothesis is correct. I move all of the Dart files into the newly created lib sub-directory and try again:
➜  scripts git:(M1) ✗ mv *.dart lib
➜  scripts git:(M1) ✗ ~/local/dart/dart-sdk/bin/pub update
Resolving dependencies...
Dependencies updated!
Yup, that is definitely the cause of the deprecation warning. I can live with most of that code being inside the lib sub-directory. The Model, Collection, and View classes are all referenced from the main.dart entry point (or by each other). So the lib sub-directory might even be appropriate. But, I cannot abide having the main.dart entry point in lib. I refuse to start adding lib in the HTML that references the main.dart entry point:
<head>
  <!-- ... -->
  <script src="/scripts/main.dart" type="application/dart"></script>
</head>
It is not a library file—it is a main.dart entry point, dammit.

Perhaps Pub will let me get away with just the main.dart file being in the root public/scripts directory:
➜  scripts git:(M1) ✗ mv lib/main.dart .
➜  scripts git:(M1) ✗ ~/local/dart/dart-sdk/bin/pub update
Resolving dependencies...
Warning: Package "scripts" is using a deprecated layout.
See http://www.dartlang.org/docs/pub-package-manager/package-layout.html for details.
Dependencies updated!
Oh, darn.

I toy with the idea of moving all of the MVC code in my Dart Comics sample app into its own sub-directory—something like public/scripts/dart_comics. But that will not work.

I could add the additional dart_comics/lib/ path for each of the imports of my application's collections and views, but there is no way that I could then import the HipsterSync class that I use for syncing CRUD operations to localStorage instead of over a REST-like web service:
#import('Collections.Comics.dart', prefix: 'Collections');
#import('Views.Comics.dart', prefix: 'Views');
#import('Views.AddComic.dart', prefix: 'Views');

#import('dart:html');
#import('dart:json');

#import('package:hipster_mvc/hipster_sync.dart');

main() {
  HipsterSync.sync = localSync;
  // ...
}
The HipsterSync class is part of hipster_mvc, which would be a dependency of the fictional dart_comics library. As such, I would not have access to it from the main.dart entry point.


So, in the end, I plan to stick with the deprecation warnings. Hopefully those deprecation warnings will go away in the future—at least for applications.


Day #556

3 comments:

  1. Since your main.dart is a web entrypoint, the convention is that it should be under "web". We can and definitely should do some better error reporting here. In this case, the convention isn't an arbitrary one.

    In order for a "package:" style import to work, it needs to have a "packages" directory in the same directory as the entrypoint file (main.dart). Pub will create the directories for you, but it only does so in certain places. You will get them in "bin", "example", "test", and "web" (and in any subdirectories in those directories). You *won't* get one in "lib" because that would cause a symlink cycle which is one of the things the new package conventions were designed to eliminate.

    What this means is that any entrypoint files in your package need to be in a directory that pub knows to put "packages" directories in. This is definitely not obvious, though, and is something pub should do a better job of explaining.

    If you want, please don't hesitate to file a bug for us so we remember to improve the error message here.

    ReplyDelete
    Replies
    1. Ah, OK. I think I've got it now.

      In the application, I have to put everything into the `web` sub-directory, including the `main.dart` entry point and application-specific classes. After running `pub`, I have a directory structure like:

      ➜ scripts git:(M1) ✗ tree
      .
      ├── dart.js
      ├── packages
      │   ├── hipster_mvc -> /home/chris/.pub-cache/hosted/pub.dartlang.org/hipster_mvc-0.1.0/lib
      │   └── scripts -> /home/chris/repos/dart-comics/public/scripts/lib
      ├── pubspec.lock
      ├── pubspec.yaml
      └── web
      ├── Collections.Comics.dart
      ├── main.dart
      ├── ModalDialog.dart
      ├── Models.ComicBook.dart
      ├── packages -> /home/chris/repos/dart-comics/public/scripts/packages
      ├── Views.AddComic.dart
      ├── Views.AddComicForm.dart
      └── Views.Comics.dart

      My problem had been the supporting classes, which I had been placing in `lib` or in the root directory. Once I moved everything into `web`, it worked.

      I'm not sure better error reporting is necessary, but some mention of the `web` directory on http://pub.dartlang.org/doc/package-layout.html would help.

      FWIW I still prefer `/scripts/main.dart` as the entry point URL. I'd rather not expose the inner-workings of pub layout in my URLs.

      Delete
    2. The formatting above didn't really work. Everything after `web` should be indented to indicate that it is all in the `web` sub-directory.

      Delete