yuchi / frontend-ng-loader-workspace

Liferay Workspace for experiments in bringing SystemJS and packages support to Liferay Portal
5 stars 2 forks source link

Request: can you provide a simple and working example-portlet for react or angular? #13

Closed marc0olo closed 7 years ago

marc0olo commented 7 years ago

Well the README-Guide seems not really be up to date.

When I followed the steps descripted in issue #1 I was really happy to see ANY output in Liferay and for just one moment my example seemed to work.

Sadly the portlet didn't show the output I wanted to see. The browser console doesn't output any errors, but when I look in the system.out of Liferay I see the following lines:

00:32:51,448 ERROR [http-nio-8080-exec-4][LiferayPortlet:482] Disabling paths for portlet react_portlet_portlet_ReactPortlet because root path is configured to have access to all portal paths
00:32:51,451 ERROR [http-nio-8080-exec-4][MVCPortlet:551] null is not a valid include
00:32:54,915 ERROR [http-nio-8080-exec-6][MVCPortlet:551] null is not a valid include
00:32:55,158 ERROR [http-nio-8080-exec-5][MVCPortlet:551] null is not a valid include
00:32:55,418 ERROR [http-nio-8080-exec-8][MVCPortlet:551] null is not a valid include

Do you have any ideas what is happening here?

yuchi commented 7 years ago

This has actually nothing to do with this loader. How are you building and developing your portlet (-web) bundle?

marc0olo commented 7 years ago

You are definitely right! ... I made to many and different attempts to get this working. After cleaning up my project I got it finally working - almost! :(

The only thing that is still failing, is when I try to render a "normal" output in react. This is the console-output of the browser:

Uncaught (in promise) Error: (SystemJS) SyntaxError: Unexpected token <
        at eval (<anonymous>)
        at Object.eval (http://localhost:8080/o/pkg/react-module/1.0.0/~/index.js:7:17)
        at eval (http://localhost:8080/o/pkg/react-module/1.0.0/~/index.js:25:4)
        at eval (http://localhost:8080/o/pkg/react-module/1.0.0/~/index.js:26:3)
    Evaluating http://localhost:8080/o/pkg/react-module/1.0.0/~/component.js
    Evaluating http://localhost:8080/o/pkg/react-module/1.0.0/~/index.js
    Error loading http://localhost:8080/o/pkg/react-module/1.0.0/~/index.js

Failure

If there is function in the js-file declared which returns the character "<", then I get the error above:

// component.js
var React = require('react');
var ReactDOM = require('react-dom');

class Component extends React.Component {
    render() {
        return <div>Hello {this.props.name}</div>;
    }
};

module.exports = Component;
// index.js
var React = require('react');
var ReactDOM = require('react-dom');
var Component = require('./component');

function render(config, wrapper) {
    return ReactDOM.render(
        React.createElement(Component, config),
        document.getElementById(wrapper));
}

module.exports = {render: render};
// view.jsp
<%@ include file="/init.jsp" %>

<div id="<portlet:namespace />wrapper"> </div>

<script>
window.process = { env: {} };
System
    .import('react-module/1.0.0')
    .then(function (MyModule) {
        MyModule.render({name: 'react-portlet'},'<portlet:namespace />wrapper');
    });
</script>

Success

When I create an element with React which only includes a String with 'Hello, World' and without a special character the output in the portlet works es expected:

// index.js
var React = require('react');
var ReactDOM = require('react-dom');

function render(wrapper) {
    return ReactDOM.render(
        React.createElement('div', null, 'Hello, World!'),
        document.getElementById(wrapper)
    );
}
module.exports = {render: render};
// view.jsp
<%@ include file="/init.jsp" %>

<div id="<portlet:namespace />wrapper"> </div>

<script>
window.process = { env: {} };
System
    .import('react-module/1.0.0')
    .then(function (MyModule) {
        MyModule.render('<portlet:namespace />wrapper');
    });
</script>

Can you help me to get this thing working? Maybe I'm just doing something wrong ...

yuchi commented 7 years ago

You are doing great! The only problem is with JSX syntax which is not supported by browsers. You'll need to use the React.createElement currently, mostly because I had no time to build an alternative transpilation process that doesn't builds AMD modules (which is what Liferay does).

yuchi commented 7 years ago

You also need to know that using JSX (that xml-like stuff) is completely optional for React development, even if it's very useful.

In the final form of this experiment this will not be an issue at all.

marc0olo commented 7 years ago

Well ok, my problem is a bit that I'm new to this javascript-stuff (npm., systemjs, loader x,y,z, ...)

Where am I using JSX in my above failure-example? I adapted this example 1:1 as described in #1 and it crashes. As you can see above I also use React.createElement in the failure-example.

So when this is actually the expected behaviour as you said, is it in general possible to create React-Components right now? I don't see any chance to do this when my failure-example doesn't work.

Off-Topic

yuchi commented 7 years ago

Well ok, my problem is a bit that I'm new to this javascript-stuff (npm., systemjs, loader x,y,z, ...)

This is great, and the perfect audience for this project.

Where am I using JSX in my above failure-example? I adapted this example 1:1 as described in #1 and it crashes. As you can see above I also use React.createElement in the failure-example.

When you develop with React you’ll need to manually define the HTML of you components inside your JS code. To do so React exposes a React.createElement function that you can use to do so.

Since you’ll have hundreds of those in your code they provided from the start an easier (and more readable) way to do so, namely JSX where “X” stands for “eXtended” and “XML”.

When you write <div>Hi</div> it is rewritten by a compile-time script in React.createElement('div', null, 'Hi'). You don’t have that compile-time process in place, therefore your JSX is outputted in the final code and served to the browser. JSX is not supported by the browser.

In your example the file component.js had one occurrence of JSX. That was the only problem in your code.

So when this is actually the expected behaviour as you said, is it in general possible to create React-Components right now? I don't see any chance to do this when my failure-example doesn't work.

As I said before everything works, except from not having compile time processes in place. We still have to flesh it out correctly.

Really great project, keep up this work! ;-)

Thank you!!!

Is or will it be also possible to create angular apps using the frontend-packages-bundle-config-extender? (I didn't try yet but I think you can answer this pretty quick :)

The only problem is that you wont be able to use TypeScript because that requires a compile-time process as well. For the rest it should work perfectly. If it doesn’t it’s a bug and please file it as such here!

you can mark this issue as 'question' since it isn't an issue

Good idea. Done.

thanks for the fast response to my questions!

Glad to be helpful!

yuchi commented 7 years ago

@marc0o- how are your experiments going? any update to share? :)

marc0olo commented 7 years ago

Yes, it is indeed working fine if I use plain javascript. Thanks for the explanation! Sadly I didn't have much time to invest in this topic up to now.


But I have a few other questions about this topic:

yuchi commented 7 years ago

is it possible to use the Liferay Javascript API in this concrete scenario? it would be a pity if not :-( https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/liferay-javascript-apis

Most “vanilla” APIs work out of the box, they are simply available on the global scope. In short, yes you can access themeDisplay.

Sometimes APIs need to be “loaded” on the page. If you need Liferay.PortletURL for example you’ll need to call AUI().use('liferay-portlet-url', …). For modules that are in the AUI format I’ll attach here an example code that provides them as Promises. For Liferay AMD Loader modules there a little more to be done—but this project doesn’t expect to be working side-by-side with the AMD Loader.

function loadAUI() {
    var args = Array.prototype.slice.call(arguments);

    return new Promise(function (resolve, reject) {
        AUI().use(args, function (A, status) {
            if (status && status.success) {
                resolve(A);
            }
            else {
                reject(status);
            }
        });
    });
}

what is the intention of the frontend-packages-bundle-config-extender compared to the possibilities Liferay provides?

This project is a Proof of Concept of a new Loader implemented in Liferay. Potentially this would replace the original implementation.

In Liferay there are few missing features that we believe are critical for front-end developers:

By using SystemJS (or a loader with similar features) and by integrating it with the whole front-end architecture (SCSS file resolution, FTL import resolution…) we get a very solid infrastructure which

when do you think you will be able to provide an alternative transpilation process that will make it possible to write compile-time scripts?

Well you could already do it as they do it at step 4 here. The issue is to have a super simple way to do it (a Gradle plugin for example).


is it possible to use compile-time scripts with liferay-amd-loader?

Could you elaborate a little bit more?


what do you think about this approach to use Angular in Liferay? https://gist.github.com/mjbradford89/e0d2175e1742173530966827184f5a21

This is very interesting and exactly in the direction of this project.

When they say…

Multiple instances/portlets using angular will break. I think this can be resolve by importing angular outside of the portlet, and bootstrapping Angular applications as they become available […]

they are referring to the fact that in the JSP they have to place a <script …>.

This project solves also that.

marc0olo commented 7 years ago

Thanks again for the detailed answer! And forget about my questions about the "compile-time"-stuff since I am still a beginner in the js-world :-D

The process described above still requires "manual" work. As you already mentioned there should be a "super simple" way to get this work done fully automatic :-)

yuchi commented 7 years ago

Thank you so much for your time. Can we consider you in if we need some testers later in the development of this?

marc0olo commented 7 years ago

Sure, assuming I have the time to test it!

Again 3 questions: