Semi-related packages question

6 views
Skip to first unread message

Kevin Smith

unread,
Jun 17, 2010, 1:33:06 PM6/17/10
to comm...@googlegroups.com
I'm a bit of an outsider with respect to the packages proposal, but concerning how modules within the package are exposed via require(*), it seems that there is general agreement that require("foo/bar") should load the bar module in the foo package, wherever that may be located.  

Question:  is it really ever necessary to load a particular module within a package?  In my limited experience with browser-based module stuff, it makes more sense to me to think of the modules within my project as "private" and to have a single module (I've called mine public.js) which exposes the entire public API of the project.

So in my case, exposing all modules via require would be undesirable.  I want to be free to change private implementation code (aka modules) and know that it's not going to break any potential user's code.

Or has this concern been addressed elsewhere?

Thanks!

Kris Kowal

unread,
Jun 17, 2010, 1:47:38 PM6/17/10
to comm...@googlegroups.com

You do make an excellent case for only exposing the "main"
module, and I think it's been brought up on the packages
thread recently too. The counter-example would be packages
that provide frameworks or toolkits, where each module
provides a particular feature, or where a package has a
reusable component. The "narwhal-lib" package is a great
example. "jack" is a decent example, although its "main"
module does expose the content of a lot of the common
modules. I recently had a case where one package needed
some parsers internally, but those parsers turned out to be
useful in another package. Grabbing the single module was
useful in the short term, although someday there might be a
full enough set of parsers and parser modules to warrant a
separate parsing framework package.

Kris Kowal

Wes Garland

unread,
Jun 17, 2010, 2:41:08 PM6/17/10
to comm...@googlegroups.com
FWIW;

require("narwhal-lib").subpackage

is approximately equivalent to

require("narwhal-lib/subpackage")

except that it does not require package-system-knowledge, and does not expose inner packages from narwhal-lib unless the narwhal-lib developer explicitly exposes them.  It also makes it easier for the package developer to provide backward-compatible interfaces, or do other creative things.

/** @file narwhal-lib.js */
exports.subpackage = releaseBuild ? require("./obsolete") : new Error("Sorry, subpackage is deprecated, please use otherSubPackage instead");

Wes

--
Wesley W. Garland
Director, Product Development
PageMail, Inc.
+1 613 542 2787 x 102

Kris Kowal

unread,
Jun 17, 2010, 2:52:28 PM6/17/10
to comm...@googlegroups.com
On Thu, Jun 17, 2010 at 11:41 AM, Wes Garland <w...@page.ca> wrote:
> FWIW;
>
> require("narwhal-lib").subpackage

> is approximately equivalent to
would be, isn't

> require("narwhal-lib/subpackage")

The trouble with this approach is that every "main" module
effectively becomes a manifest, and all modules of the
subpackage must not only be fetched, but loaded, and
executed, in the order specified by the main module.

Kris Kowal

Christoph Dorn

unread,
Jun 17, 2010, 3:06:00 PM6/17/10
to comm...@googlegroups.com

I think both approaches have merit.

One could add a module handler property to the package spec to restrict
access to arbitrary modules. The handler is bypassed for relative
requires within the package and only used when requiring modules from
outside of the package.

package.json ~ {
"modules": {
"<match>": "<handler>",
"*": "main"
}
}

lib/main.js ~ {
exports.publicapi = require("./subpackage");
}

require("narwhal-lib/publicapi");

By default however I think every module in the package should be
addressable.

Christoph

Kris Kowal

unread,
Jun 17, 2010, 3:17:08 PM6/17/10
to comm...@googlegroups.com
On Thu, Jun 17, 2010 at 12:06 PM, Christoph Dorn
<christ...@christophdorn.com> wrote:
> One could add a module handler property to the package spec to restrict
> access to arbitrary modules. The handler is bypassed for relative requires
> within the package and only used when requiring modules from outside of the
> package.
>
> By default however I think every module in the package should be
> addressable.

We do not need this feature for a workable, common package
specification. I would encourage everyone to think minimal,
simple, and as close to featureless as possible. I think we
agree that it needs to be possible in some cases, albeit not
all, to address modules inside mapped packages. Let's leave
it at that and let implementors explore API enforcement.

Kris Kowal

Wes Garland

unread,
Jun 17, 2010, 3:23:24 PM6/17/10
to comm...@googlegroups.com
>  I would encourage everyone to think minimal, simple, and as close to featureless as possible.

for(;;)
  krisKowal++;

Mikeal Rogers

unread,
Jun 17, 2010, 3:45:46 PM6/17/10
to comm...@googlegroups.com
I think the require('narwhal').subpackage style is simpler and nearly
featureless. It also, in my opinion, brings the style and feel of
Packages in line with Modules which requires explicit definition of
public functions and attributes.

However, I wouldn't want the spec to contain language that *forbids* a
package manager or platform from allowing
require('narwhal/subpackage').

-Mikeal

> --
> You received this message because you are subscribed to the Google Groups "CommonJS" group.
> To post to this group, send email to comm...@googlegroups.com.
> To unsubscribe from this group, send email to commonjs+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/commonjs?hl=en.
>
>

Kevin Smith

unread,
Jun 17, 2010, 4:50:00 PM6/17/10
to comm...@googlegroups.com
Here's what it looks like in practice (in my BastardJS style):

exports =
{

replaceTextarea: replaceTextarea,
isSupported: isSupported,
Actions: require("./actions"),
Highlighter: require("./highlighter"),
History: require("./history"),
Rectangle: require("./rectangle"),
Selection: require("./selection"),
TextFont: require("./text-font"),
TextPanel: TextPanel,
TextPlane: require("./text-plane"),
TextRange: require("./text-range")
};

For a larger project, that list might get quite big.  Or not?  I suppose there are ways to make it a little  less repetitive.

I think restrictive by default would be better - I mean if I'm trying to do semver and someone is hacking with my private stuff (because my private stuff is the shiz, of course), we have a problem.

If I'm loading in components of some huge framework, this seems fine to me:

require("narwhal").gimme("subpackage");
~~~
exports.gimme = function(sub)
{
    switch (sub)
    {
        case "submodule": return require("./subpackage");
        etc...
    }
}

Or this:

require("narwhal").subpackage();
~~~
exports.submodule = function() { require("./subpackage"); };


In any case, it lets the package author decide what to expose.  And it's easy to remember.  Property getters would work too, if those are available.

Kevin Smith

unread,
Jun 17, 2010, 4:51:24 PM6/17/10
to comm...@googlegroups.com
Err - I mixed "submodule" and "subpackage" in the last post, but it's all supposed to be the same.

Kris Kowal

unread,
Jun 17, 2010, 5:11:44 PM6/17/10
to comm...@googlegroups.com
On Thu, Jun 17, 2010 at 12:45 PM, Mikeal Rogers <mikeal...@gmail.com> wrote:
> I think the require('narwhal').subpackage style is simpler and nearly
> featureless. It also, in my opinion, brings the style and feel of
> Packages in line with Modules which requires explicit definition of
> public functions and attributes.
>
> However, I wouldn't want the spec to contain language that *forbids* a
> package manager or platform from allowing
> require('narwhal/subpackage').

Without full access to the modules of a package, many of my
packages will not be useful to other systems, and I'm not
willing to maintain a main.js that manifests all of the
module's packages. I'm sure that there are other package
maintainers who will neglect to write a main.js. It is
marginally simpler to not include this feature, but it's a
critical feature.

Since this is a value judgement and the arguments have been
made, it would probably be sufficent to put it to a show of
hands now.

Kris Kowal

Dean Landolt

unread,
Jun 17, 2010, 5:18:07 PM6/17/10
to comm...@googlegroups.com
+1 for being able to require a module

I love the idea of utility packages that aggregate or otherwise make available large subsets of functionality.The idea that we'd have to import the entirety of a package to use any subset of it is a little scary and I believe it will put an end to any robust utility libs (like narwhal-lib) before they've even had a chance to gain traction.

Kevin Smith

unread,
Jun 17, 2010, 6:41:58 PM6/17/10
to comm...@googlegroups.com
I think I've sufficiently demonstrated how subpackages can be loaded by the main module at runtime using a few different approaches.

What's the alternative mechanism for protecting access to private modules?  I may have missed it.


--

Isaac Schlueter

unread,
Jun 17, 2010, 10:25:39 PM6/17/10
to comm...@googlegroups.com
Wait, preventing bad practices? That's like, going against the grain
of this whole language! ;)

With npm, I'm *really* considering not defaulting the directories.lib
setting to "lib", and instead only linking the folder if it's
explicitly set in the package.json. In that case, you'd still be able
to get at it if you did
require(".npm/foo/1.2.3/package/path/to/module") but at least that way
it's tucked out of the way.

--i

Reply all
Reply to author
Forward
0 new messages