Monday, May 28, 2012

Dart Pub for Local Development

‹prev | My Chain | next›

I got a nice taste of the pub packager for Dart (it's so new, it has a commit, not a landing page). Like just about everything else in Dart, pub is starting small, with just enough to get an idea how it might work, but not so much that it is at all encumbered by previous implementation.

Tonight, I'd like to see how far I can push the current implementation. Specifically, I would like to see if I can make it manually emulate npm's very excellent npm link. The "link" in that command instructs npm to link a local copy of a package instead of installing it from the npm registry. It is more than installing it from a local copy—it creates a symbolic link to the local package instead of installing it. The invaluable benefit of this approach is that any changes made to the linked package can be immediately committed without the intermediate step of copying them into a separate repository.

I do this constantly as I am developing Hipster MVC. Try something new in Dart Comics / tweak the code in Hipster MVC. Struggle with an implementation aspect in Dart Comics / update the documentation in Hipster MVC.

But until now, this has been a pain. I either need to update the code on GitHub to see the change locally:
...
#import('https://raw.github.com/eee-c/hipster-mvc/master/HipsterSync.dart');
...
Or I have to manually sym-link the Hipster MVC libraries for local development only to remove them (and the updated #import() statements) before I commit to the Dart Comics repository.

So I get started by replacing the remaining references to GitHub-hosted code in Dart Comics with the pub package equivalent:
...
#import('package:hipster-mvc/HipsterSync.dart');
...
Next, in the scripts directory of Dart Comics, I replace the pub installed Hipster MVC with a symbolic link to my local copy of the repository:
➜  scripts git:(pub-packages) cd packages
➜  packages git:(pub-packages) mv hipster-mvc hipster-mvc.orig
➜  packages git:(pub-packages) ln -s ../../../../hipster-mvc
➜  packages git:(pub-packages) ls -l
total 4
lrwxrwxrwx 1 chris chris   23 May 28 22:02 hipster-mvc -> ../../../../hipster-mvc
drwxr-xr-x 3 chris chris 4096 May 27 23:06 hipster-mvc.orig
And, indeed, it all still works. I can view, delete, and add comic books to my collection just as before:


Best of all, if I make a change to my local copy of Hipster MVC, such as breaking forEach():
class HipsterCollection implements Collection {
  // ...
  void forEach(fn) {
    //models.forEach(fn);
  }
  // ...
}
Then the change is immediately visible in my Dart Comics application:


And if I fix the change in the local Hipster MVC repository:
class HipsterCollection implements Collection {
  // ...
  void forEach(fn) {
    models.forEach(fn);
  }
  // ...
}
Then Dart Comics is fixed:


That is pretty freaking amazing. If there is anything even close in client-side Javascript land, I am unaware. But even is a pre-release / proof-of-concept, the pub packager already makes life oh-so-sweet for the Dart developer.

Am I overstating? This seems huge.


Day #400

5 comments:

  1. Thanks for trying out pub and writing down your thoughts. This feedback is immeasurably helpful.

    "The invaluable benefit of this approach is that any changes made to the linked package can be immediately committed without the intermediate step of copying them into a separate repository."

    This is actually a use case we intend to support directly in pub. What you're doing here (manually adding a symlink in your packages dir) is also valid, but is a pain to do manually.

    Instead, what we plan to support is file path sources. So in your pubspec, you could have something like:

    dependencies:
      foo:
        path: ~/path/to/foo

    With this, when you do a pub install, it will just create a symlink from ~/path/to/foo to foo in your packages directory. In other words, it will do exactly what you're doing manually here.

    ReplyDelete
    Replies
    1. Nice! Built-in support for sym-link development is gonna be big. Really exciting.

      I slightly prefer the npm-link approach. Both are two step processes — npm link once in the repo + once in the target project, while pub would be edit pubspec + pub install / update. The main benefit of the former is that it leaves no residual to be cleaned up before committing changes to SCM. Also, both operations are shell instead of one file edit + one shell.

      Delete
    2. My expectation is that you'd .gitignore (or the equivalent) your "packages" directory so you don't have to worry about cleaning it up before checking it in. Would that address your worry?

      Delete
    3. My concern is only the pubspec file. I agree that it's a minor thing, but I worry that I'll end up checking in a pubspec file modified for local development. I can see something like a pubspec change getting lost in the wash of a large commit.

      Delete
  2. There's a page now: http://www.dartlang.org/docs/pub-package-manager/

    ReplyDelete