This is an automated email from the ASF dual-hosted git repository.

thiagohp pushed a commit to branch feature/requirejs-less
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git


The following commit(s) were added to refs/heads/feature/requirejs-less by this 
push:
     new 273babbcb TAP5-2810: hopefully final ES module import and init fixes
273babbcb is described below

commit 273babbcb70becae67488eab23bbb7cbf782eb00
Author: Thiago H. de Paula Figueiredo <[email protected]>
AuthorDate: Sat Aug 2 00:49:35 2025 -0300

    TAP5-2810: hopefully final ES module import and init fixes
---
 .../internal/services/DocumentLinkerImpl.java      | 18 +++--
 .../internal/services/EsModuleInitsManager.java    | 32 +++++++--
 .../services/ajax/EsModuleInitializationImpl.java  | 11 ++++
 .../services/javascript/EsModuleManagerImpl.java   | 76 +++++-----------------
 .../services/javascript/EsModuleManager.java       | 12 ++--
 .../src/main/typescript/src/t5/core/pageinit.ts    |  8 ++-
 .../ajax/JavaScriptSupportAutofocusTests.groovy    |  2 +-
 .../tapestry5/integration/app1/EsModuleTests.java  |  1 -
 8 files changed, 76 insertions(+), 84 deletions(-)

diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
index fd885ce87..41f8ef1a8 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/DocumentLinkerImpl.java
@@ -24,6 +24,7 @@ import 
org.apache.tapestry5.services.javascript.ModuleConfigurationCallback;
 import org.apache.tapestry5.services.javascript.ModuleManager;
 import org.apache.tapestry5.services.javascript.StylesheetLink;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -38,7 +39,7 @@ public class DocumentLinkerImpl implements DocumentLinker
 
     private final ModuleInitsManager initsManager = new ModuleInitsManager();
     
-    private final EsModuleInitsManager esModulesinitsManager = new 
EsModuleInitsManager();
+    private final EsModuleInitsManager esModulesInitsManager = new 
EsModuleInitsManager();
 
     private final List<ModuleConfigurationCallback> 
moduleConfigurationCallbacks = CollectionFactory.newList();
     
@@ -154,11 +155,11 @@ public class DocumentLinkerImpl implements DocumentLinker
             addElementBefore(head, existingMeta, "meta", "name", "generator", 
"content", tapestryBanner);
         }
         
-        final List<EsModuleInitialization> esModuleInits = 
esModulesinitsManager.getInits();
-        if (isHtmlRoot && !esModuleInits.isEmpty())
+        final List<EsModuleInitialization> imports = 
esModulesInitsManager.getImports();
+        if (isHtmlRoot && !imports.isEmpty())
         {
             esModuleManager.writeImportMap(root.find("head"), 
esModuleConfigurationCallbacks);
-            esModuleManager.writeImports(root, esModuleInits);
+            esModuleManager.writeImports(root, imports);
         }
 
         addScriptElements(root);
@@ -271,14 +272,17 @@ public class DocumentLinkerImpl implements DocumentLinker
                     "src", url);
         }
 
+        // Write the initialization at this point.
         if (requireJsEnabled)
         {
-            // Write the initialization at this point.
             moduleManager.writeInitialization(body, libraryURLs, 
initsManager.getSortedInits());
+            
+            // Libraries were already added in the line above.
+            esModuleManager.writeInitialization(body, Collections.emptyList(), 
esModulesInitsManager.getInitsAsJsonArrays());
         }
         else
         {
-            esModuleManager.writeInitialization(body, libraryURLs);
+            esModuleManager.writeInitialization(body, libraryURLs, 
esModulesInitsManager.getInitsAsJsonArrays());
         }
     }
 
