liferay / liferay-amd-loader

GNU Lesser General Public License v3.0
18 stars 20 forks source link

Having jQuery loaded as jquery at Liferay startup #82

Closed caneta closed 8 years ago

caneta commented 8 years ago

Hi guys, I'm facing problems with jQuery plugins again, like in #80. I'm trying to get working this carousel plugin, which source code starts with the following function:

(function(factory) {
    'use strict';
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    } else if (typeof exports !== 'undefined') {
        module.exports = factory(require('jquery'));
    } else {
        factory(jQuery);
    }
}

In a Liferay environment, it falls into the first if statement, but the module 'jquery' is not present into the portal and so I get the error that the following script is missing:

<script src="/combo/?browserId=other&amp;minifierType=&amp;languageId=en_US&amp;b=7010&amp;t=1475760284543&amp;jquery.js"></script>

And this is coherent with the Liferay AMD Loader I guess, because the jquery definition in the plugin does not match with the path of jQuery library inside the portal (the everything.jsp file). I solved temporarily changing the first if statement like this:

if (typeof define === 'function' && define.amd && window.Liferay === undefined) {

that is: if I am in a Liferay environment, don't consider the 'jquery' module but go on and fall in the third case (factory(jQuery);)

Since we've got tons of jQuery based plugins out there, I'm searching for a better approach. Is there a way to have loaded jQuery as a module named 'jquery' with the correct Liferay path, satisfying plugins like this one?

Thank you

yuchi commented 8 years ago

You could easily AMDify the provided global jQuery by placing a simple snippet in your project.

To do so create a frontend-js-jquery-amd-provider bundle with the following structure:

frontend-js-jquery-amd-provider/
├── bnd.bnd
├── build.gradle
└── src/
    └── main/
        └── resources/
            └── META-INF/
                └── resources/
                    └── config.js

Where config.js is:

define('jquery', function () {
  return window.jQuery;
});

and bnd.bnd is:

Bundle-Name: jQuery AMD Contributor
Bundle-SymbolicName: my.pkg.frontend.js.jquery.amd.contributor
Bundle-Version: 1.0.0
Liferay-JS-Config: /META-INF/resources/config.js
caneta commented 8 years ago

Thank you @yuchi, your solution worked! I'll share my steps:

  1. Inside my liferay workspace I've created a new bundle

    blade create -t mvcportlet my-pkg-frontend-js-jquery-amd-provider
  2. I've modified the liferayworkspace/modules/my-pkg-frontend-js-jquery-amd-provider tree as you described
  3. I've modified bnd.bnd a little:

    Bundle-Name: My jQuery AMD Provider
    Bundle-SymbolicName: my.pkg.frontend.js.jquery.amd.provider
    Bundle-Version: 1.0.0
    Web-ContextPath: /my-pkg-frontend-js-jquery-amd-provider
    Liferay-JS-Config: /META-INF/resources/config.js
  4. I've deployed it

    ./gradlew :modules:my-pkg-frontend-js-jquery-amd-provider:deploy
  5. Inside my themes/mytheme/js/main.js I've put the following:

    'use strict';
    Loader.addModule({
      name        : 'slick',
      dependencies: ['jquery'],
      path        : '/o/my-theme/components/slick-carousel/slick/slick.min'
    });
    
    require(['slick'],
    function(slick) {
      console.log(jQuery.fn.slick); // It prints the function source
      console.info('It works!');
    },
    function(error) {
      console.error(error);
    }
    );
    }); 
yuchi commented 8 years ago

You can also add a config.js in your theme. Leave the AMDification of jQuery in its own bundle, but move the snippet with Loader.addModule there, with this you'll have a cleaner main.js.

To do so you can leverage the fact that a theme WAR is actually deployed as a bundle, at the of the day. If you add a src/META-INF/MANIFEST.mf file with just the following content:

Liferay-JS-Config: /js/config.js

then it will be treated as other bundles and the config file used at every page request.

;)

caneta commented 8 years ago

I've moved the Loader.addModule function inside my src/config/config.js file and put the line Liferay-JS-Config: /config/config.js inside src/META-INF/MANIFEST.mf, but it didn't work: it searches for a http://localhost:8080slick.js (no slashes after port number), which is incorrect.

But putting Liferay-JS-Config=/config/config.js inside my src/WEB-INF/liferay-plugin-package.properties it worked as expected!

yuchi commented 8 years ago

Great tip!! Didn't know liferay-plugin-package.properties is merged in the manifest!

caneta commented 8 years ago

Hehehe...say thank you to @jbalsas! He gave me this hint on Liferay Forums.