留言板

How to use Dojo with Liferay 7

Zak Thompson,修改在7 年前。

How to use Dojo with Liferay 7

Junior Member 帖子: 70 加入日期: 16-6-13 最近的帖子
Has anyone been able to successfully integrate Dojo into Liferay 7? We were able to get it working fine in 6.2, but when I try to mirror the steps from 6.2 in 7, I'm running into some issues.

The steps I've tried are as follows:

Make a brand new theme, create a templates folder under src, copy and paste the old portal_normal.ftl into the new templates folder, and then modify the head within the portal_normal.ftl to include Dojo:


	<script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js" data-dojo-config="async: true"></script>

	<title>${the_title} - ${company_name}</title>

	<meta content="initial-scale=1.0, width=device-width" name="viewport">
			
	&lt;@liferay_util["include"] page=top_head_include /&gt;


In my view.jsp of a fresh Liferay MVC portlet, I added the following script:
<script type="text/javascript">
	require([
	    'dojo/dom',
	    'dojo/dom-construct'
	], function (dom, domConstruct) {
	    var greetingNode = dom.byId('greeting');
	    domConstruct.place('<em> Dojo!</em>', greetingNode);
	});
</script>


However, after deploying the theme and putting the portlet on the page, I keep getting the following exception thrown:
15:36:38,390 ERROR [http-nio-8080-exec-9][ComboServlet:89] java.lang.IllegalArgumentException: Path dojo/dom.js does not start with a "/" character
java.lang.IllegalArgumentException: Path dojo/dom.js does not start with a "/" character
	at org.apache.catalina.core.ApplicationContext.getRequestDispatcher(ApplicationContext.java:454)
	at org.apache.catalina.core.ApplicationContextFacade.getRequestDispatcher(ApplicationContextFacade.java:221)
	at com.liferay.portal.servlet.ComboServlet.getResourceRequestDispatcher(ComboServlet.java:409)
	at com.liferay.portal.servlet.ComboServlet.doService(ComboServlet.java:220)
	at com.liferay.portal.servlet.ComboServlet.service(ComboServlet.java:86)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
        ... (I can copy/paste the full stack trace if needed)


Does anyone know how to solve this exception? It seems like the portlet is treating the dojo script like java code before the render phase, and it is throwing the illegal argument exception for an invalid file path when it reality it is not a file path, but an argument for configuring dojo.

EDIT: Even after removing the dojo CDN from the theme, I still get the exact same error when trying to render the view.jsp, so I'm guessing this issue is related to how the backend is treating the JSP before rendering as opposed to an issue with importing the framework.
Zak Thompson,修改在7 年前。

RE: How to use Dojo with Liferay 7

Junior Member 帖子: 70 加入日期: 16-6-13 最近的帖子
I've been investigating this for a decent amount of time today and I believe the root cause of this issue is Liferay's AMD loader that was added in Liferay 7 as Liferay moves away from YUI. Dojo has its own AMD loader with its own definitions of require and define, and the Liferay AMD loader has its own definitions of require and define, and I believe that these are clashing and preventing dojo from operating properly. Below I'll outline some of the steps I've taken and the results I've observed.

Results from adding <script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"></script> to the header in the portal_normal.ftl:

