Skip to content

Implement standard universal absolute schema for Angular 2 resource URI #2991

Closed

Description

@yjbanov

While support for relative URIs proved to be difficult we should be able to implement a standard absolute URI schema. Here's how:

Background

JS

In JS world Angular 2 components will be distributed via two methods:

Bundles

A bundle contains all components in a single JS file. In this model HTML templates and CSS would be inlined into the JS code and therefore no URL resolution would be required.

NPM source

Any resource in an NPM source package can be identified using two pieces of information:

  • package name
  • path to a file within the package

Dart

In Dart it is most common to distribute in source. Bundles are not used. Just like with NPM, any resource can be identified via the package name and path within the package (relative to the /lib).

Considerations

Certain projects, such as angular2_material target both JS and Dart. It is therefore desirable to have a URI schema that is language-agnostic.

In Dart (and eventually in JS) applications may run in two modes: dynamic and static. In dynamic mode URLs are resolved in the browser. In static mode URLs are resolved on the server by a transformer without actually running the application. We want the URIs to work inside as well as outside the browser.

Dart has lib and web folders. Resources in web cannot be imported by 3rd-party packages. Therefore web resource do not have to be covered by this proposal. For web we want to use either relative URLs or page-relative URLs (starting with /), which is outside the scope of this proposal.

Proposal

Adopt the following absolute URI schema:

package:{PACKAGE_NAME}/{PATH_TO_RESOURCE}

For example, the material button component will use the following templateUrl:

@View({
  templateUrl: 'package:angular2_material/src/components/button/button.html'
})
export class MdButton {
  ...
}

Advantages

  • unambiguous
  • ability to reuse templates from a 3rd-party packages, e.g. a component from package a may set templateUrl: 'package:b/some/template.html' pointing to package b. As long as the package specifies a dependency on package b in package.json or pubspec.yaml any tool can unambiguously locate the template.
  • works across languages: both npm and pub could support it, and it's likely that any other package manager would support this as well.
  • works inside and outside the browser: in Dart case in-browser resolver would turn package:a/b.html to packages/a/lib/b.html via the existing pub convention; the transformer would do the same translation and locate the resource via the file system.
  • it will be instantly familiar to TypeScript and Dart developers as {PACKAGE_NAME}/{PATH_TO_RESOURCE} is exactly how they import files.

Disadvantages

  • the need for package: prefix adds boilerplate.

Alternatives

Why package: prefix?

It makes it very clear that the resolution is done relative to a package (npm or pub). If the prefix is dropped, it is not clear whether the first part of the path refers to a package or is simply the first part of a relative path. We do want to implement relative paths at some point in the future and we will use prefix-less schema for that.

How about {PACKAGE_NAME}:{PATH_TO_RESOURCE}? Isn't it shorter?

This could work, but it would be misusing the intent behind the schema part of the URI. There is usually a limited number of possible values for schema, e.g. "http", "ftp". Putting package name as schema means that schema can take unlimited number of values. We might want to support more than just "package" schemas in the future (perhaps support "http" URL as well).

See also

#2945
#2593
#2383

Activity

  1. yjbanov commented on Jul 10, 2015

    @yjbanov
    ContributorAuthor
  2. matanlurey commented on Jul 10, 2015

    @matanlurey
    Contributor

    👍 this works out of the box for me.

  3. added this to the alpha-32 milestone on Jul 10, 2015
  4. sigmundch commented on Jul 10, 2015

    @sigmundch
    Contributor

    👍

  5. yjbanov commented on Jul 11, 2015

    @yjbanov
    ContributorAuthor
  6. self-assigned this
    on Jul 11, 2015
  7. rolandjitsu commented on Jul 12, 2015

    @rolandjitsu

    In JS I do not see the need to enforce package. Also, the templateUrl only supports absolute paths anyway (not sure if relative paths have been successfully implemented or they are still in dev or have been dropped).

    Of topic, using a globally configured baseUrl for all components and then the component's templateUrl and styleUrls resolving at that baseUrl + templateUrl/baseUrl + styleUrl would be nice.

  8. yjbanov commented on Jul 13, 2015

    @yjbanov
    ContributorAuthor

    @rolandjitsu package would not be enforced, only recommended and would make things consistent across multiple interdependent packages distributed in source, and the idea is that we provide an implementation of UrlResolver for all popular environments out-of-the-box, such as pub&npm. templateUrl attribute by itself is just a string. You can put whatever you want in it, as long as you have a suitable UrlResolver that knows what to do with it. We did attempt to implement relative paths, but were unsuccessful so far. We plan to come back to it at some point.

    As for global baseUrl, you can already do that. Simply implement your own UrlResolver that does just that. However, unless your dependencies also follow the same convention it might be hard to reuse and share code.

  9. rolandjitsu commented on Jul 14, 2015

    @rolandjitsu

    @yjbanov ok, so I could use UrlResolver to resolve components from the same baseUrl path. I'll try it out, though I am not sure what you mean when you say that it might be hard to reuse and share code.

  10. sigmundch commented on Jul 14, 2015

    @sigmundch
    Contributor

    @rolandjitsu - I think what @yjbanov was referring to is the problem of how different people can refer to each other's components in a consistent way. If people develop components separately, to refer from component A from component B, B's developer would need to know where to find A with respect to the baseUrl of the app. At that point everyone needs to agree on a convention. For example, that all components will be under baseUrl/components/.... This means that if another group of people follows a different convention, you may have trouble using their components.

    The package: urls are not that different, but they allow us to separate the problem in two: the layout of a project is now separate from how the dependencies are written. In the example above, B can import A with a package: URL (so A and B's developers don't need to know the layout of the app), but you can still use the UrlResolver to map those Urls to specific locations resolved from a baseUrl.

    Hope this clarifies the idea a bit.

  11. 6 remaining items

  12. yjbanov commented on Jul 20, 2015

    @yjbanov
    ContributorAuthor

    Bumping to alpha-33. This won't make it into alpha-32.

  13. yjbanov commented on Jul 23, 2015

    @yjbanov
    ContributorAuthor

    @robwormald thanks for the pointer. Yes, this proposal is very similar, although I'd like to try something that's package manager independent. We want to support pub and npm simultaneously already.

  14. rolandjitsu commented on Jul 31, 2015

    @rolandjitsu

    @yjbanov does this change also apply to the apps that use TS or JS and not Dart?

  15. yjbanov commented on Jul 31, 2015

    @yjbanov
    ContributorAuthor

    @rolandjitsu: #3215 only adds Dart support. JS support is tracked in #3257

  16. angular-automatic-lock-bot commented on Sep 6, 2019

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  17. locked and limited conversation to collaborators on Sep 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

effort2: daysfeatureLabel used to distinguish feature request from other issues

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions