Aurelia: Lazy load of js+html features with FrameworkConfiguration? - aurelia

I want to configure a lazy load of some features with both js and html elements.
If I do aurelia.use.feature('js+html-custom-element') in configure() of main.ts everything works as expected.
But when I postpone loading like
return new FrameworkConfiguration(aurelia)
.feature('js+html-custom-element')
.apply();
then browser loads both js and html files but html is not rendered!? No errors in a console window.
In case with 'js-only-custom-element' lazy load works as expected.
Is this expected behaviour, bug or am I missing something?
aurelia-framework 1.1.5 jspm +type script solution.

Aurelia uses strong file naming convention.
For component, if the file defines class JsHtmlCustomElement, Aurelia expects the file name is js-html-custom-element.js.
For value converter (or binding behaviour, custom attribute), it can
either use naming convention foo-bar.js for class
FooBarValueConverter.
or with help of annotation foo-bar.js for
#valueConverter('fooBar') export class FooBar.

Related

How to lazy load a plugin in Vue?

Vue plugins usually requires a global setup in app entrypoint by Vue.use(somePlugin). Doing so increases the bundle size for all pages, which is often bad and that it is better to defer the downloading of the module until when the module is actually being used, aka lazy loading or code spliting.
How do I lazy load a plugin if only one page in my Vue app needs it?
To answer the OP's question more directly: You can't lazy load a plugin.
According to the documentation, plugins by definition provide globally-accessible functionality and must be setup with Vue.use() before the Vue instance is created. Due to this, they'll always be bundled with the entire Vue instance (in a vendors chunk, for example).
What you want is to lazy load the functionality in a smaller scope, at a component level. Depending on the plugin, the plugin module should also support some sort of direct code importing at a component level, like this one does. Because it just uses import statements, they can be async loaded.
TL;DR: Anything using Vue.use() can't be lazy loaded. Async imports can.
One of the options is to call your plugin file in created/mounted hook and do the stuff you want.
Just import it on the specific page an example would be "Slide" from "vue-burger-menu"
<script>
import { Slide } from "vue-burger-menu"
export default {
components: {
Slide
}
}
</script>

Vue JSX bind to class name

I'm building a simple TodoMVC app using Vue + JSX, but the documentation seems to be seriously lacking. Thus, I'm writing down the points I need to address as part of a CR to the appropriate projects. The only document I've read as of yet is the guide, which doesn't cover much JSX at all. I don't know much about how the framework works yet, but I sure prefer using the render method over the string templates for performance/network reasons.
question
What's the proper way to create a class name binding in Vue + JSX? In my TodoItem component, creating either a class or className attribute makes Babel throw a compile error complaining the API is deprecated (and suggesting I add several seemingly unrelated dependencies to the mix). Plus, including the class property in the data object seems to change nothing.
secondary question
The lack of documentation, plus the wording on the guide gives the impression JSX is not the "proper" way to write Vue components. Is that so? What's the idiomatic way to do it, given I don't want to ship the compiler along with my app?
links
code on codepan
I sure prefer using the render method over the string templates for performance/network reasons.
If you're writing *.vue files and bundling them with vue-loader (Webpack), the HTML template gets compiled into a JavaScript render function anyway, so there isn't really any kind of performance issues in that sense.
On the other hand, if you're writing your Vue components with string templates like this:
new Vue({
template: '<div>Hello</div>'
})
then you'll need the Vue template compiler at runtime to convert the string into a render function.
Typically people would opt for writing render functions manually if they need to do something specific that would be difficult/impossible to do with the HTML template alone.
You've probably already read the docs, but just in case, the relevant sections are:
Render Functions & JSX
The Data Object In-Depth
babel-plugin-transform-vue-jsx Usage
What's the proper way to create a class name binding in Vue + JSX?
You would just bind to the class attribute like you would any other attribute:
<div class={this.klass}>
data() {
return {
klass: 'foo'
}
}
The lack of documentation, plus the wording on the guide gives the impression JSX is not the "proper" way to write Vue components. Is that so? What's the idiomatic way to do it, given I don't want to ship the compiler along with my app?
JSX is definitely supported, but it is not the recommended approach. The recommended approach is to write *.vue files and load them with vue-loader (if using Webpack).
Vue comes in two versions, one with and one without the template compiler. The one with the compiler included is only for development and should not be used for production builds (unless you require string template to render function compilation at runtime, which is unlikely). See Explanation of Build Files for more info.
Typically you write HTML string templates, and they get compiled to render functions (by vue-loader) at build time.

