How to treat bootstrap's data-sap-ui-libs vs manifest's sap.ui5/dependencies/libs? - sapui5

I usually declare all standard libraries that the application depends on in the manifest under sap.ui5/dependencies/libs.
Now what should I put in the bootstrap argument data-sap-ui-libs, the same libraries? What are the effects if I put less / more in data-sap-ui-libs? How do they differ?
PS. I couldn't find this in SAP's documentation, but please proof me wrong. :-)

The bootstrapping (data-sap-ui-libs) is done in the index.html. It only needs to contain the libs which are referenced in the index.html.
If your code looks like this:
new sap.m.Shell({
app: new sap.ui.core.ComponentContainer({
name: "my.namespace.app",
height: "100%"
})
}).placeAt("content");
Then you should require the following libs:
data-sap-ui-libs="sap.m, sap.ui.core"
If your code looks like this:
sap.ui.require([
"sap/m/Shell",
"sap/ui/core/ComponentContainer"
], function(Shell, ComponentContainer) {
new Shell({
app: new ComponentContainer({
name: "my.namespace.app",
height: "100%"
})
}).placeAt("content");
});
You don't need to require anything (but it may affect loading time of your app).
All libraries that are used in the views should be required in the manifest.json. So if you use sap.m in your app you should require it in your manifest.json, even if you've already required it in the index.html.
This is because the Component.js and the manifest.json are the default entry points for an app and the index.html ist just a wrapper for standalone apps outside of a Fiori Launchpad.

What are the effects if I put less/more in data-sap-ui-libs? How do they differ?
My recommendation is to remove data-sap-ui-libs from index.html altogether. Especially if the app is dealing with OData, it's important to retrieve the $metadata document as early as possible. See the example below:
In index.html
<head>
<script id="sap-ui-bootstrap"
src="https://ui5.sap.com/<version>/resources/sap-ui-core.js"
data-sap-ui-theme="sap_horizon"
data-sap-ui-oninit="module:sap/ui/core/ComponentSupport"
data-sap-ui-async="true"
data-sap-ui-compatversion="edge"
data-sap-ui-excludejquerycompat="true"
data-sap-ui-resourceroots='{ "demo": "./" }'
data-sap-ui-xx-waitfortheme="init"
></script><!-- No data-sap-ui-lib -->
</head>
<body id="content" class="sapUiBody">
<div style="height: 100%"
data-sap-ui-component
data-name="demo"
data-height="100%"
></div>
</body>
In manifest.json
{
"sap.app": {
"dataSources": {
"myODataSource": {
"uri": "/odata_org/V2/Northwind/Northwind.svc/",
"type": "OData",
"settings": {
"odataVersion": "2.0",
"localUri": "model/metadata.xml",
"annotations": [
"annotation0"
]
}
},
"annotation0": {
"type": "ODataAnnotation",
"uri": "annotation/annotation0.xml",
"settings": {
"localUri": "annotation/annotation0.xml"
}
}
},
"...": "..."
},
"sap.ui5": {
"dependencies": {
"minUI5Version": "1.108.4",
"libs": {
"sap.ui.core": {},
"sap.m": {},
"sap.ui.table": {},
"sap.ui.unified": {}
}
},
"models": {
"": {
"dataSource": "myODataSource",
"settings": {
"preliminaryContext": true,
"tokenHandling": false
},
"preload": true
}
},
"...": "..."
},
"...": "..."
}
Result
As you can see, the $metadata document is being fetched in parallel with the control libraries. This ensures that entities can be requested right away (e.g. in $batch) as soon as the libs are loaded. If libs were declared in data-sap-ui-libs, they'd be loading first, then the $metadata, and then the entities which creates an unnecessary bottleneck.
But even without considering OData, I noticed the page gets already a bit faster when the libs are removed from data-sap-ui-libs. In general, try different approaches and do performance measurements, in addition to documented performance guidelines, and regardless of what people say (including me).
TL;DR
Use data-sap-ui-libs only if:
The app has no Component.js at all.
Modules from libraries other than sap.ui.core are accessed before creating the component (E.g. instantiating sap.m.Shell as a shell for the ComponentContainer)
Otherwise, remove data-sap-ui-libs altogether and maintain /sap.ui5/dependencies/libs only - Especially if the app is supposed to be launched from an app container such as SAP Fiori launchpad (FLP) which skips loading index.html altogether.
See also What happens if a library preload file / library dependencies is not updated in the UI5-manifest?

I would kept them declared on the manifest.
By declaring them on your .html file under the data-sap-ui-libs, you are basically requiring those dependencies right after the UI5 lib is loaded - even before your component is loaded.
By declaring them on your manifest, you are declaring the dependencies for your own component. So, those dependencies are only loaded before the initialization of your component.
As the component should be isolated, you component should not expect to be always used in a standalone mode.

Related

How to pass options to babel plugin transform-modules-commonjs?

