framework icon indicating copy to clipboard operation
framework copied to clipboard

Make resources receivable from external repositories/cdn's etc

Open DamageLimiter opened this issue 8 years ago • 11 comments

I'm submitting a bug report

  • Library Version: 1.0.2

Please tell us about your environment:

  • Operating System: Windows 10

  • Node Version: 4.6.0

  • NPM Version: 3.10.10
  • JSPM OR Webpack AND Version aurelia cli
  • Browser: all

  • Language: all

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.

  • What is the motivation / use case for changing the behavior? We are serving 60.000 employees across the world. Saving and optimizing bandwith is important to us. Custom elements like grids, tables, layout stuff etc. do not change and are equally implemented in all our applications. Deploying these custom elements on a loadbalanced web server ensures that browsers cache these elements across all our 400 applications. We are actually doing this with our current knockout-based framework, too, and works perfectly.

DamageLimiter avatar Nov 29 '16 12:11 DamageLimiter

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

jdanyow avatar Nov 30 '16 01:11 jdanyow

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.

DamageLimiter avatar Nov 30 '16 14:11 DamageLimiter

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

jdanyow avatar Nov 30 '16 15:11 jdanyow

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 avatar Nov 30 '16 16:11 DamageLimiter

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 avatar Nov 30 '16 16:11 DamageLimiter

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

DamageLimiter avatar Dec 02 '16 10:12 DamageLimiter

@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.

jdanyow avatar Dec 02 '16 11:12 jdanyow

@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.

  • For missing/misspelled .html files it throws the error
  • Sometimes you'll get the same error when adding plugins to the bundle in aurelia.json. I can't remember the specific scenario.

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

stsje avatar Dec 02 '16 12:12 stsje

@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 ;-)

DamageLimiter avatar Dec 02 '16 13:12 DamageLimiter

@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.

rdelhommer avatar Jan 21 '18 01:01 rdelhommer

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

mattduffield avatar Jan 21 '18 07:01 mattduffield