systemjs / systemjs

Dynamic ES module loader
MIT License
12.95k stars 1.09k forks source link

deprecate baseURL #290

Closed guybedford closed 9 years ago

guybedford commented 9 years ago

I believe this is going out with the move to module names as URIs.

@caridy it would be good to get confirmation on this?

guybedford commented 9 years ago

Effectively baseURL is just window.href.

matthewp commented 9 years ago

Can you explain what this means? How do you set the baseURL with this change?

guybedford commented 9 years ago

Using paths for example - module names are URIs so changing the baseURL doesn't make sense I don't think.

matthewp commented 9 years ago

It's nice being able to do System.baseURL = '../', can I do that with paths? I guess that would probably work...

matthewp commented 9 years ago

Hm, I don't think that would be very nice to write. You'd have to take the href, check to see if it's a file path and if so remove the file name, then add '../'. I like baseURL for convenience.

guybedford commented 9 years ago
  System.paths['app'] = '../';
  System.import('app/main');
guybedford commented 9 years ago

Or even just System.import('../main');

matthewp commented 9 years ago

Oh, awesome, I thought with the new sites the value had to be the full url.

matthewp commented 9 years ago

Will your paths extension support wildcards? I want to be able to do System.paths['*'] = '../';

guybedford commented 9 years ago

I'd hope so, but yes this stuff is where we may hit issues later, but I'm hoping we can help flesh out suggestions to the spec on this stuff. And if not, paths can do its own internal normalization so we have a buffer.

