Module naming and declarations

Brian Di Palma offler at gmail.com
Tue Apr 30 14:17:01 PDT 2013


I'm probably going to display my ignorance of the modules proposal here...

Good suggestions, thank you, they seem to have highlighted some
features in the module system that were new to me.
It does look like the wiki is out of date or not showing the full
range of functionality provided by modules.

For example the first suggestion you make seems to suggest module
imports are relative to the module you're currently executing in.
I had presumed all imports where from a "root" location.

In other words I thought any import using a specific identifier (
"./jquery" ) would always return the same value regardless of where
the import statement is located.
My reading of your first suggestion leads me to believe I was wrong.

If you have

module "com/megabank/metals" {
    import $ from "./jquery";
}

The import of "./jquery" is actually relative to "com/megabank/metals" ?
It's in fact importing "com/megabank/metals/jquery" ?

Therefore if I had a large concatenated JS bundle with

module "com/megabank/metals/jquery" {
    //code...
    export $;
}

in it then the "./jquery" import in "com/megabank/metals" would pull
the module above.

If there was no such module a request would be fired off by the
browser to the "%%PAGE_ROOT%%/com/megabank/metals/jquery.js" URL ?

Funnily enough I think I prefer the second suggestion.
The reason being that I think I'd rather not have location embedded in
my module identifier.
That might be fine for websites but for large code bases I feel it
would make moving resources around more painful/brittle.

The second version would allow you to have a cleaner, logical
identifier that is the same in all classes that use jquery.
So imagine I have a few classes that use jquery in my metals components set.

module "com/megabank/metals/orderticket" {
    import $ from "jquery";

    export class OrderTicketPresentationModel {
        //code in here uses jquery.
    }
}

module "com/megabank/metals/orderticket/settlement" {
    import $ from "jquery";

    export class SettlementPresentationNode {
        //code in here uses jquery.
    }
}

module "com/megabank/metals/spotticket" {
    import $ from "jquery";

    export class SpotTicketPresentationModel {
        //code in here uses jquery.
    }
}

Each of these classes would be in their own files and concatenated by
a bundler when loading up the application.
Could you imagine packing all those classes with relative import
statements to jquery?
Moving modules around becomes a total pain, surely I have this very wrong?
Is the expect future code base really meant to be litered with
"../../jquery" and "../jquery" references everywhere?