How to intercept component loading with a loader plugin in aurelia (jspm)?

I want to intercept the module loading of Aurelia to redirect some calls.
To do such things the aurelia-loader has a addPlugin() interface. You add a suffix like !myplugin to a resource to mark that it should be loaded using that plugin.
Now when I do this with my own component, it loads the JS file but the name for the HTML template is messed up. Like from the resource name my-comp!myplugin it will load my-comp.js but tries to find my-comp!myplugin.html which does not match the plugin name anymore.
I have provided a gist with that issue here: https://gist.run/?id=c7ed477bc652540ed8b0702d843f1832
The loader plugin code in main.js is basically:
loader.addPlugin('gate', {
fetch(address) {
console.info('Intercepted:', address);
var tmpParts = address.split('.');
var extension = tmpParts[tmpParts.length - 1].toLowerCase();
if (extension == 'css') {
console.debug('Loading as styles', address);
return loader.loadText(address);
} else if(extension == 'html') {
console.debug('Loading as template:', address);
return loader.loadTemplate(address);
} else {
console.debug('Loading as module:', address);
return loader.loadModule(address);
}
}
});
Using it like this in a template (marked with Issue 1 in the gist):
<require from="./comp2!gate"></require>
After that is should be possible to load the component like this:
<comp2></comp2>
Or even like this:
<compose view-model="./comp2!gate"></compose>
Instead the name for the template is messed up, the browser console says:
Failed to load resource: the server responded with a status of 404 ()
https://gist.host/run/1485182959149/comp2!gate.html
The expected name of the template would be https://gist.host/run/1485182959149/comp2.html!gate (including the plugin)
How can I fix the loader plugin to work correctly?
The loader is aurelia-loader-default 1.0.0, JSPM is 0.16.39, Node is 6.5.0, NPM 3.10.5.
I have added a second gist.run: https://gist.run/?id=1ddd4233e3afc40d89eb64b751e1dd8f
It is a bit shorter. When I specify the view using #useView decorator in comp2.js (marked with issue 4), it works - but I cannot specify a loader plugin with #useView. I would expect it to load the view with the same loader plugin or be able to specify a loader plugin with #useView.
Okay, I found a solution which looks like it can work with less code and patching and it works between two gists.
This gist contains the external component comp3:
https://gist.run/?id=dc837978a514011e13c872dbad92ae3f
This gist is the basic Aurelia app with a plugin and a small patch to the applyPluginToUrl method of the loader:
https://gist.run/?id=39e6fdacefc9e5c69b42a5e8c9049384
If the gist URLs are fixed, it should work for everyone. The Aurelia app loads comp3 from the first gist and displays it (you see the purple border define in the comp3-view).
There is one caveat at the moment: No support for CSS as SystemJS adds the extension .js to them, looks like I have to take care of that.
I do not like the path to loader.applyPluginToUrl but SystemJS does not really support plugin chaining and so the order must be correct. Also this solution requires all external components to set #useView including the loader plugin.
Any better approaches?

Rangy injection module issue

I'm trying to inject the rangy javascript core and serializer code base (https://code.google.com/p/rangy/) into an html page. However when I inject it, the rangy object isn't created properly. The modules are added at rangy.modules.* however the functions created within the module are not added to the rangy object. Also the modules all have the following variables 'initialized' and 'supported' as false. Has anyone been able to inject the Rangy code base into their web page properly or can provide any assistance?
To inject - open up Chrome javascript console and insert code as minified (very important or it will not work - http://jscompress.com/):
javascript: insert code here
You can call rangy.init() to initialize Rangy after the page has loaded.

Dojo custom widget with external JavaScript libraries dependency

I'm developing a custom Dojo widget which in fact acts as a wrapper for Timeline JS library (http://www.simile-widgets.org/timeline/).
Is there a possibility to include the required JS code for Timeline in the custom dojo widget or must I include manually in my "index.html"??
Thanks in advance.
Do you have control over the Timeline source code, that is, are you hosting it yourself?
If this is the case you could turn the dependency into a dojo module by inserting an appropriate dojo.provide call on the top or you could just straight up copy-and-paste everything inside your MyWidget.js source file.
If this is all ends up too compicated for you to consider it worth it, adding the script tag by hand on the index.html is not that bad (given how base Javascript actually doesn't have a real module system you could use instead)