sap.ui.define y carga asíncrona: el fin de las variables globales en UI5
AMD, dependencias explícitas, async:true y ComponentSupport en lugar de scripts inline. Por qué sap.ui.require sustituye a los globales y cómo esto encaja con la CSP. Con código real de bootstrap.
Por Logali Tech 2 min de lectura
Si abres una app UI5 antigua verás sap.ui.getCore() colgando de una variable global, scripts que se cargan en orden frágil y un onInit que asume que todo ya está en memoria. El modelo moderno de UI5 es asíncrono y modular: cada fichero declara sus dependencias con sap.ui.define, el framework las resuelve y solo entonces ejecuta tu código. Nada de globales, nada de orden implícito.
sap.ui.define: AMD para UI5
sap.ui.define es la implementación AMD de UI5. Recibe un array de rutas de módulos y una función factoría cuyos argumentos son esos módulos ya cargados, en orden. Ese es el contrato.
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/MessageToast",
"sap/ui/model/json/JSONModel"
],
function (Controller, MessageToast, JSONModel) {
"use strict";
return Controller.extend("logaligroup.SAPUI5.controller.App", {
onInit: function () {
this.getView().setModel(new JSONModel({ recipient: { name: "World" } }));
}
});
});
Tres cosas que este patrón te garantiza:
- Dependencias explícitas: lees el array y sabes exactamente de qué depende el fichero. No hay imports ocultos.
- Sin globales:
Controller,MessageToastyJSONModelson parámetros locales. No contaminanwindow. - Orden garantizado: la factoría no corre hasta que los tres módulos están cargados. Se acabaron los “undefined is not a function” por carga fuera de orden.
flowchart TB D["sap.ui.define lista de dependencias"] --> L["Loader async resuelve módulos"] L --> F["Factory function recibe módulos cargados"] F --> R["return del módulo listo para usarse"] BS["Bootstrap async:true"] --> D
El bootstrap: async de verdad
Todo empieza en el index.html. La bandera que marca la diferencia es data-sap-ui-async="true": sin ella, UI5 carga en modo síncrono legacy, bloqueante y desaconsejado.
<script id="sap-ui-bootstrap"
src="resources/sap-ui-core.js"
data-sap-ui-theme="sap_horizon"
data-sap-ui-resourceroots='{"logaligroup.SAPUI5": "./"}'
data-sap-ui-async="true"
data-sap-ui-compatVersion="edge"
data-sap-ui-oninit="module:sap/ui/core/ComponentSupport">
</script>
Fíjate en data-sap-ui-oninit="module:sap/ui/core/ComponentSupport". En lugar de un <script> inline que arranca el componente a mano, delegas el arranque en ComponentSupport. El componente se declara con un atributo en el <body>:
<body class="sapUiBody" id="content">
<div data-sap-ui-component
data-name="logaligroup.SAPUI5"
data-id="container"
data-settings='{"id": "SAPUI5"}'></div>
</body>
Por qué esto es también seguridad
Aquí está el corolario que muchos pasan por alto: la carga sin scripts inline es lo que hace tu app compatible con Content Security Policy (CSP). Una CSP estricta bloquea todo JavaScript embebido en el HTML. Si tu arranque depende de un <script>onInit()</script>, la CSP lo mata; si depende de ComponentSupport y sap.ui.define, no hay código inline que bloquear.
El async no es solo rendimiento. Es lo que permite que la misma app pase un audit de seguridad con CSP estricta sin reescribir el arranque.
Reglas prácticas que aplicamos siempre:
- Todo fichero JS empieza por
sap.ui.define. Nuncasap.ui.getCore()global, nuncajQuery.sap. - Bootstrap con
data-sap-ui-async="true"y arranque víaComponentSupport, no scripts inline. - Si necesitas un módulo dentro de una función (no en la cabecera), usa
sap.ui.require, la variante asíncrona, no la carga síncrona.
El código moderno de UI5 es asíncrono por defecto. No es una opción avanzada: es el mínimo para que tu app sea mantenible y auditable.
¿Te ha resultado útil?
Gracias por tu valoración.
Comentarios
Aún no hay comentarios.