I've not given a very good overview of our code structure or
development environment but I think that's probably necessary to
understand where I'm coming from.
We sell a framework that allows banks to build their own trading applications.
As we are targeting a large number of different banks with different
needs our framework has to be very modular and easy to use as the
banks themselves do a lot of their own development.
To achive this we built a server side framework that uses conventions
to provide quick and easy development.
This short video shows how we configure a trade ticket (
http://vimeo.com/49064357 ) but it also gives a glimpse of our
conventions.

Actually the video shows how you shouldn't develop as he's working in
a full application and we recommend working in what we call a
workbench ( isolated from the app with fake services ).
Each component can have a "src", "resources" and "themes" directories
and inside the "resources" you can have "xml", "html" and "i18n".

We bundle all required resources on the fly when developing, we have a
single URL request for each resource.
One "bundle.js" request basically bundles all the JS you are using -
and only the JS you are using, no more.
We do that by reading some seed files and the files they pull in as
our JS is all namespaced according to the folder/filename like Java.
The code "new novox.package.MyClass();" would make us bundle and
analyze that code to pull its depedencies.
You add a new class creation to your code, save, press F5 and voila
you have the code you referenced when before you didn't.

It's surprisingly quick to do even for large code bases and for
production we create actual bundle files that are the same as the ones
in development.
The difference between dev and prod is quite minor.

Anyway we develop like you would in Java, with lots of small classes
and then the server side pulls them all together for us when we need
the code in the browser.

What I'd like to know is, are modules open?

Can I have package like declarations in all my files exporting the one
class in the file and when I concatanate the code together will it
work?
>From what I can tell I can't do that.
I will instead have to have a module per class I suppose?

In my GridView.js file I can't do.

module "novox/grid" {
    export class GridView {
    }
}

and in the same directory in my GridDecorator.js file I can't then do.

module "novox/grid" {
    export class GridDecorator {
    }
}

That will throw an error won't it? I've declared the same module
identifier twice and that will trigger an error.

I'd be forced to write

module "novox/grid/GridDecorator" {
    export class GridDecorator {
    }
}

So my module identifier are namespaced by including the leaf node (
the class I'm exporting ).

import { GridView } from "novox/grid/GridView";

Pity to have that redundancy but it seems we have no choice.

Also must I have the module declaration in each class/file. I think
not, correct?

module "novox/grid/GridDecorator" { //I think this line is not required?
    export class GridDecorator {
    }
}

When I concatanate I will need to insert that line though?

Yes, I wasn't planning to paste any jQuery code into any file I was
thinking more about how our bundler would output the code.

I know that multiple versions of libraries is an awful requirement but
that's what some of the tier 1 banks have been asking for.
They have large, seperate teams and they don't coordinate in any way...

"
Also, if jquery imports something, and the name happens to collide
with something you've declared in Metals, wouldn't jquery break?
"

OK so what I think you mean is if one of our classes imports something
and the names collide...
That's not an issue for us, we enforce namespacing of our resources
and so you can't have two resources with the same identifier.
i.e. we blow up if you have two components with the same src directory
structure or IDs in the XML/HTML resources.

Or do you mean what happens if we use a 3rd-party library and they
import something like

import {MyClass} from "novox/grid/GridView";

Highly unlikely as we stick to the reverse domain, Java-like namespace approach.
So novox would be either our company name or one of our clients.

Not many OSS libraries would call their packages after banks I'd say.

Not sure you could fix that beyond changing the actual source code of
the library I'd guess?

B.

On Tue, Apr 30, 2013 at 6:11 PM, Jason Orendorff
<jason.orendorff at gmail.com> wrote:
> On Mon, Apr 29, 2013 at 4:50 PM, Brian Di Palma <offler at gmail.com> wrote:
>> I was wondering how versioning was expected to work in this module system.
>> [...]
>> Now in each teams code base JQuery is imported like so:
>>
>> import $ from "jquery";
>>
>> That's great as long as they are developing separately from each other.
>> What I'm wondering is how their components are meant to be integrated
>> into a single app.
>
> The simplest thing would be to make a jquery module in your component:
>
>     module "megabank/metals/jquery" {
>         import $ from "jquery-1.9";
>         export $;
>     }
>
>     // other modules under megabank/metals/ would write:
>     import $ from "./jquery";
>
> That's the way that's built in the system, and that's what I would probably do.
>
> Loaders are customizable, so one alternative is to add versioning to
> the system loader: https://gist.github.com/jorendorff/5489886
>
>> With nested modules maybe you could bundle them like so
>>
>> module Metals {
>>     module jquery {
>>       //jquery 1.9.
>>     }
>> }
>
> Do you imagine the whole Metals module being in a single file,
> including jquery? Or would lexical modules be "open", like C++
> namespaces and Ruby classes? Or would they be put together some other
> way?
>
> Having to paste jquery code into your project seems unfortunate. You'd
> rather use the files unchanged, right? Also, if jquery imports
> something, and the name happens to collide with something you've
> declared in Metals, wouldn't jquery break?  (Well, OK, the real jQuery
> doesn't import anything and is extremely careful about which global
> names it uses. But one goal of a module system is not to have to be
> quite so paranoid.)
>
> Closing thought: All use cases are welcome! That said, using multiple
> versions of a library in a project is icky enough that an occasional
> project-wide search-and-replace at the margin isn't much worse.
>
> -j


More information about the es-discuss mailing list