aurelia / framework

The Aurelia 1 framework entry point, bringing together all the required sub-modules of Aurelia.
MIT License
11.76k stars 627 forks source link

Make resources receivable from external repositories/cdn's etc #663

Open DamageLimiter opened 7 years ago

DamageLimiter commented 7 years ago

I'm submitting a bug report

Please tell us about your environment:

Current behavior: External resources (i. e. custom elements) cannot be referenced. If I try to reference a custom element from here:

config.globalResources(["https://www.cdn-intranet.com/resources/elements/test-stuff"]);

it tries to resolve the url "as-is" and does not try to resolve it for ".js" and ".html". In fact, it tries to resolve https://www.cdn-intranet.com/resources/elements/test-stuff and received a 404. I also tried

config.globalResources(["//www.cdn-intranet.com/resources/elements/test-stuff"]);

but it doesn't work, too.

Expected/desired behavior: It would be neat if aurelia would not make a difference between locally or externally available resources.

jdanyow commented 7 years ago

I think this is probably supported by the requirejs loader used by aurelia cli projects.

Try adding the following to the top of your main.js:


// add this: (don't worry, requirejs is in the global scope)
requirejs.config({
  packages: [
    {
      name: 'test-stuff',
      location: 'https://www.cdn-intranet.com/resources/elements/test-stuff',
      main: 'index'
    }
});

export function configure(aurelia: Aurelia) {
  aurelia.use
    .standardConfiguration()
    .plugin('test-stuff')                // <------- also add this
    .feature('resources');

Next, make sure you have an index.js at https://www.cdn-intranet.com/resources/elements/test-stuff/index.js that contains the transpiled version of this code:

export function configure(config) {
  config.globalResources([
    './upper-value-converter',
    // other stuff .....
  ]);
}

Last but not least, make sure you have a transpiled upper-value-converter.js at https://www.cdn-intranet.com/resources/elements/test-stuff/upper-value-converter.js

DamageLimiter commented 7 years ago

I've tried something similar but actually it works for js files only (perfectly for a value-converter). But if you try to load a custom component you need to have the html file loaded as well.

My Custom Component is called test-stuff. So what's happening -> require loads the index.js from a remote server as expected. Then the js file of the custom component (./test-stuff) is loaded from the remote server. This is working as expected, too. But then I receive this error:

Uncaught TypeError: h.load is not a function (This error appears about 1,5 seconds before the next one)

_Unhandled rejection Error: Load timeout for modules: template-registry-entry!test-stuff/test-stuff.html_unnormalized2,template-registry-entry!test-stuff/test-stuff.html,text!test-stuff/test-stuff.html_unnormalized3,text!test-stuff/test-stuff.html http://requirejs.org/docs/errors.html#timeout_

One interesting thing though: In the network tab of the browser I can see that it doesn't even try to load the html file.

jdanyow commented 7 years ago

ok getting close- would you be able to debug this and make a determination where things are going wrong in the loader?

DamageLimiter commented 7 years ago

Yes. I need to download the debug version of require though. This minified version is not very handy for debugging. Back in a few... :-)

DamageLimiter commented 7 years ago

It fails at this point here (in requirejs): plugin.load(map.name, localRequire, load, config);

Parameter map.name is "remoteStuff/test-stuff.html". Via aurelia-loader-default it tries to load the template:

TextTemplateLoader.prototype.loadTemplate = function loadTemplate(loader, entry) {
      return loader.loadText(entry.address).then(function (text) {
        entry.template = _aureliaPal.DOM.createTemplateFromMarkup(text);
      });
    };

entry.address is "remoteStuff/test-stuff.html". Which is wrong. It is supposed to be a remote address.

this is my require config:

requirejs.config({
    packages: [
        {
            name: 'remoteStuff',
            location: 'https://myInternalCDN.de/app/componentstore/aurelia/elements/test-stuff',
            main: 'index'
        }
    ]
});

aurelia config:

aurelia.use
        .standardConfiguration()
        .plugin("remoteStuff")
        .feature('resources');

transpiled version of "https://myInternalCDN.de/app/componentstore/aurelia/elements/test-stuff/index.js"

define('remoteStuff',["require", "exports"], function (require, exports) {
    "use strict";

    Object.defineProperty(exports, "__esModule", {
        value: true
    });

    function configure(config) {
        config.globalResources(["./test-stuff"]);
    }
    exports.configure = configure;
});
DamageLimiter commented 7 years ago

Are there any news yet? Can you work the debug information I've provided or do you need something else?

jdanyow commented 7 years ago

@DamageLimiter it would be awesome if you could continue to attack this one. Why isn't the module loader replacing the remoteStuff part of remoteStuff/test-stuff.html with the full url from the configuration?

In the meantime, what happens if you do something like this:

main.js:

import {TestTemplateLoader} from 'aurelia-loader-default';  // double check this import- I wrote this from memory

TextTemplateLoader.prototype.loadTemplate = function loadTemplate(loader, entry) {
  entry.address = entry.address.replace(/^remoteStuff\//, 'https://myInternalCDN.de/app/componentstore/aurelia/elements/test-stuff');

  return loader.loadText(entry.address).then(function (text) {
    entry.template = _aureliaPal.DOM.createTemplateFromMarkup(text);
  });
};

export function configure(aurelia) {
  ...
  ...
  ...

This kind of test ^^^ will tell us if there are any further roadblocks after we get the entry address fixed. It may also serve as a temporary workaround for you.

stsje commented 7 years ago

@jdanyow @EisenbergEffect We encounter the same Uncaught TypeError: h.load is not a function error quite often, and it isn't telling us what is going wrong. It is only in CLI projects using es2015. It would be nice to have a better error message, but I can't seem to figure out where in Aurelia/the cli that needs a change.

This missing error description is really a pain, and it often comes up in gitter as well.

DamageLimiter commented 7 years ago

@stsje h.load is the minified version of plugin.load (see me debug information) thus the error is thrown in requirejs. At the bottom line is more or a less a file not found or reference unknown error.

@jdanyow I'll dig in debugging the hell out of this. Once I identified the culprit I'll let you know ;-)

rdelhommer commented 6 years ago

@DamageLimiter Did you guys ever figure out a solution for this? My team is looking to do something similar and I'm curious how you resolved the issue.

mattduffield commented 6 years ago

Hi @rdelhommer, I put together a quick demo project of how I handle loading external plugins and libraries for external use. I have to do an extra step of bundling the plugins I want to use via a CDN but it works just fine. The sample project demos how you could bring in the aurelia-dialog plugin externally. I use this approach for FrontEnd Creator which is an online tool used to author Aurelia applications. https://github.com/mattduffield/au-cdn