Lazy-loaded overriden or custom CMS Components - spartacus-storefront

I was trying to test Lazy-loaded CMS components on ongoing Spartacus project with version 2.1.4 and I wasn't able to properly display the components. Before I continue with further investigation, I just want to check couple of things:
is it possible to lazy-load components which we have overriden, for example BannerComponent, SearchBoxComponent...?
is it possible to apply lazy-load on custom CMS components ?
are there any limitations when this feature won't work? Maybe in combination with some other feature?
There are many OOTB Spartacus CMS components that we have overriden in our project, and I have defined lazy-load feature for couple of them like it is described here https://sap.github.io/spartacus-docs/customizing-cms-components/#lazy-loaded-cms-components-code-splitting inside modules for certain components, this is one example:
breadcrumb.module.ts example here
and after the build, chunks are there, visible from source tab also, but components aren't displayed and there are errors because of missing modules (such as CommonModule, RouterModule, basically for everything that we used in our custom implementation..) which are declared in corresponding module but for some reason aren't registered at all.
Any guesses what we should fix in order to check if this feature is working in our architecture?

I suggest to stick "CMS-driven lazy loading of feature modules" (as explained here: https://sap.github.io/spartacus-docs/lazy-loading-guide/) instead of lazy loading of separate components (using component: () => import()) as it's simpler to make it work.
The idea is to define CMS mapping inside the module, which then will be lazy loaded (with components, services, etc.) instead of lazy loading separate (and decoupled) components. Then, in the root application, we let Spartacus know, which feature module should be loaded, when we want to render specified component (example: https://sap.github.io/spartacus-docs/lazy-loading-guide/#configuration-of-lazy-loaded-modules)
Using component: () => import() will lazy load only component code (no module, unless defined in the same file), such a component will have access to global (root) services, etc. It's still useful in some cases, but a bit problematic to make it work in more than basic scenarios (but this will improve in Spartacus 3.x/4.0).
Regarding your questions:
is it possible to lazy-load components which we have overriden, for example BannerComponent, SearchBoxComponent...?
Yes. Briefly explained here: https://sap.github.io/spartacus-docs/lazy-loading-guide/#wrapping-library-code-in-a-lazy-loaded-module
is it possible to apply lazy-load on custom CMS components ?
Yes.
are there any limitations when this feature won't work? Maybe in combination with some other feature?
As explained above.

Related

AsmComponentsModule does not have exported components

Our team needs to add custom code to the ASM module in order to make SSO login possible in our project, and we realised the AsmComponentsModule doesn't export its declared components. This made it difficult for us to reuse them, since we had to create our own custom module which is a copy of AsmComponentsModule, containing components that are simply extensions of the components declared on it.
This is problematic, since we also had to duplicate HTML and SCSS files. The problem would be even bigger if this module had even more components declared on it.
Is there a better way to do this? Or we should expect a future fix containing the exports array on this module?
PR Fix: https://github.com/SAP/spartacus/pull/15282
Will be released into 4.3.1 and 3.4.7 patches.

Vue.js components - handling translations within a component library from a consuming project without repetition

I fully expect this is a little niche, and I'm not sure if there's a solution, but I have an interesting situation.
We have a library of Vue components we use in our projects, from form fields to data tables. Some of these components need aria labels, buttons, labels, messages, and so on. Most of our projects will need translating into any number of languages, on the fly, often via user-selectable drop-down menus. Translation is handled by Vue i18n.
I have begun adding slots and props as required to allow this translation, but I realise it's going to be a lot of repetition to use the components, as it will be necessary to translate them each time they are used, some of which may be used hundreds of times in a large project.
The components are part of a library which has no knowledge of any current translation, and won't have access to the translated strings.
What I'm wondering is if anyone has an idea for how to essentially say 'here are some default slots and props for this component, which will override the defaults set in the component itself, but will apply every time I use this component in this project unless otherwise stated'.
I can't make these the defaults in the component itself, as what the default will be differs from user to user.
The only two thoughts I've had are:
Somehow passing the instance of the vue-i18n plugin to the components as they're used, allowing them to find their own translation strings.
Creating 'wrapper' components which are part of the current project, and thus do have access to translations, which can set a lot of these repetitive props and slots for us. This seems pretty reasonable, but doesn't solve where some components use others (e.g. our form components can be used by themselves, or initialised by a form builder, which then wouldn't know to use the 'middleware' components)
Am I missing an obvious solution?

How do I upgrade my Durandal.js app to Aurelia?

I have an existing Durandal.js app that takes advantage of all of the ES5 features but I want to upgrade it to the new Aurelia platform. What is the proper upgrade path and what is the simplest way to upgrade up front with as least pain as possible? Is there a doc with the upgrade path?
(Please feel free to make this a community answer by contributing)
Module Loading
Aurelia supports using AMD modules and require.js as a module loader. If you are using require.js with Durandal and want to convert your modules over to Aurelia they should be almost identical, depending on any future changes to require.js.
The lifecycle callbacks remain the same meaning that activate, attached, detached, deactivate, canActivate, canDeactivate, and any others should stay the same. They also still accept returning a promise.
If you choose not to stick with require.js, you can convert the AMD modules over from the AMD format to ES6+ format. This requires removing the first line or two and last line in the AMD module and replacing it with a class export similar to this -
define([], function (){
// stuff
]);
becomes
import {inject} from 'aurelia-framework';
#inject()
export class TheClassName{
// stuff
}
Where the inject piece is aurelia's DI system.
Data-binding
Aurelia provides the developer the ability to use whichever data-binding libraries you wish, including but not limited to the default aurelia-binding, handlebars, knockout, etc...
Some of these libraries may still need plugins to properly update when value changes occur, but this is a work-in-progress to find which do. If you are using Durandal 2.1 and knockout it is advised to leave the data-binding in place as-is and take a step-by-step approach to upgrading, one view model at a time. This is a work in progress and will be explained better moving forward
Aurelia data-binding tries to make use of the newest technology available but will gracefully fallback to dirty-checking. This enables the developer to build for the future but support the present.
The following article explains a possible upgrade path "Upgrading to Aurelia from Durandal.js":
https://github.com/aurelia/framework/blob/master/doc/article/drafts/durandal-to-aurelia.md
And the durandal extension "Durelia" helps with the migration:
https://github.com/josundt/Durelia

Cocoa/Objective-C Plugins Collisions

My application has a plugin system that allows my users to write their own plugins that get loaded at runtime. Usually this is fine but in some cases two plugins use the same libraries that will cause a collision between those two.
Example:
Plugin A wants to use TouchJSON for working with JSON and thus the creator adds the TouchJSON code to the plugin source and it gets compiled and linked into the plugin binary. Later Plugin B also wants to use that same library and does exactly the same. Now when my app loads these two different plugins it detects this and spits out an warning like this:
Class CJSONScanner is implemented in
both [path_to_plugin_a] and
[path_to_plugin_b]. One of the two
will be used. Which one is undefined.
Since my app just loads plugins and makes sure they conform to a certain protocol I have no control over which plugins are loaded and if two or more use the same library.
As long as both plugins use the exact same version of the library this will probably work but as soon as the API changes in one plugin a bunch of problems will arise.
Is there anything I can do about this?
The bundle loading system provides no mean to pacifically resolve name conflicts. In fact, we're told to ensure ourselves that the problem doesn't happen, rather than what to do if it happens. (Obviously, in your case, that's not possible).
You could file a bug report with this issue.
If this is absolutely critical to your application, you may want to have bundles live in separate processes and use some kind of IPC, possibly NSDistantObject, to pass the data from your program to the plugin hosts. However, I'm fairly sure this is a bag of hurt, so if you don't have very clearly-defined interfaces that allow for distribution into different processes, it might be quite an undertaking.
In a single-process model, the only way to deal with this is to ensure that the shared code (more precisely, the shared Objective-C classes) is loaded once. There are two ways to do this:
Put the shared code in a framework.
Put the shared code in a loadable bundle, and load the bundle when the plug-in is loaded if the relevant classes aren’t already available (check using NSClassFromString()). The client code would also have to use NSClassFromString() rather than referring to classes directly.
Of course, if you aren’t in control of the plug-ins you can’t enforce either of these schemes. The best you can do is provide appropriate guidelines and possibly infrastructure; for instance, in the second case the loading could be handled by the application, perhaps by specifying a class to check for and the name of an embedded bundle to load if it isn’t available in the plug-in’s Info.plist.

JSF2: Building JSF2 views (whole component trees) at runtime

Currently I'm trying JSF 2.0 and still learning the more advanced features.
JSF2 is comfortable when having to deal with pre-defined views (fixed component trees) whose widgets are completely known at compile time -- of course with the exception of repeating data list/table entries and light dynamic modification of forms via the DataTable "trick" (as I read here, especially under JSF2, can I add JSF components dynamically? and How to create dynamic JSF 1.2 form fields).
Now I'm wondering about the realization of completely dynamic JSF2 component trees, where a web user, for each given content type (e.g. 'Person', 'PersonList' but also 'PersonalManagementPanel'), can choose one from a list of content-type compatible widgets (=JSF custom components).
As result, this user will always see the "Personal Manager Page" rendered with his/her prefered "PersonalManagerPanel", which in turn also renders its nested components ('Person', 'PersonList') with the user's preferred variants.
Obviously, the goal is to get a selectively configurable/customizable JSF Page -- at runtime.
Is this scenario realizable in JSF2? -- How could this be done?
Are there more appropriate Java technologies for this requierement?
-- One possible alternative I'm thinking of is XML plus XSLT.
Thank you very much for your help and suggestions.
Best regards
Martin
You can use something like this:
<ui:include src="#{bean.template}" />
Or if you want more complicated components, you should take a look at the PreRenderViewEvent.
Note that there are issues with both solutions.
http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-770
http://java.net/jira/browse/JAVASERVERFACES-1708
http://java.net/jira/browse/JAVASERVERFACES-2041