zenparsing / es6now

ECMAScript 6 to 5 Compiler and Runtime Environment
MIT License
29 stars 2 forks source link

".js" convention #21

Closed guybedford closed 10 years ago

guybedford commented 10 years ago

The current convention for ES6 is to exclude the '.js' extension, as has been discussed on TC39.

This is what all current implementations that I've seen are doing based on the pseudo- implementation at https://github.com/jorendorff/js-loaders/blob/master/browser-loader.js.

zenparsing commented 10 years ago

Yeah, I realize that. Automatically appending the ".js" extension was controversial and opposed by certain members of TC39. Certain W3C people are uncomfortable with it as well.

Those advocating CommonJS-style "module IDs" were unable to achieve consensus within TC39, and therefore the ES6 spec does not included any guidance one way or another.

My opinion is that CommonJS-style "IDs" aren't a good match for a module system that is intended to be at home on both the browser and the server. My hope is that others will see that as well before it's too late.

I can explain my reasoning if you're interested.

guybedford commented 10 years ago

I'd be very interested to hear your opinion on this yes, if this is a good context for it great, otherwise feel free to email me as well.

zenparsing commented 10 years ago

This is the perfect place for it, but I'll have to come back to it tomorrow.

As a bit of history though, the js-loaders project was written by those members of TC39 that advocated for the CJS style, even though there was a big, heated, and unresolved debate over it about a year ago on es-discuss.

zenparsing commented 10 years ago

Sorry @guybedford for the delay in responding. I'm working on a blog post which will flesh out my ideas on the subject and includes some research that I did. I'll let you know when I've finished it.

zenparsing commented 10 years ago

@guybedford it is my understanding that if the built-in Loader was URL-based, implementing Node-style module specifiers with a custom loader would be quite trivial, and would amount to overriding the normalize hook to:

Is that right?

guybedford commented 10 years ago

How would moving the .js and baseURL rules into normalize simplify here?

I'm not sure what you mean about "does not start with '.'", but the rules you've mentioned above are the standard rules of the locate hook in the currently proposed System loader implementation.

A node-style module loader has been implemented at https://github.com/calvinmetcalf/es6-translate. While I disagree on the handling of default exports, the general implementation principles as a custom loader seem to work well.

zenparsing commented 10 years ago

Sorry, I must not have been clear. I know that the rules above are baked in to the proposed standard hooks.

But suppose for a minute that the standard loader was URL-based, instead of CommonJS-based. Then, if the user wanted to implement a custom loader which interpreted module specifiers in the CJS fashion, that would be trivial. Is that right?

In that scenario, the user would want to override the normalize hook, IIUC.

guybedford commented 10 years ago

Yes, it's purely an argument about default behaviour anyway - it can all be overridden either way.

Note that this is really about how the registry object itself looks. The worry with URLs in the registry is that URLs are not universal in the sense that my loader will have different URLs to your loader, so even if we have the same modules, we have different looking registries. There is a certain elegance to having a canonical universal registry as something that is possible.

But that aside, I think the point still remains what the added benefit of the extension / url forms as default is.

zenparsing commented 10 years ago

OK, cool.

So to your second paragraph, I agree completely. But URLs (and by URLs I mean fully general URIs) are capable of representing abstract identifiers, by simply using a custom scheme. In es6now, I use "package:" for that purpose.

The benefit of having the standard loader be URL-based is architectural: on the web there is one universal syntax to represent resources. In fact, URLs are one of the core architectural principles of the web. If we are going to introduce an incompatible resource identifier syntax, then there should be a very good reason. As far as I can tell, the only argument for CJS-style identifiers is saving a few keystrokes. This doesn't strike me as a compelling reason.

Furthermore, automatically appending file extensions is an alien concept for the core web platform, and seems to go against the very useful principle that the form of a URL is not coupled with the content of the resource that it represents.

guybedford commented 10 years ago

I use custom schemes as well - npm:some/module for example. In this way it becomes a universally meaningful reference as you say.

But I can do that without having it mean that it is a URL. If we use URLs, we have to carefully define what we mean by the primary form - is it absolute or relative to the baseURL, is it with the protocol or not etc. These are tricky things to set down and if not done properly, we end up with a mess of URLs that have tricky normalization rules into a unique URL, which is a core property of the registry.

URLs are designed with concepts of DNS in mind, which don't apply for modules, as the baseURL / paths rules effectively abstracts this away making modules portable.

I think the point is that the module loader can only load js files, so why have unnecessary repetition. These precedents have also been set and adopted individually by the CommonJS and AMD communities.

zenparsing commented 10 years ago

Re. paragraph 2: There is nothing new to set down, though. I'm proposing that the browser (by default) do only what it currently does with any URL found in HTML, CSS, etc. The interpretation of custom schema would be an exercise for the user (and should only take a few lines of code). In this way, users can do whatever they want without polluting the web's URL-based architecture.

Re. paragraph 3: The location is only abstracted away in the case of package identifiers. Relative paths are still very much "locators", and my research shows that relative paths make up about 43% of all require calls.

For the rest (which include package names and system/node modules), URLs give us a very useful property that CJS identifiers do not have: multiple namespaces can be defined by schema. So for instance we can have a dom scheme for DOM stuff and a sys scheme for core language stuff. With CJS identifiers, they are all lumped in the same pool. URIs (and please, when I say URL, think URI) were designed with universality in mind.

Re paragraph 4: Right - this is the "keystrokes" argument. But again, saving a few keystrokes is not a valid reason to violate a core web principle (that the form of a URL is not coupled with the content it represents). And consider, even Node does not mandate file extensions. It's totally possible in Node to use the file extension if you want. Mandating that all modules must have ".js" file extensions for their URLs is, well, madness. I don't know any other way to say it! : )

As far as AMD goes, it is a user-level library and makes design decisions that are appropriate for a library. But what is appropriate for a library is not necessarily appropriate for the platform.

guybedford commented 10 years ago

There is a little to set down with the URLs - will the registry contain http://example.com/resource.js or just /resource.js or resource.js. This affects the way relative module names operate so it should be done somewhat consistently ideally if universality is a goal. All these other properties of URLs become problems not solutions in this context.

The location is abstracted away when I just have a module called jquery in the registry, whether it is a relative module name or not.

I agree with you on the concept of schema though. We have all our module names of the following form: jquery, npm:jquery, example:module etc. So instead of paths, we use the schema form to denote different locations. The location itself is effectively just a baseURL, with a default location when no schema is provided. This can potentially transfer simply without needing all the other overhead that URLs bring.

The js extension argument is also an important one to discuss. I'm also almost tempted to agree with you here, but was hoping to hear stronger arguments since script tags seem to work fine with just js extensions in most cases.

guybedford commented 10 years ago

Actually you may want to have a look at https://github.com/google/traceur-compiler/issues/1221.

zenparsing commented 10 years ago

See #22