@@ -350,7 +354,7 @@ public class DocumentLinkerImpl implements DocumentLinker
     public void addEsModuleInitialization(EsModuleInitialization 
initialization) 
     {
         assert initialization != null;
-        esModulesinitsManager.add(initialization);
+        esModulesInitsManager.add(initialization);
         hasScriptsOrInitializations = true;
     }
     
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/EsModuleInitsManager.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/EsModuleInitsManager.java
index 96a01f1d0..c79201b5c 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/EsModuleInitsManager.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/EsModuleInitsManager.java
@@ -39,27 +39,39 @@ public class EsModuleInitsManager
 {
     private final Set<String> modules = CollectionFactory.newSet();
     
+    private final List<EsModuleInitialization> imports = 
CollectionFactory.newList();
+    
     private final List<EsModuleInitialization> initializations = 
CollectionFactory.newList();
     
     public void add(EsModuleInitialization initialization)
     {
         assert initialization != null;
 
-        // We ignore a module being added again.
-        final String moduleName = ((EsModuleInitializationImpl) 
initialization).getModuleName();
-        if (!modules.contains(moduleName))
+        // We avoid having the same module being imported more than twice.
+        // Also notice non-pure inits (i.e. ones having a function name or 
+        // both) are added both to the imports, so they can have
+        // <script type="module"> added for them, and to initializations,
+        // the function call will be made by t5/core/pageinit.
+        final EsModuleInitializationImpl init = (EsModuleInitializationImpl) 
initialization;
+        final String moduleName = init.getModuleName();
+        final boolean alreadyPresent = modules.contains(moduleName);
+        if (!init.isPure())
         {
             initializations.add(initialization);
+        }
+        if (!alreadyPresent)
+        {
+            imports.add(initialization);
             modules.add(moduleName);
         }
     }
 
     /**
-     * Returns all previously added inits.
+     * Returns all imports.
      */
-    public List<EsModuleInitialization> getInits()
+    public List<EsModuleInitialization> getImports()
     {
-        return initializations;
+        return imports;
     }
     
     /**
@@ -78,7 +90,13 @@ public class EsModuleInitsManager
                 final JSONArray arguments = initImpl.getArguments();
                 final JSONArray initArray = new JSONArray();
                 
-                initArray.add(initImpl.getModuleName());
+                String moduleName = initImpl.getModuleName();
+                if (initImpl.getFunctionName() != null)
+                {
+                    moduleName = moduleName + ":" + initImpl.getFunctionName();
+                }
+                
+                initArray.add(moduleName);
                 
                 if (arguments != null)
                 {
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/EsModuleInitializationImpl.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/EsModuleInitializationImpl.java
index 1fd947592..663b422f2 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/EsModuleInitializationImpl.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ajax/EsModuleInitializationImpl.java
@@ -76,4 +76,15 @@ public class EsModuleInitializationImpl extends 
BaseInitialization<EsModuleIniti
         return arguments;
     }
     
+    public boolean isPure() 
+    {
+        return functionName == null && arguments == null;
+    }
+
+    @Override
+    public String toString() 
+    {
+        return "ESInit[moduleName=" + moduleName + ", functionName=" + 
functionName + ", arguments=" + arguments + "]";
+    }
+    
 }
\ No newline at end of file
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsModuleManagerImpl.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsModuleManagerImpl.java
index b0f4090d2..9c773cfdd 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsModuleManagerImpl.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/EsModuleManagerImpl.java
@@ -25,7 +25,6 @@ import org.apache.tapestry5.commons.util.AvailableValues;
 import org.apache.tapestry5.commons.util.CollectionFactory;
 import org.apache.tapestry5.commons.util.UnknownValueException;
 import org.apache.tapestry5.dom.Element;
-import org.apache.tapestry5.http.TapestryHttpSymbolConstants;
 import org.apache.tapestry5.internal.InternalConstants;
 import org.apache.tapestry5.internal.services.ajax.EsModuleInitializationImpl;
 import org.apache.tapestry5.internal.services.assets.ResourceChangeTracker;
@@ -48,8 +47,6 @@ import 
org.apache.tapestry5.services.javascript.JavaScriptStack;
 public class EsModuleManagerImpl implements EsModuleManager
 {
 
-    private static final String GENERIC_IMPORTED_VARIABLE = "m";
-
     /**
      * Name of the JSON object property containing the imports in an import 
map.
      */
@@ -58,8 +55,8 @@ public class EsModuleManagerImpl implements EsModuleManager
     private static final String CLASSPATH_ROOT = "META-INF/assets/es-modules/";
 
     private final boolean compactJSON;
-
-    private final boolean productionMode;
+    
+    private final boolean requireJsEnabled;
 
     private final Set<String> extensions;
     
@@ -88,8 +85,8 @@ public class EsModuleManagerImpl implements EsModuleManager
                              StreamableResourceSource streamableResourceSource,
                              @Symbol(SymbolConstants.COMPACT_JSON)
                              boolean compactJSON,
-                             
@Symbol(TapestryHttpSymbolConstants.PRODUCTION_MODE)
-                             boolean productionMode,
+                             @Symbol(SymbolConstants.REQUIRE_JS_ENABLED)
+                             boolean requireJsEnabled,
                              
@Symbol(SymbolConstants.JAVASCRIPT_INFRASTRUCTURE_PROVIDER)
                              String infraProvider,                             
                              ClasspathScanner classpathScanner,
@@ -97,9 +94,9 @@ public class EsModuleManagerImpl implements EsModuleManager
                              @Core JavaScriptStack javaScriptStack)
     {
         this.compactJSON = compactJSON;
+        this.requireJsEnabled = requireJsEnabled;
         this.assetSource = assetSource;
         this.classpathScanner = classpathScanner;
-        this.productionMode = productionMode;
         this.resourceChangeTracker = resourceChangeTracker;
         this.infraProvider = infraProvider;
         
@@ -217,8 +214,6 @@ public class EsModuleManagerImpl implements EsModuleManager
         Element head = null;
         ImportPlacement placement;
         EsModuleInitializationImpl init;
-        String functionName;
-        JSONArray arguments;
         
         List<EsModuleInitialization> allInits = new 
ArrayList<>(coreStackInits.size() + inits.size());
         allInits.addAll(coreStackInits);
@@ -229,6 +224,7 @@ public class EsModuleManagerImpl implements EsModuleManager
             
             init = (EsModuleInitializationImpl) i;
             final String moduleId = init.getModuleName();
+            
             // Making sure the user doesn't shoot their own foot
             final String url = cache.get(moduleId);
             if (url == null)
@@ -266,65 +262,23 @@ public class EsModuleManagerImpl implements 
EsModuleManager
             
             writeAttributes(script, init);
             script.attribute("src", url);
-            
-            functionName = init.getFunctionName();
-            arguments = init.getArguments();
-            
-            if (!productionMode)
-            {
-                script.attribute("data-module-id", moduleId);
-                final Element log = script.element("script", "type", 
"text/javascript");
-                log.text(String.format("console.debug('Imported ES module 
%s');", moduleId));
-                log.moveBefore(script);
-            }
-            
-            // If we have not only the import, but also an automatic function 
call
-            if (arguments != null || functionName != null)
-            {
-                
-                // TODO: move this logic to a pageinit call, like AMD does
-                // t5/core/pageinit:loadLibrariesAndInitialize
-                final Element moduleFunctionCall = script.element("script");
-                
-                moduleFunctionCall.moveAfter(script);
-                
-                final String moduleFunctionCallFormat = 
-                        "import m from '%s';\n"
-                        + "import console from 't5/core/console';\n"
-                        + "\nif (console.debugEnabled) {"
-                        + "\n    console.debug('Invoking %1$s:%2$s(' + 
(Array.from(%4$s).map(function(arg) { return JSON.stringify(arg); })).join(\", 
\") + ')');"
-                        + "\n    m.%2$s(%3$s);" 
-                        + "\n}\n";
-                
-                
moduleFunctionCall.text(String.format(moduleFunctionCallFormat, 
-                        moduleId, 
-                        functionName,
-                        convertToJsFunctionParameters(arguments, compactJSON),
-                        arguments));
-                
-                writeAttributes(moduleFunctionCall, init);
-                
-                // Avoiding duplicated ids
-                final String id = moduleFunctionCall.getAttribute("id");
-                if (id != null)
-                {
-                    moduleFunctionCall.forceAttributes("id", id + 
"-function-call");
-                }
-                
-            }
+            script.attribute("data-module-id", moduleId);
             
         }
         
     }
     
     @Override
-    public void writeInitialization(Element body, List<String> libraryURLs) 
+    public void writeInitialization(Element body, List<String> libraryURLs, 
List<JSONArray> inits)
     {
 
-        Element element = body.element("script", "type", "module");
-
-        element.raw(String.format("import pageinit from 
\"t5/core/pageinit\";\npageinit(%s, []);",
-                convert(libraryURLs)));
+        if (!requireJsEnabled || !libraryURLs.isEmpty() || !inits.isEmpty())
+        {
+            Element element = body.element("script", "type", "module");
+    
+            element.raw(String.format("import pageinit from 
\"t5/core/pageinit\";\npageinit(%s, %s);",
+                    convert(libraryURLs), convert(inits)));
+        }
     }
     
     private String convert(List<?> input)
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleManager.java
 
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleManager.java
index cc57b47fe..0d97c0024 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleManager.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/services/javascript/EsModuleManager.java
@@ -16,6 +16,7 @@ import java.util.List;
 
 import org.apache.tapestry5.dom.Element;
 import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
+import org.apache.tapestry5.json.JSONArray;
 import 
org.apache.tapestry5.services.javascript.EsModuleManager.EsModuleManagerContribution;
 
 /**
@@ -50,10 +51,10 @@ public interface EsModuleManager
      *
      * @param root
      *         {@code <root>} element of the page.
-     * @param inits
-     *         specify initialization on the page, based on loading modules, 
extacting functions from modules, and invoking those functions
+     * @param imports
+     *         imported modules as {@linkplain EsModuleInitialization} 
instances.
      */
-    void writeImports(Element root, List<EsModuleInitialization> inits);
+    void writeImports(Element root, List<EsModuleInitialization> imports);
     
 
     /**
@@ -64,9 +65,10 @@ public interface EsModuleManager
      *
      * @param body {@code body} element of the page.
      * @param libraryURLs URLs of the JS files to be included in the page.
-     *          
+     * @param inits a list of {@linkplain} JSONArray} instances containing the 
+     * module initializations.
      */
-    void writeInitialization(Element body, List<String> libraryURLs);
+    void writeInitialization(Element body, List<String> libraryURLs, 
List<JSONArray> inits);
     
     /**
      * Encapsulates a contribution to {@linkplain EsModuleManager}.
diff --git a/tapestry-core/src/main/typescript/src/t5/core/pageinit.ts 
b/tapestry-core/src/main/typescript/src/t5/core/pageinit.ts
index 85d13124c..134bce505 100644
--- a/tapestry-core/src/main/typescript/src/t5/core/pageinit.ts
+++ b/tapestry-core/src/main/typescript/src/t5/core/pageinit.ts
@@ -35,7 +35,7 @@ const isOpera = Object.prototype.toString.call(window.opera) 
=== '[object Opera]
 // @ts-ignore
 const isIE = !!window.attachEvent && !isOpera;
 
-const requireJsEnabled = "true" == 
document.querySelector("body")?.dataset['requireJsEnabled'];
+const requireJsEnabled = "true" == 
document.querySelector("html")?.dataset['requireJsEnabled'];
 
 const rebuildURL = function(path: string) {
   if (path.match(/^https?:/)) { return path; }
@@ -113,6 +113,10 @@ const invokeInitializer = function(tracker: () => any, 
qualifiedName: string, in
 
   function executeInitializer(moduleLib: any) {
 
+    if (!requireJsEnabled && moduleLib['default'] != null && 
_.isFunction(moduleLib['default'])) {
+      moduleLib = moduleLib['default'];
+    }
+
     try {
       // Some modules export nothing but do some full-page initialization, 
such as adding
       // event handlers to the body.
@@ -167,7 +171,7 @@ const invokeInitializer = function(tracker: () => any, 
qualifiedName: string, in
   } else {
 
     return import(moduleName).then(function(moduleLib: any) {
-      return executeInitializer(moduleLib['default']);
+      return executeInitializer(moduleLib);
     });
 
   }
diff --git 
a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportAutofocusTests.groovy
 
b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportAutofocusTests.groovy
index c631d4448..7caf1b90d 100644
--- 
a/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportAutofocusTests.groovy
+++ 
b/tapestry-core/src/test/groovy/org/apache/tapestry5/internal/services/ajax/JavaScriptSupportAutofocusTests.groovy
@@ -42,7 +42,7 @@ class JavaScriptSupportAutofocusTests extends 
InternalBaseTestCase {
         replay()
 
         // Test in partial mode, to bypass the logic about importing the 
"core' stack.
-        def jss = new JavaScriptSupportImpl(linker, stackSource, 
stackPathConstructor, null, true, null)
+        def jss = new JavaScriptSupportImpl(linker, stackSource, 
stackPathConstructor, null, true, null, true)
 
         cls jss
 
diff --git 
a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/EsModuleTests.java
 
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/EsModuleTests.java
index d2ba735ee..26e85f508 100644
--- 
a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/EsModuleTests.java
+++ 
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/EsModuleTests.java
@@ -30,7 +30,6 @@ import 
org.apache.tapestry5.services.javascript.EsModuleConfigurationCallback;
 import org.apache.tapestry5.services.javascript.EsModuleInitialization;
 import org.apache.tapestry5.services.javascript.EsModuleManager;
 import org.apache.tapestry5.services.javascript.JavaScriptSupport;
-import org.openqa.selenium.support.ui.ExpectedCondition;
 import org.testng.annotations.Test;
 
 /**

Reply via email to