bower/spec

moduleType proposal

robdodson opened this issue · 20 comments

@unscriptable just mentioned this (#7 (comment))

Related to this I believe bower/bower#934

moduleType would allow the developer to specify if their package is AMD, global, CJS, etc.

This seems like a sensible proposal, the only issue I can see is if people mix diferent types in different files but they'd be in the wrong then.

josh commented

Should we have a recommended set of values even though it may not be strictly enforced?

@wycats first raised this proposal AFAIK

+@paul_irish

Should we have a recommended set of values even though it may not be strictly enforced?

Yes, people will usually follow the guidelines, it's good to encourage consistency.

Yes, we agreed that moduleType would be added at a recent meeting. The original proposal is in this document by @wycats.

I have some proposed wording in #13. It could be expanded to take in all of the details of the original if necessary.

I'm a little worried whether bower.json is the right place for this... Here's some thoughts:

  1. Up to now bower has been mostly playing the role of a (dumb, content-agnostic) transport layer. It doesn't care whether it's transporting JavaScript, CSS, images, templates, etc. The moduleType option is JavaScript-specific. Are we OK with that? What about CSS, for instance?
  2. If bower is a transport tool, then it would be orthogonal to any build tool running on top. It seems that the moduleType declaration (and main as well perhaps) would then conceptually belong in the build tool. I know we don't have a great build tool that we all agree on, but I'm working hard to change this with broccoli. So perhaps moduleType would belong in Broccolifile.js, not bower.json?
  3. From my perspective as a build tool author, understanding the module type is only really useful once you also understand how module names are constructed. For instance, Node puts each package in a separate namespace, so you have require('package-name/path/to/module') (great for single-module packages, not so great for multiple-module packages because you get paths like package-name/lib/foo) whereas Ruby adds the package's require_path directory to its search path, so you have require 'path/to/module' without any intermediate namespace. Ruby's approach yields directory structures like this. Right now, I believe we don't have these semantics defined, so there's no "correct" way for packages to import their dependencies.

Sorry, I realize this all sounds really negative -- I'm totally on board with solving the underlying pain, and having the moduleType declaration in some place, and perhaps bower.json will turn out to be the right place.

I'm available to chat on Skype too if anybody wants to sync up.

Cc @rpflorence

Yes bower.json is the right place for this.

  1. If your package contains no JS then don't specify a moduleType.
  2. moduleType should belong with the package, it's an intrinsic feature of the package.
    The explicit declaration of package attributes will make it much easier for tools/IDEs to consume packages.
  3. I don't see how that should be a reason for a package not to explicitly declare its attributes.

Bower needs to be more then an empty sack, it needs some sort of convention/structure that IDEs/tools can rely on for it to be used as a base of a tool chain.

Up to now bower has been mostly playing the role of a (dumb, content-agnostic) transport layer. It doesn't care whether it's transporting JavaScript, CSS, images, templates, etc. The moduleType option is JavaScript-specific. Are we OK with that? What about CSS, for instance?

I think you could say the same thing about the main attribute. I believe moduleType would be optional and just included to help build tool authors.

As a build tool author, it seems like the best way to differentiate a CommonJS module, AMD module, ES6 module, and browser global is to build an AST and poke around till you arrive at a best guess. I would much rather have the component author just tell me what I'm working with and how they want it built. As @briandipalma points out, this seems like it's intrinsic to the package and would make my life (as a build tool maintainer) and the author's life easier.

Bower needs to be more then an empty sack

For the record, I agree we need more than an empty sack for it to be useful -- I'm just not sure if the additional functionality belongs in bower proper, or if we should have bower combined with some other tool.

It's not really additional functionality, it is purely about allowing a bower package to declare features intrinsic to the package. This is the bower.json spec repo after all, we are not dealing with code. Bower shouldn't couple itself to any specific tool, it should encourage package creators to provide all the package meta-data that any tool/IDE/live development bundler requires to achieve its aims.

Since this has already been implemented in a release version of Bower itself (bower/bower#934), could at least the as-implemented functionality get promptly added to the spec?

We are going to need the ability to specify the "main" script (if bower can decide what that means) for each module type. While we can do UMD to support lots of types, you can't support native modules and legacy modules in the same file. For more info, see instructure/ic-ajax#13

josh commented

@rpflorence to an extent I think you're right. But I'm also worried about too much build tool fragmentation.

Maybe we need more than a moduleType directive.

{ "name": "jquery",
  "main": "jquery.js",
  "amd": {
    "main": "jquery-amd.js"
  },
  "es6-module": {
    "main": "jquery-es6.js",
    "dependencies": { "es6-module-transpiler": "*" }
  }
}

Each custom subsection could provide overrides for any existing properties. Maybe "dependencies" is a bad idea, I dunno. But I can see other properties besides "main" being added in the future.

I feel like I got this idea from anther package manager or format.

I am +1 on recursive package.json formats where child nodes override parent nodes, then tools can do what they need to do and authors can package how they need to package.

josh commented

Wrote up the alternative idea for discussion in #23

I think there are two issues at play here

  1. A developer would like to inform the consumer what "type" their bower item is
  2. A consumer wants to get a specific version of a package if it's available

The post by @josh in this thread and #23 touches on both of these concepts by overlaying overrides for different types, much like the Packages/1.1 overlay. However, I feel we are limiting ourselves to an enum of known systems. Instead, we may just want to leave this flexible and have the developer describe n different variants of their bower package for consumption.

{
  "name": "foo",
  "main": "dist/foo.js",
  "variants": {
    "default": "source",
    "source": "/",
    "es6": "dist/es6/foo.js",
    "arbitrary": {
      "main": "applied/via/overlay.js",
      "files": "dist/variantname"
    }
  }
}

Variants describe alternate consumable versions of the package. The sensible defaults would be default: "source", source: "/". This way, packages without variants would function as they do today. Requesting a variant would be done with the : operator in the dependencies key.

Ping! :)

The bower init CLI asks for it, but it's not in the bower.json spec. What's the latest thinking about this, folks?

I'm rather new to Bower, so having bower init ask me something that looks to be undocumented was confusing. Can some documentation be added, ala http://stackoverflow.com/questions/22674018/bower-init-difference-between-amd-es6-globals-and-node?

@desandro Could you please close this in light of #13 (comment) ?