React + Atlassian Connect Express

Is there a recommended architecture for getting started with React via create-react-app and Atlassian Connect Express?

It seems natural to head in the direction of putting the “client” skeleton provided by create-react-app into the ACE infrastructure and letting it handle all views, but I’d appreciate any heads up of traps in this approach.

2 Likes

I just found that AltasKit has a starter project.

It’s surprising this doesn’t feature more prominently in the Getting Started documentation - the only mention I found of it was that it is a “library of components”, which put it in the “worry about that when I need a library of components” bucket :slight_smile:

… but I see that it doesn’t really answer my question - it’s just the React client.

So the question remains - how to set up an application with React (client from create-react-app) + ACE (server), what gotchas might one anticipate?

One immediate gotcha is that the create-react-app framework expects to be the front end web server, but ACE sets up the tunnel to it’s express server.

So far, this seems to mean either abandoning ACE and doing what it does manually, with the tunnel pointing to the react app, or ejecting from the create-react-app framework and then hacking that to serve the react entry point script to ACE server.

Would love to know if someone solved this already :slight_smile:

Please see ACE + React (create-react-app)

Thanks - unfortunately these don’t help me with what must be a basic question, but is blocking me.

When you use fullstackreact, in Dev mode React is served by webpack, and expects to proxy API requests to the backend server through webpack

https://github.com/fullstackreact/food-lookup-demo/raw/master/flow-diagram.png

In this picture, ACE is the API server.

The basic problem I’m having is that ACE expects the user (the Jira cloud instance) to be talking direct to it, and it sets up a tunnel to itself for the Jira cloud instance to talk through.

So I can easily not do the proxy, and have the webpack dev server just serving the react pages, but in that scenario I haven’t been able to see how to get ACE to front this - IE a request for a route in the react app coming from Jira in the cloud has to somehow go via ACE to the webpack server.

It’s probably trivial (it sounds it) yet I haven’t been able to make that work.

Sorry for confusion, I just wanted to say that yes, this seems to be unsolved problem.

Thanks. It seems like it would be a Good Thing. At least, for me the goal is to have the hot module replacement for the react server supplied by Webpack.

The alternative that “works” is to build the react side each time, and serve the built files, but that is a painfully slow business.

It’s surprisingly hard to make this work. I must be missing something obvious, but not sure what yet.

Hey martin, i feel your struggle, i’ve tried to use create-react-app with ace, but failed, because of lots of little quirks and edges that don’t fit together. So the best way is to create your own setup. I made a little work on that, with help of survive.js book i’ve setup basic react project as my client and hooked it up with server by building files and creating .hbs files for my views folder with htmlwebpack plugin.
I’ve uploaded it here, if you want you can try it out, maybe make it even better or just create your own setup.

3 Likes

That’s a very nice piece of work - looks really clean, worked right away. Thanks!

How does this magic work?

<% htmlWebpackPlugin.files.js.forEach(function(file) { %>

… I can’t see where htmlWebpackPlugin.files is coming from! :slight_smile:

That’s from htmlWebpackPlugin :slight_smile:
htmlWebpackPlugin allows you to control files that are injected in html if you want, it uses ejs syntax by default, hence those <% %> tags, you can type <%= htmlWebpackPlugin.files %> to see what’s inside of the files variable.
Pretty much it contains all your pages defined in webpack.config.js file at the end of a file like so
You can also use webpack variable there, it might be handy for some cases, but i don’t know which exactly :slight_smile:

const pages = [
        parts.page({
            title: 'Index page',
            template: path.resolve(`${__dirname}/../server/views/templates/index.hbs`),
            filename: path.resolve(`${__dirname}/../server/views/index.hbs`),
            entry: {
                app: PATHS.app
            },
            chunks: ['app', 'manifest', 'vendor'].concat(reactDevtoolsChunk),
            minify: env === 'development' ? false : minifyOptions,
            env
        })
    ]

Don’t forget to change chunks and entry. For this page i provide app entry and also explicitly provide chunks that i want to include in hbs file.

I use this multipage setup because i don’t want to import my whole react project in one hbs file and then manage inside it which page exactly should i render for such places like admin pages and sections in issues, i think it’s better to have multiple pages for that, then include react part just for that case, this pages refreshes between them anyway, so less code to load, less pain to manage.
If you need only one page that’s okay too, you just keep one page inside an array :slight_smile:

Maybe better approach for managing multiple pages, especially if you’re going for a huuuuge app is to make different configs for each page and build them in parallel, but that’s an optimisation for a really big projects, i bet they would make even better setup then what i have :smiley:

Also it might be unnecessary to use furl in hbs file (that’s a helper function provided by ACE to fingerprint static resources url) since we already adding hashes to our static resources

2 Likes

FWIW I finally got to the bottom of why it is fundamentally not possible to build a ACE API server with a create-react-app client react server, out of the box.

The reason is that

  1. The ACE express server has to be the one fronting the user (Jira) because it sets up the tunnel.

That means that React routes have to get to React via it.

  1. The express server setup done by ACE has this in it:

    // defer configuration of the plugin until the express app has been configured
    process.nextTick(function () {
    self._configure(callback);
    });

Inside that self._configure() the various express routes needed by ACE are setup.

And the reason why this is a problem is that any solution using ACE as the backend server has to somehow send all react routes to the react server. What these routes are is not known in advance (and should not have to be known at the ACE level). That means that there will have to be a catchall route in the ACE express server that sends anything not destined to the ACE server over to react.

But you can’t make a catchall route in the ACE express server setup (app.js and routes/index.js), because that will “get in first” before the ACE configuration above is run, which means that the routes intended for ACE would get sent by the catchall to react instead. Fundamentally the catch-all for react has to be configured last. But it can’t due to that above code.

This is a shame, and I’m still pursuing it, because I think there is a lot of benefit in being able to use both ACE and the create-react-app infrastructure as each intended, in a complimentary way.

(alexter_pr’s solution is nice and clean looking but was forced to abandon create-react-app. That pages setup magic to make it work is also a little scary from a maintenance point of view!)

4 Likes

The other way is to make something similar to ACE, but with your language of choice, handle app authentication, and also manage REST API authentication for client too and all that server things :slight_smile: I’m not enough experienced yet to do that myself, but i know that some people make their apps with dart. Though this might take some time to setup, but then you would have much grained control over your app

As I mentioned, I think it is a “worthwhile goal” to be able to build a React based addon using both the ACE and create-react-app frameworks if possible, mostly so that we can then worry about writing the addon instead of the dev framework :smiley:

I have an experimental solution working now.

First, I had to fork ACE with a tweak to make it possible to add a catchall route after ACE route configuration.

With that in place, it appears very simple to proxy all React related calls to the web server.

The resulting “starter project” is here if anyone is interested.

It’s very important to note that this is experimental: it might be flawed because I don’t necessarily know what I’m doing!

Therefore, I’d be delighted if it helps someone else get started too - as long as you understand that, but

I’d be even more delighted if someone who is more intimate with ACE was able to take a look and spot flaws. :slight_smile:

Fortunately it doesn’t seem to matter if it is flawed: any addon development done using it will be fine anyhow, it just might need something like alexter’s skelton replacing this, should there be an issue later with this way of running the dev environment.

So I am pressing on building on top of it.

One thing I’ve noticed is that the Atlassian Connect all.js appears to cause some interesting traffic to the React server even though the React app doesn’t try to use any AC functions yet.

 GET /static/js/bundle.js 200 69.239 ms - 342092
[0] GET /sockjs-node/info?t=1509075873554 200 8.830 ms - 79
[0] GET /static/media/logo.5d5d9eef.svg 200 15.343 ms - 1308
[0] GET /sockjs-node/iframe.html 200 7.122 ms - 449
[0] GET /__webpack_dev_server__/sockjs.bundle.js 200 16.494 ms - -
[0] GET /__webpack_dev_server__/sockjs.bundle.js 304 8.537 ms - -
[0] POST /sockjs-node/272/a4hue25n/xhr?t=1509075889235 200 7.507 ms - 2
[0] POST /sockjs-node/272/a4hue25n/xhr?t=1509075891695 200 6.463 ms - 145

I’m vaguely wary about whether these are sync or async, and if that is affecting the ACE server delivering API requests.

If anyone can suggest if this is something to worry about or not, that too would be great :slight_smile:

That’s cool, i wish ACE team provide solution for this kind of things, since it was built to make cloud add-ons plus new design demands to use atlaskit, so it would be nice to be able to make add-ons instead of worrying about how to glue this two pieces together :pensive:

@martin.gregory, would you mind making PR for ACE? Maybe they would consider adding it or providing us with something else

Also requests to webpack server exhausts ngrok connections limit pretty fast, so it’s appearing to be very annoying :frowning:

I’m so sad that Atlassian doesn’t want to provide robust tooling for creating add-ons, which doesn’t involve me into managing all that jizz. Maybe i’m just too unexperienced.

Yeah, I have it in mind to create a PR. I’ve seen (looking at others) that they won’t accept a PR without tests (fair enough) so I have to take some time out to look into how the ACE test set up works. Maybe next week.

Also, maybe after I’ve used it a bit and get more confident that there aren’t further gotcha’s waiting to be discovered :slight_smile:

My experience with create-react-app is that it’s a great way to get started and concentrating on your add-on’s goals immediately. Long term, though, you will likely “eject” so you can better control the
config of how your javascript is built.

The main issue for me (as it’s a devspeed killer) is that the JS files (as you’ve identified) have to be served over the ngrok tunnel. This is incredibly slow as you have to both upload and then download many megs of js on every page refresh. The way I get around this is to eject from create-react-app so I can define my own webpack config. This uses the ssl: true flag and I refer to localhost instead of the app URL for loading the JS. In the end, since the “ejected” config is quite complicated and does a whole lot of stuff I’m not interested in, I just went back to a basic webpack config that I built myself. Webpack 2 is much, much easier to configure, so I recommend just biting this off and leaning as a part of your dev environment setup.

Aside from that, there are a number of other reasons why a custom webpack config has become necessary (we build cloud and server versions of our apps, etc).

Hope this helps.

2 Likes

Any chance of sharing the config you’ve come up with? (Or a stripped version that shows the basics that you mention)

I couldn’t recommend @edave’s suggestion more. We’ve done the same and it was worth the time to get it right.

Keep in mind if you use a VM to test IE then the localhost webpack dev server by default isn’t accessible inside the VM.