If I add a console.log(require) in my view.jsp, I get the following output (which is Liferay's require):
{
        var self = this;

        void 0;

        var failureCallback;
        var i;
        var modules;
        var successCallback;

        // Modules can be specified by as an arr…



If I add a console.log(dojo.require), I get the following output:
function (a,c){var b=function(a,c){var b=K(k(a),e.module);if(I.length&amp;&amp;I[0].finish)I[0].finish.push(a);else{if(b.executed)return b.result;c&amp;&amp;(b.result=F);var d=D();S(b);d=D();b.executed!==C&amp;&amp;b.injecte…



I also get the above output if I set window.require = dojo.require, and then try to run the following code:
require([
'dojo/dom',
'dojo/dom-construct'
], function (dom, domConstruct) {
var greetingNode = dom.byId('greeting');
domConstruct.place('<i> Dojo!</i>', greetingNode);
});


Then I get the error:
dojo.js.uncompressed.js:6252 Uncaught TypeError: a.replace is not a function. 


I also get the same error if I run the same function, but instead of require I use dojo.require.

If I don't include the dojo CDN in the header and instead include it in the view JSP, I then get the following error:
dojo.js.uncompressed.js:1879Error: defineAlreadyDefined(…)


Based on the evidence above, I think that there's a fundamental conflict between the two AMD loaders from Liferay and Dojo. Has anyone else experienced this, and if so, how were you able to get Dojo to work in Liferay 7?
thumbnail
Chema Balsas,修改在7 年前。

RE: How to use Dojo with Liferay 7

Regular Member 帖子: 127 加入日期: 13-2-25 最近的帖子
Hey Zak,

I've been taking a look at this, and there is a huge conflict with dojo's loader emoticon

The first issue you were experiencing is simply a misconfiguration issue. Since you were (unknowingly) using our loader and you hadn't configured it to know about the dojo modules, it was requesting files via combo which throws an exception like that.

Configuring the loader can be achieved quite easily. See the attached module and deploy it if you want to try some things out.

However, once you have our loader working, bigger issues pop up. As far as I can tell:
  • Circular dependencies - dojo seems to have lots of them, and our loader doesn't support that
  • AMD extensions - dojo has some extensions we also don't support... such as ./has!dom-addeventlistener?:./aspect


Having seen this, I'd venture it's highly unlikely that you can get both dojo and liferay working together nicely...

The only option I see, is what you tried, null our loader require and define functions and then load dojo. That should get dojo up and running, but I'm not sure about how it will affect anything else using the loader. Maybe the dojo loader can handle it. Most likely it won't emoticon

Sorry I can't bring better news, but I'll keep this in the back burner to see if any solution comes to mind.

If you do come up with any solutions, please let us know!
Zak Thompson,修改在7 年前。

RE: How to use Dojo with Liferay 7

Junior Member 帖子: 70 加入日期: 16-6-13 最近的帖子
Hi Chema,

Thanks for your reply. Based on some of the discussions from this dojo support case, it seems like Dojo does not use a fully AMD compliant loader and has some proprietary API's of their own included.

When I would null out the Liferay loader by reassigning window.require, I would run into javascript errors for broken promises, which makes me think that the Liferay modules will not be able to be loaded by the Dojo loader.

In the portal_normal.ftl, if I remove this line "<@liferay_util["include"] page=top_head_include />" from the head, Dojo will actually work entirely as expected, because the Liferay module loader will never get initialized. However, this results in a massively broken page , as no CSS loads, image icons are not resized, and there are a host of errors in the javascript console from other things breaking.

Based on all the evidence gathered thus far I would have to say it doesn't appear that there is a way to get Dojo and Liferay 7 working nicely together.

Thank you for spending time looking into the issue Chema.
Zak Thompson,修改在7 年前。

RE: How to use Dojo with Liferay 7

Junior Member 帖子: 70 加入日期: 16-6-13 最近的帖子
Hi Chema,

Could you give a quick rundown of what the example module provided is doing, and what steps need to be implemented in general to import a module via the Liferay AMD loader? I'm seeing that there's the config file, the package.json, the bnd.bnd and the build.gradle, and I'm not entirely sure what to put in each one to import a module in the general case.

Thanks,
Zak
thumbnail
Chema Balsas,修改在7 年前。

RE: How to use Dojo with Liferay 7

Regular Member 帖子: 127 加入日期: 13-2-25 最近的帖子
Hi Zak,

Thanks for the dojo support case reference! We'll keep an eye on this to see if we can come up with something, but as you say, it isn't straightforward right now emoticon

The general steps to use modules are described in these tutorials

If you have some amd modules, what you need is to inform our loader of where they are. This can be done using our Module Config Generator (this is what our configJSModules build task does). What this program does is:
  • Scan a source tree looking for amd modules (define(...))
  • Name those modules if they aren't already
  • Collect the module definitions and their dependencies
  • Generate an output (config.json) with all the collected data


This configuration is then provided to the loader on initialization. By default, when you deploy a bundle, if it has both a package.json and a config.json file, the latter will be aggregated with the rest of the loader configuration.

With this in mind, what I did on the attached module was to try to generate a compatible dojo version by:
  • Create the package.json - this automatically triggers some of the build tasks such as the configJSModules and will mark the module as a candidate to have modules configuration
  • Grab and expand the dojo dependency from webjars in the build.gradle
  • Configure the configJSModules task so it goes over the js files in the dojo sources (by default we scan only *.es.js files)
  • Add the Liferay-Export-JS-Submodules: * header in the bnd.bnd file. This instructs liferay to generate aliases for the first level of modules. Usually, to access a module you need to do require('bundleName/module/path'.... With this header, that module will also be available when doing require('module/path'.... This allows for require('dojo/dom') to work.
  • Finally, if you add a Liferay-JS-Config header, the file you point it to will be automatically loaded after the loaders are ready. With this, you should be able to provide some extra configuration, like calling Loader.addModule.... You can scan the sources to see some usage.


Hope that gives you a good overall picture.

Please, let me know if I can help with anything else!
thumbnail
Chema Balsas,修改在7 年前。

RE: How to use Dojo with Liferay 7

Regular Member 帖子: 127 加入日期: 13-2-25 最近的帖子
Hey Zak,

Based on this and similar feedback, we've decided to try and alleviate this issue. Our current plan is:
  • Add an option to the loader to configure where it gets exported
  • We will always expose and use the loader via the Liferay namespace
  • For backwards compatibility, we'll add a property or configuration com.javascript.loader.global, when true (default), we'll expose the loader methods on the global scope so things will work the same way.
  • If someone has conflicts, they can simply turn off the setting and our loader will remain hidden.


You can follow the discussion about the loader implementation details. Once that's done, you can follow the work to integrate it into Liferay Portal in LPS-68298.

We'll try to get it done as soon as possible. Hope this sheds some hope to your problem!
thumbnail
Salman Khan,修改在7 年前。

RE: How to use Dojo with Liferay 7

New Member 发布: 1 加入日期: 14-8-19 最近的帖子
Hey Zak,

I need this integrated for a client and it really important, I tried steps mentioned with lfr-module-config-generator , but that is not very clear , and I am not able to understand how to use it.
Zak Thompson,修改在7 年前。

RE: How to use Dojo with Liferay 7

Junior Member 帖子: 70 加入日期: 16-6-13 最近的帖子
Salman,

It seems the issue is solved by https://issues.liferay.com/browse/LPS-68298, however, that is currently in review and has not been merged into the portal core. We're currently waiting on this fix as well.
thumbnail
Chema Balsas,修改在7 年前。

RE: How to use Dojo with Liferay 7

Regular Member 帖子: 127 加入日期: 13-2-25 最近的帖子
Hey Zak,

https://issues.liferay.com/browse/LPS-68298 has been merged in master and backported to the maintenance branch, so it should be included in the next GA and fixpack releases.

It is currently in PM review, which just means that we'll discuss the implications with a Product Manager, not that the fix is not there ;)
Zak Thompson,修改在7 年前。

RE: How to use Dojo with Liferay 7

Junior Member 帖子: 70 加入日期: 16-6-13 最近的帖子
Thanks for the clarification Chema, I'm not entirely familiar with Liferay's internal workflow for publishing/code review. Also, thanks for all your work on getting the feature implemented.