I create a Vue 2 project by Vue-Cli 5, then I want to remove "use strick" in the complied code.
As I Know, the #babel/plugin-transform-strick-mode may be enabled via #babel/plugin-transform-modules-commonjs, and the plugin is included in #babel/preset-env under the modules option.
But the Vue-Cli used a preset #vue/babel-preset-app by a plugin #vue/cli-plugin-babel for babel.
So my question is How pass strictMode: false as an option to the transform-modules-commonjs by #vue/babel-preset-app which preset is in the #vue/cli-plugin-babel ?
module.exports = {
presets: [["#vue/cli-plugin-babel/preset", { modules: "auto" }]],
plugins: [
// I tried this way, but it throw many errors like:
/**
ERROR in ./node_modules/axios/dist/node/axios.cjs 11:15-32
Module not found: Error: Can't resolve 'stream' in 'D:\workspace\cqset_offical_website\node_modules\axios\dist\node'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "stream": require.resolve("stream-browserify") }'
- install 'stream-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "stream": false }
*/
["#babel/plugin-transform-modules-commonjs", {}],
[
"component",
{
libraryName: "element-ui",
styleLibraryName: "theme-chalk",
},
],
],
};

How to add babel and polyfills to a RequireJs project?

I am working on a legacy project which uses RequireJs to load and resolve all the dependencies. It works fine on modern browsers, but i need to add support for IE11.
I tried to use babel 7 with #babel/preset-env with following .babelrc
{
"presets": [
["#babel/preset-env", {
"useBuiltIns": "usage",
"corejs": 3,
"targets": {
"browsers" : ["ie>=11"]
},
"modules": false
}]
],
"compact": false
}
the import statements injected by the preset as following
import "core-js/modules/es.function.name.js";
cause error "import statements can't be used outside a module". Even when I use modules: "amd", then core-js is imported as
define(["core-js/modules/es.array.filter.js", "core-js/modules/es.object.to-string.js", "core-js/modules/es.string.includes.js", "core-js/modules/es.function.name.js", "core-js/modules/es.regexp.exec.js", "core-js/modules/es.string.split.js", "core-js/modules/es.string.small.js", "core-js/modules/es.string.search.js"], function (_esArrayFilter, _esObjectToString, _esStringIncludes, _esFunctionName, _esRegexpExec, _esStringSplit, _esStringSmall, _esStringSearch) {
"use strict";
//...
});
which throws error like "define is not defined in require.js".
When using useBuiltIns: "entry", and then including core-js as
require(["core-js", ../other modules], function(corejs, ...){
}
)
in the main.js file, it fails to correctly resolve the path of the files even though I have included the path to core-js in require.config.paths.
I tried #babel/runtime and #babel/plugin-transform-runtime but no luck there.
So my question is what would be the best way to add babel and the required polyfills in my RequireJs project so that it is compatible with IE 11?

Javascript in nuxt plugins folder - how to use in component?

I have a javascript variable (var testButton) in my Nuxt plugins folder. I then added the file to my nuxt.config.js plugins. In my component, I have a Buefy button, and I'm trying to call the script:
<b-button #click="testButton">Click Me</b-button>
...
<script>
export default {
mounted () {
this.$testButton()
}
}
</script>
I import the script in my script section and have tried computed and mounted lifecycles. Not sure what I'm doing wrong. Thank you
Check the following things, you must be missing one or more:
1. Your plugin should export a method. That method should receive an 'inject' function and use it to register your 'testButton' function.
So, in your ~/plugins/testButton.js
export default (context, inject) => {
inject('testButton', () => {
console.log('testButton works!')
})
}
2. You shuold register your plugin correctly in the nuxt.conf.js file
Do it like so:
plugins: [
{ src: '~/plugins/testButton.js' },
],
3. Call it as '$testButton()' (note that Nuxt will have added a dollar sign to your method's name).
Your '$testButton' method will now be available from anywhere in your nuxt app. You don't have to import it o create any computed property.
<b-button #click="$testButton">Click Me</b-button>
<script>
export default {
}
</script>

Flexible content modules in Silverstripe

We are looking at using Silverstripe CMS and want to be able to have modules which can be reordered.
We have come from a Wordpress setup and mostly use the flexible content ACF field. Modules (e.g. text, masthead or video) need to be able to be re-ordered.
We use our CMS's as an API so these modules are output as a section to the page or post:
[
{
"id": 10,
"title": "Post title",
"slug": "post_slug",
"path": "/post_slug",
"template": "campaign",
"published": "2017-05-25 06:09:36",
"image": null,
"seo": {
"title": "",
"description": "",
"image": {
},
},
"sections": [
{
"type": "masthead",
"Title": "",
"video": false,
"image": [
],
"showCta": false,
"cta": [
]
},
{
"type": "video_text",
"video_text": [
{
"type": "video",
"video_url": "https://www.youtube.com/watch?v=asdfa",
"video_length": "07:38",
"video_preview": false
},
{
"type": "text",
"title": "Video Title",
"content": "Video text content",
"call_to_action": false,
"cta": [
]
}
]
},
{
"type": "text",
"title": "Text Title",
"content": "",
"alignment": "centre",
"call_to_action": false,
"cta": {
"text": "CTA button",
"link_type": "internal_link",
"internal_link": "about",
"external_link": "",
"section_id": [
]
}
},
]
}
]
Does Silverstripe have it's own way of handling modules / do I need to ditch this flexible content modules method? How do others handle flexible content modules in Silverstripe?
Both silverstripe-blocks and silverstripe-elemental works very well in their own regard but I don't think they will achieve what you want. These modules don't really give you the power to use pre-defined templates. You can hook the templates in but the code will be massive. I not sure if there is an open source module for that yet.
From your JSON code, in order to have those Sections to render something like this below;
<section id="Sections">
<div id="video_text" class="section">
<iframe width="560" height="315" src="https://www.youtube.com/watch?v=asdfa" frameborder="0" allowfullscreen></iframe>
</section>
<div id="text" class="section">
<h2>Text Title</h2>
<a class='text-center btn btn-default' href="/about/">CTA button</a>
</section>
</sections>
You might want to do this.
Use DataObjects (DO) for you Sections, easy for re-ordering.
Create an abstract DO, BlockSection, with fields like Title(Varchar), Content(HTMLText), Sort(Int) and most importantly has_one to Page.
For the video use can name the DO VideoBlockSection and it extends BlockSection,
TextBlockSection for the other one. Don't forget the $singular_name for each DO (useful for nice class naming in the Grid)
On Page getCMSFields add the Grid to manage the Sections. You need to add GridFieldSortableRows and GridFieldAddNewMultiClass and now you can add you Section on each Page.
Add has_many from Page to BlockSection and a method that will render the Blocks and outputs the html.
Page.php
private static $has_many = array(
"Sections" => "BlockSection",
);
function SectionContent()
$aContent = ArrayList::create();
$oSections = $this->Sections();
if (count($oSections )) {
foreach ( $oSections as $oSection ) {
$aContent->push(ArrayData::create([
"Section" => $oSection,
"Content" => $oSection->renderWith([$oSection->ClassName, get_parent_class($oSection)]),
]));
}
}
return $aContent;
For the VideoBlockSection the template array list will be VideoBlockSection and BlockSection
VideoBlockSection.ss
<div id="video_text_{$ID}" class="section">
<iframe width="560" height="315" src="{$URL}" frameborder="0" allowfullscreen></iframe>
</section>
In you specific case, because you are using an API you need to use a wrapper to render the Template.
It needs to match [section][type] to a Template (renderWith) video_text to VideoBlockSection
Lastly in Page.ss
<% loop $SectionContent %>
{$Content}
<% end_loop %>
This was a proof of concept but its working for me so refactoring, speed and memory usage was not considered (but its working).
This way I had to ditch the unnecessary so called "page types" which I find not to be reusable in most cases.
This works 100% for me and I use it together with Bootstrap 3. I use it to create CTAs, parallax scroll, Google Map Section (multiple maps on one page), Thumbnails. Specify image resize method (Cropped, ByWidth, ByHeight).
DO NOT ditch that flexible content modules method.
I am working on an open source module which works with SS4 and Bootstrap 4 (with possibilities of using any other html framework)

How to get aurelia-cli and Syncfusion non aurelia-syncfusion-bridge to work?

Windows 7 x64
aurelia-cli 0.23.0
syncfusion 14.4.20
jquery 3.1.1
I saw the other question regarding this but it doesn't seem to follow the bootstrap example. I believe Syncfusion should also be setup using the bootstrap example as a template but I cannot seem to get it to work.
My test project is just a new aurelia-cli project with default settings.
I am using the ejDatePicker control as an example.
aurelia.json I added
{
"name": "jsrender",
"path": "../node_modules/jsrender",
"main": "jsrender",
"deps": ["jquery"],
"exports": "$"
},
{
"name": "syncfusion",
"path": "../node_modules/syncfusion-javascript",
"main": "/Scripts/ej/web/ej.web.all.min",
"deps": ["jquery", "jsrender"],
"exports": "$",
"resources": [
"Content/ej/web/ej.widgets.core.min.css",
"Content/ej/web/bootstrap-theme/ej.theme.min.css"
]
}
app.html
<template>
<require from="syncfusion/Content/ej/web/ej.widgets.core.min.css"></require>
<require from="syncfusion/Content/ej/web/bootstrap-theme/ej.theme.min.css"></require>
<!--Container for ejDatePicker widget-->
<input id="startDate" type="text" />
</template>
app.js
export class App {
constructor(){
$("#startDate").ejDatePicker();
}
}
main.js
import 'jquery';
import 'jsrender'
import 'syncfusion'
......
I am not getting any errors but the control is not displaying. However if I remove the suncfusion config from aurelia.json then $("#startDate").ejDatePicker(); complains that ejDatePicker is not valid so to me that means that the config in aurelia.json is pulling in the correct javascript file.
I had the $("#startDate").ejDatePicker(); in the constructor instead of attached(). It is working after I made that change.