-
Notifications
You must be signed in to change notification settings - Fork 45
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
Use moduleIds instead of urls #28
Comments
Do you mean
In two places in the first Example? These lines do not match the |
@johnjbarton Yes. Updating. Edit: removed the Duplicate loading of ModulesWhat happens if I do: System.paths["lodash/*"] = "cdn.com/lodash/*"; import "lodash/main";
import "lodash/array"; And in "lodash/main.js", it does: import "./array"; Will this load "lodash/array.js" twice? |
This has to mean One side effect of allowing
is that, absent a remapping, it would resolve to |
Edit: Updated title. |
That effectively means no |
This is something we commonly want people to do in CanJS. CanJS runs on either Dojo / Mootools / Zepto / jQuery or YUI. We let people alias a This type of thing should be possible. |
Yes, allow that. Just don't allow |
Why? I'd argue that there are good reasons to patch some specific file. For instance browserify's "browser" field allows developers to do this for node modules so they work on the server. Example:
|
Accident! |
In a module system, module By distinguishing "./foo/x.js" and "foo/x.js" we allow package authors to express two different ideas. With "./foo/x.js" they are saying "I support the use of my implementation of "x.js"; with "foo/x.js" they say "I support any implementation matching the interface of "foo/x.js". Package users can remap "foo/x.js" but if they want to change the "x.js" pulled in by "./foo/x.js" they have to hack. That sets the right kind of barrier to help package authors give appropriate levels of support to users. Allowing every path to be remapped creates an overly complex solution with no role for the package author to create boundaries. It's similar to the difference between private_ and public members or other forms of software boundaries. |
@justinbmeyer I see a lot of misleading parts in this issue. we need some concrete examples that illustrate the issue. Keep in mind that any discussion around this will have to cover these two cases as well: <script src="./a/b.js" type="module"></script>
<script type="module">
import "./x/y.js";
</script>
<script>
System.import('./j/k.js');
</script> you should also look at #20, where we have some details |
Thanks everyone for all the feedback. I'm trying my best to understand this choice and be as level-headed about the reasons for and against it as possible. @caridy What is misleading? Does the "Build systems" section make sense? Why is it not concrete enough? On those use cases, I don't believe a user should be able to write that. Those are not valid moduleIds. Another takeAfter having a discussion with @guybedford about this I'm trying to understand why people support this change and what the tradeoffs are. In my opinion, it comes down to:
VS
I favor the ecosystem / extension developer point. I believe that: Any mature application development will be based around moduleIds.This means that even if canonical URLS are used, advanced users will add loader extensions that use moduleIds.
Extension development will be difficult.Taking my The form of and access to those moduleIds will be fragmented.Many extensions will have their own form of moduleIds and moduleId side-tables, making interoperability more difficult. If the goals (#27) of this group are only to create a minimal spec that enables as much as possible, then I understand the removal of moduleIds. However, I'm fairly confident that it will have missed an opportunity to provide an extremely important integration point for extension and ecosystem authors needed to build a wide variety of interoperable tools and libraries. |
TLDR; moduleIds are important because it's very common to have a module at different URLs at different times of an application lifecycle. moduleIds make dealing with this much easier and are worth a little effort to understand on part of users. |
From the requirejs perspective, I tried supporting URLs and module IDs in dependency references, and it just led to confusion, and ultimately limited, even broke optimizations, and made things like "map" config not possible in a general sense. To use those features, the requirement is "use only IDs", and in a requirejs 3, I would remove the support for plain URLs as module references. I believe the problem is assuming the forms that @caridy mentioned above should be supported. I started from the same place with requirejs, but it did not work out well. So I suggest the reasons for trying to support that should be revisited. I would be happy to talk more about this in a more realtime talk, as these sorts of issues just get mired in people's subjective text parsing and time issues, and often the disconnect is a deeper philosophical issue that really only comes out in people being able to talk in realtime. In the absence of that, some other things to consider:
I now view module IDs like the identifiers for functions, and the loader should treat their storage similarly. Instead of language identifiers, modules use string names that allow for some relative referencing via segments separated by "/", and they may be async-resolved. But they have a name that is incidental to what address the came from. This becomes even clearer once there is nested inlining of modules. This happens today with browserified/amd-optimized modules having an internal module structure all defined inline, but also a public face for use by other module code outside. This is similar to how named functions can be nested inside other named functions. Using module IDs makes it clear that these are just units of code referenced via a name. Making sure they are distinct entities from an address (which may or may not actually be used to load the module) will lead to fewer misunderstandings, and allows much for flexibility for loader configuration, flexibility that has been proven to be useful in AMD loaders, specifically the package and map configs. |
I want to chime in that moduleIds work better for browsers. @jrburke pointed out some very good examples and I want to expound on plugins. Consider a resource that is loaded by 2 different packages. One might load it with the There are lots of scenarios where you want "pseudo" modules that don't actually map to a url. Inlined modules is one example. But if we can Lastly I just want to stress how important this decision is, as it will influence how modules are written going forward. |
#52 could be considered a response to this. |
with the latest refactors to allow sync operations on the registry, we have settle on using the result from resolve hook as the keys for the registry. |
Bah humbug. I realize you have to make a decision. I hope this is the right one. Sent from my iPhone
|
I don’t know what the WHATWG policy is regarding reopening “closed” issues, but I was just informed today of this issue via Twitter and I would strenuously encourage reconsideration of the use of URLs as registry keys in the final design of the loader specification. Last month I wrote a fairly lengthy article about this topic that explains why I think you can’t just use file paths or URLs to address various different real world use cases, and how using URLs makes a loader design brittle and harder to reason about for any non-trivial application. (Alternatively I would be happy for someone from the WG to explain how I am wrong, and how the WHATWG loader using URLs is going to be able to cleanly solve the use cases described therein.) Others in this thread have also been making many of the same arguments, and it’s disheartening to see that there isn’t even a single rebuttal to their arguments from the WG, just a “we’re doing it this other way”. Is there some other discussion forum where all of the people in this ticket were answered and I just don’t know about it? Thanks! |
@csnover feel free to ping me (caridy at gmail dot com), and we can chat about it. As for reconsider any decision we make here, it is as simple as having a good reason to do so. We are very open to correct any mistake or problems to make this spec better. |
whatwg/loader changes relative module identifiers, like
"../foo"
, from being name-normalized to address-normalized. I think this is an incorrect solution because:Background
There are 3 namespaces:
../foo
,bar/foo
,http://cdn.com/bar/foo.js
.Terms:
This change makes the default normalize hook use the "parentAddress" with module specifiers that look like "../" or "./". This will result in normalized names that are urls/paths.
Example
Compare what happens previously to currently with the following example:
Previously:
Current
Rationale for the change.
The following are examples I've found discussing the reasons for the change. This seemingly is to solve the confusion that moduleNames are a separate namespace from addresses. I think address-normalization will cause more problems than it solves. I will discuss the reasons for this next; however, I will link to those reasons in the following rationale and example sections.
Rationale 1
It is true that you will commonly expect the file loaded to be relative to the parent module's address. This will happen most of the time with name-normalization. However, the following example shows a case where this does not happen:
Example 1.A
A user expected the following to load
"path/to/two.js"
instead of"two.js"
:With name-normalization, this is a mistake by the user of misunderstanding that moduleNames are not addresses.
./
is swapping out the current module nameone
fortwo
. They could fix this problem by simply adding:or
Example 1.B
In this example, the code might look like:
The result is that name-normalized would load
"http://bar.com/b.js"
while address-normalized would load"http://foo.com/b.js"
. I think users would and should expect"http://bar.com/b.js"
to load. The address-normalized result will be more difficult to deal with in builds.Example 2
I'm unsure what this use case is exactly. I hope the details of it can be provided. My guess is that a
polyfill/reflect/util
should be loaded instead ofjs/reflect/util
and thatpolyfill/reflect/util
has its own relative dependencies. The code setup might look like:The idea is to swap
js/reflect/util.js
with something like the followingpolyfills/reflect/util.js
:The problem is that with a paths config like:
...
./magic
will normalize tojs/reflect/magic
.However, this can be solved better with a map config that is used by RequireJS or SystemJS like:
Conclusions
In short, the problems attempted to be solved by address-normalization are either:
The following will discuss some very real problems that will be created by address-normalization.
Problems with address-normalization
By incorporating addresses into moduleNames, address-normalization creates non-deterministic moduleNames in all sorts of situations. Deterministic moduleNames are critical for a lot of advanced, but essential functionality.
System extensions that match moduleNames and different environments.
It's pretty common to point something like
lodash
to a CDN only in production. And, it will be pretty common that some extension might want to run on only certain modules specified by a System config like:However, this will not work because my
ES6-ES5
plugin can not simply match moduleNames that start withlodash
because if anylodash
module uses a relative path, it's module name might be something like: "http://cdn.com/lodash/array.js". address-normalization will force all config to be addressed based, and much more likely to change.Build systems
Build systems typically have to write out a version of a module that is self defining. For instance:
It's very important that the right
moduleNames
are written out that the client understands and can repeatably locate. address-normalization will make this very hard.Build systems often load files in different paths and have different addresses. The client might find "lodash/array" at
http://localhost/utils/lodash/array.js
, but the server might see it at:/user/jbm/dev/project/shared/utils/lodash/array.js
. This file can not be written out like:Or even:
The reason is that the client might want to dynamically import "lodash/superArray" which might look like:
The client would see "lodash/superArray" at
http://localhost/utils/lodash/array/superArray.js
and would loadhttp://localhost/utils/lodash/array/array.js
twice.Recommendations
It's highly likely I am missing something. But if I'm not, this seems like a step in the wrong direction. I recommend reverting to name-normalization and adding a
"map"
specification.The text was updated successfully, but these errors were encountered: