How to use React front-end for Page in ERPNext

Hi there,

I was trying to using React framework for designing a Page in ERPNext.

I found online resource like tutorial-adding-node-modules-to-frappe which should be pretty similar to what I would like to achive.

Hence my steps below:

  1. In my custom app, npm init and npm i react, react-dom
  2. Create symbolic link by ln -s node_modules/ {my_custom_app}/public/node_modules
  3. Create a build.json in {my_custom_app}/public/build.json
    { "js/react_bundle.js": [ "node_modules/object-assign/index.js", "node_modules/react/umd/react.development.js", "node_modules/react-dom/umd/react-dom.development.js" ] }
  4. In custom app hook.py file, add the ‘react_bundle.js’ to the app_include_js
    app_include_js = [ "/assets/{my_custom_app}/js/react_bundle.js", ]
  5. On bench folder, run bench build --app {my_custom_app}

But the error I got is like below:

My guess is that since react and react-dom would require some dependencies, putting all the files in the build.json won’t solve the dependencies.

But not sure how should I solve this imported_error within the frappe/erpnext framework. Any help is greatly appreciated!

Recently I found a workaround for this.

  • Build in any JS Framework (config proxy and other things for js+frappe seamless development)
  • Build Web component: output will be js file and css file. Put these in your build.json
  • <use-me data="hello components"></use-me>
2 Likes

Thanks for your reply.

However I’m not really sure if I understand your answers correctly.

  1. What do you mean by “config proxy”?

output will be js file, if old version of js framework is used then it’ll also output a css file

  1. I’m not sure if react and react-dom would output a css file during bench build process, and I suppose the version of them would be fixed as package-lock.json specified?

  2. <use-me data="hello components"></use-me>”, confused as this is supposed to be JSX or HTML?

Could you please elaborate?

Thank you.

Build a web component with react, https://reactjs.org/docs/web-components.html

html/js https://www.webcomponents.org/introduction

I figured out how to use React in Portal Pages.
Let’s say you have an app named myapp.
Then these are the steps.
1-in myapp run

yarn add react
yarn add react-dom

2-create jsx file in same dir, e.g. hello.jsx

import React from 'react';
import * as ReactDOM from 'react-dom'

class App extends React.Component {
    render() {
        return (
            <div className="App">
                <h1>Hello World App!</h1>
            </div>
        );
    }
}

export default function hello(it) {
    ReactDOM.render(<App/>, it);
}

3-create a js file named myapp.bundle.js in myapp/public/js with content like this

import hello from "./hello"

window.myapp = {}
window.myapp.hello = hello

4-create hello.html in myapp/www, e.g.

<div id="root">
  Loading...
</div>
{{ include_script('myapp.bundle.js') }}
<script>
  window.myapp.hello(document.getElementById('root'))
</script>

5-run bench build
6-now load page and you should see Hello World App!

I have to figure out how to do the same for Desk Pages next.

5 Likes

I figured out how to use React inside a Desk Page.
Assuming you created hello.jsx and myapp.bundle.js above.

1-Use Desk to create a Page(not a WebPage) called mypage (anything you want). Make sure it’s standard and choose your module.
2-A directory named mypage will be created along with files named mypage.js and mypage.json.
3-In mypage.js add this

frappe.pages['mypage'].on_page_load = function(wrapper) {
    var parent = $('<div class="container"></div>').appendTo(wrapper);
    frappe.require('myapp.bundle.js').then(() => {
        window.myapp.hello(parent[0])
    })
}

That’s it. Now you can see your React app rendered in /app/mypage.

4 Likes

Hi @mingfang,

Thank you very much for the detailed instructions.
I tried but failed at the attached the hello.jsx into window.myapp.hello.
image

In step 2, you wrote

2-create jsx file in same dir, e.g. hello.jsx

I tried with in my bench/app/myapp directory and also public/js but neither of them worked for me.

image


image

Could you please clarify which directory should I use, from the syntax import hello from "./hello", I suppose I need to attached the hello.jsx along with myapp.bundle.js in the same directory?

Thanks a lot.
Andy

the jsx and bundle.js files must go in public/js.
Also you must rename your react-bundle.js to react.bundle.js.
You can see here https://github.com/frappe/frappe/blob/develop/esbuild/esbuild.js#L169
that frappe looks for files named *.bundle.js

1 Like

Hi Ming Fang,

Thank you for your answers, I realized that I’m still using Frappe 12.11.0 and ERPNext 12.13.0 which doesn’t have the esbuild.js. I suppose that’s also the reason why I keep getting the error “cannot use import statement outside a module”.
image

I will try to update these two apps version and let you know how it goes.
Thank you again for your efforts.:+1:

Hi AOL,

Im curious if you were successful on your attempts to rebuild frappe with react components. I curious if this can be replicated to vue components?

If anyone wish to know about how I used webcomponents built with Angular?

Angular App: https://github.com/revant/erpnext_feature_board/tree/main/webcomponents
yarn build:elements: https://github.com/revant/erpnext_feature_board/tree/main/webcomponents/elements
Copied es5 built assets in public/js and public/css and mapped the files in build.json: https://github.com/revant/erpnext_feature_board/blob/main/erpnext_feature_board/public/build.json
Usage in improvement listing: https://github.com/revant/erpnext_feature_board/blob/main/erpnext_feature_board/www/improvements.html
Usage in improvement form: https://github.com/revant/erpnext_feature_board/blob/main/erpnext_feature_board/www/improvement.html

Live improvement listing (2021-07-02): https://board.castlecraft.co.in/improvements
Live improvement detail (2021-07-02): https://board.castlecraft.co.in/improvement?name=GH-IMP-2021-00092

2 Likes

It’s been a good learning experience but I’m afraid I hit a dead end with Frappe.
Making React work in Frappe is possible it’s not practical.

My use case is simple, I tried to implement a Desk page to should PrimeReact table here


I was not able to import css(import 'primeicons/primeicons.css';) files easily and had to modified frappe’s esbuild script to do so.
After building, the resulting css bundle was in the wrong directory and was unable to be loaded by Desk.

Long story short, this is the end of the road for me in Frappe.
It’s a great framework that makes simple things easy, but unfortunately the hard things are impossible. Good luck everyone.

1 Like

I’d recommend to first convert anything from any modern js framework to es5
and then use those packaged dist in frappe’s build.json

During first conversion setup your js build system however you like. Once we get it in es5 we can treat it as any other third party .min.js used in frappe framework.

There is a drawback in this method: frappe.* javascript object is not available during development of such app and you need to depend on dev server proxy to frappe gunicorn locally running on 8000. If dev server with proxy is setup then it can be used as api server during development, all backend ReST API calls can be made to /api/* routes from the frontend app without setting any URL.

The plus here is, you get all the power of metadata driven frappe framework to build the backend. If not you’ll need to wire up a lot of choices together to represent validated models in ReST/GraphQL API.

2 Likes

I got React working as frontend !, so the problem was esbuild will produce .js and .css and the .css file has no “entryPoint” so frappe simply ignores it. To fix this i avoided using css and used styled-components, using this esbuild does not produce a different css file and everything simply works !

You can access the frappe object in development as well, and there’s no need to use an api proxy nor there’s a need to build web-components

Also note that esbuild is only available on frappe’s develop branch, frappe v13 used rollup which doesn’t compile jsx on its own, there’s ways to make it work, but esbuild worked out-of-the-box

1 Like

Thank you, although I am still using V12, so I am not able to verify your solution. But your steps make sense to me, so I marked it as a solution to the ones who might encounter the same issue.

1 Like