Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spec main hash extension mapping #7

Closed
wants to merge 3 commits into from
Closed

Spec main hash extension mapping #7

wants to merge 3 commits into from

Conversation

josh
Copy link
Contributor

@josh josh commented Nov 12, 2013

If the main array is to be deprecated #6, I need a replacement for it.

The confusion of the main array comes from the fact that you should only have one type per extension in the array. Making an explicit map of extension to filename reduces the possibility of invalid main definitions.

extensions not types

I think “extensions” make more sense over “types” (script, style, font). For one, we’d have to spec all the the types. Bower is about all assets, not about one specific type and the ones we can think of. Maybe you want to package to contain text or data files. We shouldn’t stop you because it doesn’t fit inside a predefined bucket.

main is just a path alias.

"name": "foo"
"main": {
  js: "scripts/bar.js"
  css: "styles/bar.css"
}

Means alias foo.js to foo/scripts/bar.js and foo.css to foo/scripts/bar.css.

Extensions express capabilities to build tools. Some tools can’t handle files that will processing. Require.js for an example will never know what to do with a .coffee file. It needs .js files. It makes sense for it to just use the file of package[‘main’][‘js’]. Other tools like Sprockets are aware of both .css, .scss, .less, etc and can choose the based on which preprocessor the user has available.

“main”: {
 coffee: “foo.coffee”,
 js: “foo.js”
}

Seems acceptable to me. Coffeescript aware tools can prefer building from source, while other tools may just pick the compiled version and be fine. This helps Sprocket’s automatic source map generation.

@benschwarz
Copy link
Member

I endorse this internet e-note

@benschwarz
Copy link
Member

This is one of the most thought out arguments we've had to date.

@josh josh mentioned this pull request Nov 12, 2013
@sindresorhus
Copy link
Contributor

main can be a path to a file in the package that serves as an alias of the package name.

👍 really just clarifying what it actually is.

main can be an Array of paths in the package. There must only be one path per file extension. This usage is considered deprecated. Build tools and package managers should still support the usage. Packages themselves should migrate to the 3 option as implementation roll out.

Nah, Bower can just pluck the first JS file.

main can be an Object with file extension keys mapping to a single path. This is preferred over the Array definition as it makes it clear only one file can exist per extension.

If we were to go for extension mapping, an array would be better. Making it verbose just to make it clear isn't worth it. Bower can easily pluck the extensions and categorize them. Bower can also prevent publishing with multiple of the same extension.

@josh josh mentioned this pull request Nov 12, 2013
@josh
Copy link
Contributor Author

josh commented Nov 12, 2013

Independent of this PR, #8 attempts to clarify the alias intent.

Nah, Bower can just pluck the first JS file.

Right, for "list". But that behavior doesn't seem ideal.

If we were to go for extension mapping, an array would be better.

Ha, well I'd rather not deprecate it then, #6.

Bower can easily pluck the extensions and categorize them.

The other thing thats strange about using an Array is order. main ought to have no preference of priority. .js is not more important than .css. Which is reveal by the strange behavior of list just picking the first filename.

@danielchatfield
Copy link

One feature of using an object rather than an array is that you could specify both the css source and the minified source.

"main": {
  "min.css": "styles.min.css",
  "css": "styles.css"
}

Not sure if this is useful as it could be argued that minification is the job of the build tool and it kind of fudges the definition of a file extension.

I'm +1 for the Object as I think it will make it more flexible for the future however I don't think the key should be strictly defined as the file extension as without this restriction it could be useful for extensions to do something like:

"main": {
  "some-extension-config": "config.json",
  "css": "styles.css"
}

@josh
Copy link
Contributor Author

josh commented Nov 12, 2013

I kinda like the min example. Neat idea.

I think so long as "{package}.{key}" maps to "{package}/{value}" it should be okay.

On Nov 12, 2013, at 6:18 PM, Daniel Chatfield notifications@github.com wrote:

One feature of using an object rather than an array is that you could specify both the css source and the minified source.

"main": {
"min.css": "styles.min.css",
"css": "styles.css"
}
Not sure if this is useful as it could be argued that minification is the job of the build tool and it kind of fudges the definition of a file extension.

I'm +1 for the Object as I think it will make it more flexible for the future however I don't think the key should be strictly defined as the file extension as without this restriction it could be useful for extensions to do something like:

"main": {
"some-extension-config": "config.json",
"css": "styles.css"
}

Reply to this email directly or view it on GitHub.

@josh
Copy link
Contributor Author

josh commented Nov 12, 2013

@danielchatfield updated with your suggestion. I'm having trouble with succinct wording for multiple file extensions. Let me know if you come up with anything clearer.

I'm considering using this for source maps in Sprockets. If a main provides js.map, use that as the initial source map input.

"main": {
  "js": "foo.js",
  "min.js": "foo.min.js",
  "coffee": "foo.coffee"
}

Here most build tools may just default to using "js". However, lets say Sprockets understanding coffee. It would prefer compiling the original coffee so it could generate a source mapping back to the most original file.

"main": {
  "js": "foo.js",
  "min.js": "foo.min.js",
  "dart": "foo.dart"
  "js.map": "foo.js.map"
}

Or here, the author used Dart and compiled to js. Sprockets doesn't understand dart, but it sees there a map already checked into source. Sprockets would then use the existing map and link it to the original dart source.

@danielchatfield
Copy link

Looks good 👍

@josh
Copy link
Contributor Author

josh commented Nov 12, 2013

Related, #9 paths aliases for non-main files.

@unscriptable
Copy link

I'm not sure if this the appropriate place to discuss this, but we also have different flavors of JavaScript: global scripts, AMD modules, CommonJS modules, and ES6 modules. At one point in a discussion thread (can't find it, atm :( ), there was a proposal for a type property in package.json. It would have values such as "harmony" (now "es6", of course) or "commonjs".

This information is important to loaders and build tools. Any idea how this would fit into this proposed strategy? The discussion about having different keys for minified css sounds similar to having multiple script/module formats.

@josh
Copy link
Contributor Author

josh commented Nov 12, 2013

@unscriptable definitely open a new issue on this repository. Lets discuss.

@robdodson robdodson mentioned this pull request Nov 12, 2013
@briandipalma
Copy link

@sindresorhus Verbosity should not be the main priority especially if IDEs/tools auto generate bower config files.
A higher priority should be clarity and explicitness. You could understand how the array would be parsed if you knew the spec but if you didn't you might be unclear when faced with multiple resources of the same extension, while an object makes it explict by preventing such cases.

This proposal along with the paths proposal #9 seem a good combination.

@sindresorhus
Copy link
Contributor

You could understand how the array would be parsed if you knew the spec but if you didn't you might be unclear when faced with multiple resources of the same extension

Neither name (only lowercase, max 50 chars, ...), version (semver), etc, is clear without reading the spec. We should base our decisions on people reading the docs, and rather prevent them making mistakes through tooling. Not by compromising.

@briandipalma
Copy link

I don't understand how an object is compromising and an array is not. Surely main can only be used to alias one resource not multiple, in that case why list multiple?

@josh
Copy link
Contributor Author

josh commented Nov 13, 2013

The array confused people now into thinking that its basically "files" and you can do stuff like:

"main": ["foo.js", "bar.js"]

Theres no way to represent that file list as

"main": {
  "js": "foo.js",
  "js": "bar.js"
}

@benschwarz
Copy link
Member

Theres no way to represent that file list as

"main": {
  "js": "foo.js",
  "js": "bar.js"
}

and theres no rationale to, either, right?

@josh
Copy link
Contributor Author

josh commented Nov 13, 2013

and theres no rationale to, either, right?

Nope.

@zzolo
Copy link

zzolo commented Nov 20, 2013

This may not be the best place for this comment and admittedly I have not been a part of this discussion or the development of Bower at all, but having used it for a while and really loving it, I do want to offer my opinion.

My main issue with Bower is there is no way to easily know what files I need to include to actually use the package as a dependency in my application. I currently manually maintain a component map that maps each component to a set of files needed to include the dependency.

The current description of main is "The primary acting files necessary to use your package". This essentially means the build files. But many packages have different types of builds and as Bower does not try to force any build tools or mechanism for including dependencies, I think its important to allow for different sets of builds.

Here is an example of what I propose.

// Most libs would look like this
builds: {
  default: {
    js: ['dist/foo.min.js']
  },
  src: {
    js: ['dist/foo.js']
  }
}

// A more complicated example
builds: {
  default: {
    js: ['dist/foo.min.js'],
    css: ['dist/foo.min.css']
  },
  coffee: {
    css: ['dist/foo.min.css'],
    coffee: ['dist/foo.coffee']
  },
  src: {
    js: ['src/foo.js'],
    css: ['src/foo.css'],
    mustache: ['src/bar-template.mustache']
  },
  legacy: {
    js: ['dist/foo.legacy.min.js', 'dist/foo.min.js'],
    css: ['dist/foo.min.css', 'dist/foo.min.ie.css']
  }
}

Firstly, rename main to builds. There can be many different build combinations (I can point you to some specific examples if you want). There should definitely be support for arrays of files (order does matter). And I think keyed by extension type makes the most sense.

As an everyday user of Bower, this would be lovely.

Either way, many thanks for all the amazing work on such a helpful tool.

@briandipalma
Copy link

@zzolo I may be misunderstanding main or your post but...

The current description of main is "The primary acting files necessary to use your package". This essentially means the build files.

I'm not sure that's what main is about. I thought it was more the root of your package's dependency tree.

For instance, if your package consists of JS code broken up into several files you would specify a JS file that inside it may have require("./package-util") or import {package-util} from "./package-util") depending of if you are using ES6 or not. It may have several import statements which pull in all the other JS files in the package or the first imported file will pull them in. The end result is though a tool could start parsing the main file and end up bundling your entire package and leave any non imported files as they are not being used by the package.

Does this make sense?

@zzolo
Copy link

zzolo commented Nov 20, 2013

@briandipalma That does make sense. But...

  1. There are many packages out there that don't use those conventions, and though I think they should, that's just not how the current front-end ecosystem is at the moment.
  2. There are still possibilities that you want to include JS files manually through some other process. I am thinking of legacy versions for old browser support (see Ractive).
  3. This doesn't apply to CSS or other non-JS files. Well, if using something like SASS, you could import, but again, this is not how most builds are created.

@briandipalma
Copy link

  1. Correct but those are legacy packages once ES6 is available in browsers and I think Bower is trying to take a forward looking approach.
  2. I'm not sure but maybe the paths Proposal #9 paths proposal might be helpful there?
  3. The main property can be any resource type I believe, including CSS. You can import in CSS.

@robdodson
Copy link

There are a few libraries out there that specify a directory in main. mout for instance. The issue has come up a few times on the bower-requirejs project of whether or not we should support this (yeoman/bower-requirejs#47, yeoman/bower-requirejs#52) It seems like in this proposed system that would no longer be possible? I'm ok with that, just double checking.

@wibblymat is a directory in your main array currently considered OK? I would love to close these issues because I think what they're both really asking for is CommonJS packages, which would be better solved by the moduleType proposal

@cvrebert
Copy link
Contributor

@robdodson I've just asked for clarification on that: #19
[Edit: Answer: No, main cannot be a directory.]

@donaldpipowitch
Copy link

main is just a path alias.

"name": "foo"
"main": {
js: "scripts/bar.js"
css: "styles/bar.css"
}
Means alias foo.js to foo/scripts/bar.js and foo.css to foo/scripts/bar.css.

That sounds a great. But I would like to throw in some more exotic examples, because most debate is about JavaScript/CoffeeScript and CSS/Less/Sass, but I would to use Bower for all my front-end resources. So lets say I want modularize my HTML templates to reuse them across multiple projects.

This is okay for a single HTML template:

"name": "button"
"main": {
  "html": "dist/template.html",
  "css": "dist/style.css"
}

That is nice. I can now import my button.css and button.html which will now be resolved to button/dist/style.css and button/dist/template.html by my build tools. But I rarely have just one template for one component/package/module.
Let's use this example again. My button package would look more like this:

"name": "button"
"main": {
  "html": "dist/button-default.html",
  "-big.html": "dist/button-big.html",
  "/button-icon.html": "dist/button-icon.html",
  "css": "dist/style.css"
}

And now I can use button.html, button-big.html and button/button-icon.html in combination with my single button.css. (I just throw in - and /to prefix them as an idea... I don't know which one I would use at end or if I would use both.)

Another very use case - which I really don't know if it extremely exotic_ or maybe not so uncommon as I think: multiple sources as used in <video>, <audio> or for responsive images.

"name": "company"
"main": {
  "intro": [ "compressed/intro.webm", "compressed/intro.mp4" ],
  "team": [ "compressed/team.webm", "compressed/team.mp4" ]
}

It could be used like this:

<video>
  <!-- bowersrc -->
  <source src="company.intro"></source>
  <!-- endbowersrc -->
</video>

(Note. The wiredep'esk annotations to get Bower dependencies...)

And my build tool could resolve this to:

<video>
  <source src="company/compressed/intro.webm"></source>
  <source src="company/compressed/intro.mp4"></source>
</video>

Maybe this solution is not the most beautiful. I just want to push the discussion more to HTML and other assets.

@josh
Copy link
Contributor Author

josh commented May 16, 2014

@donaldpipowitch see #9.

@josh josh closed this Oct 1, 2014
@josh josh deleted the main-hash branch October 1, 2014 22:23
@donaldpipowitch
Copy link

Is "paths" official now?

@cvrebert
Copy link
Contributor

cvrebert commented Oct 2, 2014

@donaldpipowitch Nope, the Bower spec just continues to languish; see #6 (comment)

@donaldpipowitch
Copy link

Oh :( This is quite sad.

@briandipalma
Copy link

@donaldpipowitch Take a look at http://jspm.io/

@donaldpipowitch
Copy link

JSPM is for JavaScript resources only, right? I always looked at Bower as a package manager for all frontend resources - even fonts and images.

@briandipalma
Copy link

@donaldpipowitch It's a package manager, there are plugins for SystemJS (ES6/CJS/AMD/global module loader it uses) for CSS, text, images etc.

What's in the package doesn't matter to either npm, bower or jspm.

@donaldpipowitch
Copy link

Thanks. I'll look into it again. But it isn't really widely adopted or has this changed?

@briandipalma
Copy link

It's quite small at the moment but I think bower is moribund and frankly I don't think jspm constrains you too much. Your code will still be ES6 modules or CJS and installable by any other package manager.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants