componentjs / spec

Component specs
34 stars 4 forks source link

Custom Alias Definitions #41

Closed dominicbarnes closed 10 years ago

dominicbarnes commented 10 years ago

I saw something browserify did while working on some components this weekend that I thought would be helpful to those of us developing dual-purpose browser/server components. (it happens)

Since npm only has a single namespace, many cases a component is required to have different names for the package.json and component.json. As a result, wanting to use the component server-side requires something like this:

var emitter;
try {
  emitter = require("emitter");
} catch (e) {
  emitter = require("emitter-component");
}

Ugly, right? I was thinking we could leverage the existing alias implementation and allow us to use the same name in both contexts:

{
  "alias": {
    "emitter-component": "emitter"
  }
}

This will require the npm module name to be used client-side, which probably isn't "ideal", but this would only be necessary where someone wants a component to work in both contexts. The end result would be this: (and it would work in both cases)

var emitter = require("emitter-component");

I haven't tried using raw require.alias myself yet to accomplish the same thing, so I'll report back once I have something workable.

Swatinem commented 10 years ago

While this sure is annoying, the core of the problem is npms single namespace, so that’s where the fix should be.

Having to install component/emitter with its name emitter and use emitter-component creates more confusion than using the try/catch workaround.

dominicbarnes commented 10 years ago

I was thinking that may be the case, but if you look at a component.json the alias definition will be clear. And if you come at it from an npm module perspective, it remains clear as well.

While I understand this is an npm issue, it's not a problem, merely a design decision, and one they are not going to change for our sakes.

dominicbarnes commented 10 years ago

fwiw, I don't think the try..catch is clear on it's own. (of course you could just use comments to spell that out)

jonathanong commented 10 years ago

this would probably be better as a builder plugin or something.

dominicbarnes commented 10 years ago

That's true, I'll create one and experiment with it for a while.

jonathanong commented 10 years ago

yeah i have never ran into this problem myself. if i'm writing for node, i'd rather use node's emitter anyways.

Swatinem commented 10 years ago

I recently saw a {"alias": "user/repo"} style dependency in a package.json, can’t remember where though.

But then I was thinking about maybe a component-install --link-npm style command that would just create symlinks in node_modules.

If you have component deps like this:

Swatinem/t
-> component/t

It would create a hierarchy like this:

node_modules/t -> ../components/Swatinem-t
node_modules/t/node_modules/t -> ../components/component-t

But In its core, the problem comes down to having modules support different systems, then you end up with mostly redundant {bower,component.package}.json files, which can get quite annoying. Since AMD has died in favor of commonjs, at least we don’t have to worry about multiple module systems anymore, haha.

dominicbarnes commented 10 years ago

@jonathanong Yeah, when writing for node I'll definitely use their built-in stuff first.

However, I'm working on a client library for an internal API and I'm hoping to make it usable both in node and in the browser. (could use browserify, but I really like component so much better)

jonathanong commented 10 years ago

there's this: https://github.com/npmcomponent

haha so you can do require('component-emitter') and not worry about anything! i wonder if it's reliable enough to actually depend on it.

Swatinem commented 10 years ago

FYI: I just created https://github.com/Swatinem/component-linknpm implementing the symlink idea from my previous comment. Still very rough and incomplete so far. Ideas very welcome how to solve this properly.

jonathanong commented 10 years ago

The solution is to publish modules to npm with your username prepended. component-emitter

dominicbarnes commented 10 years ago

True, but I seldom have control over the modules I want to include :)

jonathanong commented 10 years ago

Yeah we should start publishing this way.

Swatinem commented 10 years ago

The inconvenience is not in the publish, but in the require() call. I don’t want to always repeat myself there.

jonathanong commented 10 years ago

Oh this shortens node require calls. Nice!

Swatinem commented 10 years ago

Ye, it does something like this:

  Linking : node_modules/inputarea -> components/component-inputarea
  Linking : node_modules/inputarea/node_modules/emitter -> components/component-emitter
  Linking : node_modules/inputarea/node_modules/events -> components/component-events
  Linking : node_modules/inputarea/node_modules/events/node_modules/event -> components/component-event
  Linking : node_modules/inputarea/node_modules/events/node_modules/delegate -> components/component-delegate
  Linking : node_modules/inputarea/node_modules/events/node_modules/delegate/node_modules/matches-selector -> components/component-matches-selector
  Linking : node_modules/inputarea/node_modules/events/node_modules/delegate/node_modules/matches-selector/node_modules/query -> components/component-query
  Linking : node_modules/inputarea/node_modules/classes -> components/component-classes
  Linking : node_modules/inputarea/node_modules/classes/node_modules/indexof -> components/component-indexof

I do not recommend using this for public components though. I mainly use it to be able to test non-DOM components using node itself (as opposed to phantomjs)

jonathanong commented 10 years ago

i don't think this belongs in the spec, especially since it's an npm problem, not component. component's require is supposed to be flexible.

open up an issue in buidler.js builder2.js if you have a suggestion (since that's where it should be handled).