Paths is a wildcard, there isn't currently a wildcard proposal for paths for things like paths['*.less'] = 'less/*.less' though.

guybedford commented 9 years ago

Oh right - I was actually considering adding a single wildcard path rule like that yes, good point. But I don't want it to be more general than that specific case.

guybedford commented 9 years ago

Actually I suppose though, if we did that, that would just be baseURL though?

So maybe we shouldn't deprecate baseURL rather? Then if the spec doesn't implement, we provide the implementation?

matthewp commented 9 years ago

:+1: to not deprecating.

guybedford commented 9 years ago

Yeah I guess it is all or nothing.

Ok how about this then - what's a good argument that we even need a baseURL or wildcard path?

matthewp commented 9 years ago

You can't load modules from the root without a baseURL. And that's something that's common and desirable.

guybedford commented 9 years ago

You mean like System.import('/x.js')? This will be allowed.

matthewp commented 9 years ago

No, I mean like System.import('foo') where foo is at baseURL + '/foo.js'

guybedford commented 9 years ago

Right, I appreciate that, but perhaps we've just got used to a simple convention that we can do without?

matthewp commented 9 years ago

Why should we do without it though? What do we gain from getting rid of it? Btw, in jspm don't you have a ~/ path for this purpose as well?

guybedford commented 9 years ago

Each API feature should have a good reason for being there. That pressure is the difference between bloat and streamlining. Just because a feature has become tradition doesn't give it exception, and this is the big breaking change where we can consider these things, which won't be happening again soon.

In jspm the we've changed to defining an app path - https://github.com/jspm/jspm-cli/wiki/Getting-Started#5-in-an-html-page-include-the-downloaded-systemjs-loader-along-with-the-automatically-generated-configuration-file-configjs-then-load-the-modules.

guybedford commented 9 years ago

Sorry, don't mean to drone on... just throwing these ideas out, really value the feedback.

matthewp commented 9 years ago

I don't mind the debate. So what is app/? Is that the base directory? So if your structure looks like:

one
  models
  components
two
  models
  components
three
  models
  views

To get to the "car" model you might do System.import('app/one/models/cart'), is that right? Or does app mean something else here?

guybedford commented 9 years ago

App would be a path the user would always define in the config file to the application code:

System.paths['app'] = '/src/';
matthewp commented 9 years ago

Without a baseURL (or a wildcard path) you can't reuse a config file. The paths become worthless, they have to be redefined for each page.

guybedford commented 9 years ago

Ok, agreed we need to keep baseURL It is critically necessary for bundling, because the only way to bundle in a URL module scheme is either as absolute URIs or relative to some baseURL. Absolute URI bundles are not portable so to make them portable we need a baseURL the names are relative to.

guybedford commented 9 years ago

Not happening.

caridy commented 9 years ago

@guybedford I will keep this in mind, we can revisit this later this month. I'm not fully convinced that we need baseURL, we will see.

guybedford commented 9 years ago

@caridy sure that makes sense, but as long as it can be implemented in an extension (which it currently can be). As discussed here, we do need this feature after all.

matthewp commented 9 years ago

@caridy I'm not sure how it's possible to reuse a config that contains paths without baseURL. Reusing a config is very important in large applications where you have more than a single index.html. You might have separate test/demo pages for each component you are working on and need to use the same configuration file for each of these.

caridy commented 9 years ago

@matthewp this is not different from scripts, and even links in a page. The same principle should apply, including <base href="/path/to/base/">. My main concern of introducing a configuration is that script/module tags will not, or should not, rely on that for obvious reasons, which means we will have a dual behavior, and that will be undesired.

matthewp commented 9 years ago

Geez, I forgot all about base. I remember it having a lot of gotchas in the past but maybe those have been cleared up. Can you put a relative path in the base href (relative to the current document)? If so that might work. Still have to consider non-browser environments though.

guybedford commented 9 years ago

Yeah would one really want the script base and the <a href="some/path"> bases to match though? This is creating coupled concerns between navigation and script loading.

caridy commented 9 years ago

@matthewp yes

guybedford commented 9 years ago

I just wanted to come back to this idea of deprecating an explicit baseURL for the loader. The baseURL "under the hood" can be the base or window.location.origin.

The problem we hit previously was that bundles want to be able to be baseURL-relative and control that baseURL.

But surely we just use absolute URLs for bundles then?

System.register('/first/module.js', ...)

That is, our bundle names still go through the locate phase, but not the normalize phase (these phases will be simulated within the new resolve hook for conceptual simplicity).

So @matthewp do you have a strong argument that bundle names need more than absolute normalization rules? Note that SystemJS will probably still expose a locate hook so that custom location functions could be written allowing custom concepts of bundleBase and bundle portability.

In short, I'm still keen to deprecate an explicit baseURL in the loader, and just make the root the default internal baseURL which is a fixed natural reference point.

matthewp commented 9 years ago

I'm not following your question, maybe it's related to how System.register bundles works (which we don't use)? I would hope that the bundle extension still normalizes (or whatever that becomes) the bundle names though, I can't think of a reason why not? I'm probably misunderstanding you though.

guybedford commented 9 years ago

Regardless of the exact process, the question is simply if there are scenarios where an explicit baseURL not matching the window.location might be needed, and I'm still not convinced that there are.

matthewp commented 9 years ago

Yes, I don't think so. I haven't used <base> in recent years so if it's possible to do <base href="../../"> then I don't see a need for a SystemJS baseURL.

MajorBreakfast commented 9 years ago

I think baseURL should go away. Or at least I don't see me ever using it. Edit: I think baseURL isn't necessary in the browser case. For web workers it's another story as I'm not aware of an alternative.

BTW in ember apps we extensively use the base tag because the server responds to example.com and example.com/posts/10 with the same index.html. The ember app will look differently for both URLs of course - but that's all in the client-side code. The index.html contains a base tag with a domain relative URL, e.g. "/", so that all resources are found.

theefer commented 9 years ago

I'd stay away from relying on <base href="..."> as other framework (e.g. Angular) seem to want to (ab)use it for their router and this will likely creating mixing of concerns that will be hard to reconciliate across the various bits that would read this tag.

In our app, we need to override the baseURL to point to /assets, which is the path under which our server exposes the assets from its public local folder. If there were no baseURL, how would we be expected to manage this in the configuration?

MajorBreakfast commented 9 years ago

I'd stay away from relying on as other framework (e.g. Angular) seem to want to (ab)use it for their router

@theefer What do you mean? I think the base tag is the optimal primitive to define what place you consider the app root in relation to the domain (or to the current resource, though that's inconvenient because the relative location usually isn't fixed). I am not aware of any downsides.

probins commented 9 years ago

if there are scenarios where an explicit baseURL not matching the window.location might be needed

when you are loading from the cloud, not from the server that the base html sits on. My 'app' consists of a small html file that people can copy to Google Drive, Dropbox or similar, and which pulls in the code from jspm:github. I have a testing version which pulls in from localhost, and the only real difference is the baseURL. I might be able to use <base> instead; I have used this in the past and seem to remember coming across issues, but it's so long ago I can't really remember what the issues were.

matthewp commented 9 years ago

Actually I think baseURL is essential in Node. You can't reasonably expect to be able to change process.chdir() because other parts of the program (other libraries, etc) will not be expecting it.

theefer commented 9 years ago

@MajorBreakfast For Angular, the base URL is essentially the root for the routing. For SystemJS, the base URL is the root for resolving module paths. What if the routing root (say /) is not the same as the module path root (say /assets or even https://cdn.example.io/app-files)?

@guybedford I know we discussed this in previous issues and PRs, but how else than using baseURL is one supposed to setup the server path where assets are exposed under? Can't really hack the paths in the config as they would then no longer match local file paths on disk. I might be missing something, but this seems like a strong need for baseURL.

guilhermeaiolfi commented 9 years ago

I'm using baseURL to define the path for production/development/etc based on the 'environment' that my server-side framework is using. That way I keep the same config.js regardless. So it's essential for me or am I doing that wrong?

guybedford commented 9 years ago

The idea was to try and converge on absolute URLs (like /path/to/module.js) and share that base always, but I guess it is a little too restricting to always expect.

theefer commented 9 years ago

For us the problem is that the absolute path of the URL on the server may need to differ from the local path. The common path fragment can indeed be set in the config.js paths, but the server prefix has to be set using System.baseURL whereas the local filesystem prefix is set using directories.baseURL in package.json.

For example consider:

// config.js

System.config({
  "paths": {
    "app/*": "lib/*.js",
    "github:*": "jspm_packages/github/*.js",
    "npm:*": "jspm_packages/npm/*.js"
  }
});

// SERVER
https://example.com/index.html (or https://example.com/somewhere/else/index.html)

<script src="/assets/config.js"></script>
<script>
System.baseURL = '/assets';
System.import('app/main');
</script>

loads:
https://example.com/assets/config.js
https://example.com/assets/lib/main.js

// package.json

{
  "jspm": {
    "directories": {
      "baseURL": "public"
    },
   ...
}

given:
dir/package.json
dir/public/config.js
dir/public/lib/main.js

In other words, for paths to resolve correctly on both the server and client, they need different baseURLs. I think that's a fairly common pattern really...

MajorBreakfast commented 9 years ago

@theefer It's possible to dynamically set the base tag just like baseURL:

<head>
  <script>
    if (...) { document.write('<base href="...">') }
  </script>
  <!-- Inserts the base tag here -->
</head>

I've done this in the past. It works as expected.

theefer commented 9 years ago

@MajorBreakfast But in my example above, it'd have to be set to /assets for SystemJS (root of assets paths) and to / for AngularJS (navigation). Which one is it?

guybedford commented 9 years ago

Thanks everyone for letting me rehash this. It sounds like we will stick with it for practicality.

MajorBreakfast commented 9 years ago

@theefer The trick is to avoid that scenario in the first place. For example:

<link rel="stylesheet" href="assets/style.css">
System.import('assets/style.css!')

It's better if these two access the same file to avoid unnecessary confusion. The baseURL then only needs to be used in environments like node oder web workers which have no base tag.