Message Boards

How to override JavaScript modules?

Marcin Pawluk, modified 3 Years ago.

How to override JavaScript modules?

New Member Posts: 16 Join Date: 1/22/20 Recent Posts
Hi. Is it possible to override JavaScript modules in the same way or similar like we can do with JSP files? For example I want to modify MapBase class to turn off geolocation. Documentation says only how to override JavaScript in AUI/YUI. I tried to create fragment to override Liferay Map Common module, but still default script is loaded instead of mine. I can't find any information how to solve my case. I'm using Liferay 7.2.1 GA2.
thumbnail
Ivan Zaera, modified 3 Years ago.

RE: How to override JavaScript modules?

Regular Member Posts: 119 Join Date: 10/1/13 Recent Posts
Hi Marcin:
What have you tried exactly? An OSGi fragment bundle to overwrite a certain .js file?
Marcin Pawluk, modified 3 Years ago.

RE: How to override JavaScript modules?

New Member Posts: 16 Join Date: 1/22/20 Recent Posts
Hi Ivan.
Yes, I tried an OSGI fragment to override module https://github.com/liferay/liferay-portal/tree/7.2.1-ga2/modules/apps/map/map-common. I've added files:
  • .npmbridgerrc - with the same content as original file in Liferay's repository
  • .npmbundlerrc - I was testing 
  • package.json - with the same content as original file in Liferay's repository
  • bnd.bnd - with added Fragment-Host: com.liferay.map.common;bundle-version="[4.0.0,5.0.0)"
  • src/main/resources/META-INF/resources/js/ - all files (MapBase.es.js, MarkerBase.es.js, validators.es.js, GeoJSONBase.es.js)
I'm building using npm command. In build directory I've generated all files. Felix shows that fragment works and if I use Web-ContextPath to check file, for example https://localhost:8080/o/map-common/js/MapBase.es.js I see my file. When I create simple structure with Geolocation DDM field and next create Web Content, it uses original file, not my version.
thumbnail
Ivan Zaera, modified 3 Years ago.

RE: How to override JavaScript modules?

Regular Member Posts: 119 Join Date: 10/1/13 Recent Posts
Mmm, then it looks like DDM is not using the https://localhost:8080/o/map-common/js/MapBase.es.js file you are requesting by hand...

I would open the browser dev tools and check the network tab when the DDM geolocation field appears. Then I would inspect each JavaScript file downloaded to see where they are coming from (URL) and what are their contents. It may be several things: a caching issue, another URL being used, ....
Marcin Pawluk, modified 3 Years ago.

RE: How to override JavaScript modules?

New Member Posts: 16 Join Date: 1/22/20 Recent Posts
Hi Ivan. I've checked of course and MapBase.es.js comes from http://localhost:8080/o/js/resolved-module/map-common@4.0.17/js/MapBase.es.js. According to Your article on github https://github.com/liferay/liferay-js-toolkit/wiki/How-Liferay-serves-npm-packages-to-the-browser, resolved module is a like a global module in whole Liferay. Is it possible to override resolved modules?
thumbnail
Ivan Zaera, modified 3 Years ago.

RE: How to override JavaScript modules?

Regular Member Posts: 119 Join Date: 10/1/13 Recent Posts
It should be possible with an OSGi fragment as you are trying. I don't know why it doesn't work...
Every JS file served by the NPMRegistry (the ones downloaded from /o/js/....) are retrieved from the OSGi bundles using the Bundle API (from OSGi) so, as long, as that API returns the fragment file, it should work (see https://github.com/liferay/liferay-portal/blob/02caaf9ddb812523a225b4d6b77450aad11a69e8/modules/apps/frontend-js/frontend-js-loader-modules-extender/src/main/java/com/liferay/frontend/js/loader/modules/extender/internal/npm/flat/FlatJSBundle.java#L65 and https://github.com/liferay/liferay-portal/blob/02caaf9ddb812523a225b4d6b77450aad11a69e8/modules/apps/frontend-js/frontend-js-loader-modules-extender/src/main/java/com/liferay/frontend/js/loader/modules/extender/internal/npm/flat/FlatJSBundle.java#L87).
Maybe you can do a little test in Java: grab the map-common Bundle object from OSGi and ask it for the MapBase.es.js file to see what you get (if the original or the modified file). That could shed some light to the issue...
Marcin Pawluk, modified 3 Years ago.

RE: How to override JavaScript modules?

New Member Posts: 16 Join Date: 1/22/20 Recent Posts
I've made some tests and below are conclusions
I also added two custom files in my fragment
  • test.txt directly inside resources folder (next to js folder)
  • index.es.js inside resources/js/ folder
These files are visible when I use http://localhost:8080/o/js/resolved-module/map-common@4.0.17/js/index.es.js.
I also did a test with grabbing bundle object from OSGi (example code below)

package bundle.module;import java.net.URL;
import org.apache.commons.io.IOUtils;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class BundleModuleActivator implements BundleActivator {
     @Override
    public void start(BundleContext bundleContext) throws Exception {
        try {
            Bundle b = null;
            Bundle[] bundles = bundleContext.getBundles();
            for (Bundle bundle : bundles) { 
                if ("com.liferay.map.common".equals(bundle.getSymbolicName())) {
                    b = bundle;
                }
            }
            
            System.out.println(b.getLocation());
            URL url = b.getResource("/META-INF/resources/js/MapBase.es.js");
            System.out.println("URL: " + url);
            
            System.out.println("URL: " + IOUtils.toString(url));
        } catch (Exception ex) {
            System.err.println(ex.getMessage());
            ex.printStackTrace();
        }
    }
     @Override
    public void stop(BundleContext bundleContext) throws Exception {
    }
​​​​​​​}
It returns original file instead modified. Honestly I've no idea how to override this file. I checked documentation, but it looks like there is no information or example how to do this.
thumbnail
David Gómez, modified 3 Years ago.

RE: How to override JavaScript modules?

New Member Posts: 10 Join Date: 2/26/18 Recent Posts
Hi Marcin,

From your last post, it seems that your fragment is adding its contents (given the fact that your custom files are visible) but not overriding the contents (as  the resolved-module .es.js source code is stil resolved to the original content).
How are you deploying the fragment? Do you have the fragment code accesible in any repository so anyone else could try to repdroduce your scenario?
Marcin Pawluk, modified 3 Years ago.

RE: How to override JavaScript modules?

New Member Posts: 16 Join Date: 1/22/20 Recent Posts
Hi David,
I've created GitHub repository -> https://github.com/mardrof/liferay-js-overriding and added map-common-fragment module. In MapBase.es.js I added alert function in 100 line. As you said, adding works, but overriding not.
Marcin Pawluk, modified 3 Years ago.

RE: How to override JavaScript modules?

New Member Posts: 16 Join Date: 1/22/20 Recent Posts
Could you try to do the same in your local environment?
Patrick Dos Santos, modified 1 Year ago.

RE: How to override JavaScript modules?

New Member Posts: 2 Join Date: 3/29/22 Recent Posts

Hello,

Anyone found a solution to resolve the problem of overring a JS file in a JS module ? I'm facing the same issue in Liferay 7.4...

Its Science, modified 1 Year ago.

RE: How to override JavaScript modules?

New Member Posts: 2 Join Date: 7/20/22 Recent Posts

Perhaps you are confusing the JSP method of of override using OSGI fragments directly for the indrect approach needed to do the same with  javascript modules, which are using strict mode by default. This might help: https://www.surekhatech.com/blog/override-liferay-portal-javascript

​​​​​​​

Muneer Ahmad, modified 1 Year ago.

RE: How to override JavaScript modules?

New Member Post: 1 Join Date: 8/4/22 Recent Posts

You can override any built-in function by just re-declaring it. parseFloat = function(a){ alert(a) }; Now parseFloat(3) will alert 3.

Its Science, modified 1 Year ago.

RE: RE: How to override JavaScript modules?

New Member Posts: 2 Join Date: 7/20/22 Recent Posts

This is only the case if strict mode is not being used. Since the class in question, MapBase is part of an ES module strict mode is the default so only the first declaration will be respected. That is my understanding of it anyways. Some info below

​​​​​​​https://262.ecma-international.org/6.0/#sec-strict-mode-code

thumbnail
David H Nebinger, modified 7 Months ago.

RE: How to override JavaScript modules?

Liferay Legend Posts: 14919 Join Date: 9/2/06 Recent Posts

For clarification purposes and for anyone else who stumbles upon this post in the future...

Liferay does not support overriding a JS file via a fragment bundle.

I don't care what it says above, it simply is not supported.

In vanilla OSGi, a fragment bundle can only add new files to the host bundle, it cannot override files from the host bundle. When accessing a file, OSGi will pick from the host bundle first (if it exists), and only if not found will it go to the fragment bundle.

Liferay does have an override in place exclusively for .jsp and .jspf files so fragment bundles can override these files from the host bundle. But this customization is only for JSP files and does not work for other types of files such as JS files.

There is no supported way to override a JS file in a Liferay module.

You can use the technique documented here: https://liferay.dev/blogs/-/blogs/extending-liferay-osgi-modules-revisited but it is important to point out that this is completely unsupported by Liferay.