ember-custom-elements icon indicating copy to clipboard operation
ember-custom-elements copied to clipboard

docs: how to render an entire application as custom element in another apps

Open billyjov opened this issue 3 years ago • 12 comments

Hi, thanks for this addon. I want to how i can build my app in other to render this in another react app. I did following like described in the README

app.js:

import Application from '@ember/application';
import Resolver from 'ember-resolver';
import loadInitializers from 'ember-load-initializers';
import config from 'ember-app/config/environment';
import { customElement } from 'ember-custom-elements';

@customElement('ember-app')
export default class App extends Application {
  modulePrefix = config.modulePrefix;
  podModulePrefix = config.podModulePrefix;
  Resolver = Resolver;

  // needed for custom elements
  autoboot = false;
}

loadInitializers(App, config.modulePrefix);

Then i ran ember build.

Import dist/vendor.js and dist/ember-app.js in my react app does not work to render <ember-app></ember-app>.

Is there a way to archieve this using the addon?

Thanks in advance

billyjov avatar Apr 13 '21 00:04 billyjov

@alexlafroscia @Ravenstine any advice on this ?

billyjov avatar Apr 14 '21 00:04 billyjov

@billyjov Looks like a bug to me. I think it wasn't caught before because the tests are only testing apps that have an owner. (honestly, I couldn't tell you exactly why that is).

I'm actually working right now on rolling out a new version with some fixes and improvements, so I will see if I can work this in.

Ravenstine avatar Apr 14 '21 02:04 Ravenstine

@Ravenstine what do you mean with

the tests are only testing apps that have an owner

?

billyjov avatar Apr 14 '21 10:04 billyjov

@billyjov If you look at the tests that test the use case of the decorator on an application class, it's actually registering the application class with the owner inside the test. This is on purpose since it's a conceivable use case where someone has an Ember app that imports/implements multiple other apps through custom elements, although I imagine that's a rare use-case. It was intended that your use case be supported as well, but I think I may have regressed it a while ago since there's no test that tests the use on application classes that don't have an owner associated with them.

In other words, it may be possible to get the existing version of this add-on to create a custom element to render an Ember app if it's owned by another app that has been booted(so that initializers are performed) but hasn't started routing (so that it doesn't render into the body element). However, I don't exactly recommend it and I couldn't guarantee whether that would work for what you want to do.

Last night I did some work to bring back this functionality (for apps that aren't owned by another container) so that it would support your use-case:

Screen Shot 2021-04-14 at 8 21 11 AM

I've got to do some more work to make sure it's well-tested and solid, but in the next day or so I'll make a pre-release that will include this and other improvements.

Ravenstine avatar Apr 14 '21 15:04 Ravenstine

Thanks.

Last night I did some work to bring back this functionality (for apps that aren't owned by another container) so that it would support your use-case

Can you pls release a new version of the addon so that i can try it locally too ? The steps you followed to archieve the result will also be helpful.

Thanks in advance.

billyjov avatar Apr 14 '21 15:04 billyjov

@billyjov I've published a pre-release version that has changes that I hope will resolve your issue. If you could try installing [email protected] and let me know if it works for you, it would be highly appreciated. Based on my own testing, it should work with your implementation that you've described.

https://www.npmjs.com/package/ember-custom-elements/v/2.1.0-1

Ravenstine avatar Apr 16 '21 23:04 Ravenstine

@Ravenstine i tried this and got following by importing vendor.js and ember-app.js inside my react app after a ember build command.

2021-04-19 23_10_45-

Am i missing something ?

Here is the repository where i gave a try.

https://github.com/billyjov/ember-react-microfrontend

billyjov avatar Apr 19 '21 21:04 billyjov

@billyjov So there's a few things that your build setup needs to do (outside the bounds of the add-on) to get it to work.

The problem you're seeing is due to your React app not being able to serve the vendor.js and ember-app.js files because they are outside of its public/ directory. You can handle this a few different ways, but I'm not that experienced with React so I'm not exactly sure what the common way to handle this is.

In a fork I made of your repo, you can see I created a Makefile with some steps that force the necessary files to be located in your React public/ folder:

https://github.com/billyjov/ember-react-microfrontend/compare/master...Ravenstine:master#diff-76ed074a9305c04054cdebb9e9aad2d818052b07091de1f20cad0bbac34ffb52

Basically, it just builds the Ember app, copies the dist/ contents into the public/, directory, and runs the React server. I'm sure there's a much better way to accomplish this, but at least it allows your React server to serve the Ember files. Someone better acquainted with React might be able to help you in this area.

Another thing that needs to happen (which I may add to the add-on documentation) is to tell Ember CLI to bundle the app config rather than place it in a <meta> tag:

https://github.com/billyjov/ember-react-microfrontend/compare/master...Ravenstine:master#diff-10b286d8090b2d4154f505a29e7f80da7ab948813c06aabf235f51f8102cbc0f

You'll also notice I disabled fingerprinting the built Ember assets, since that makes it difficult to copy and serve them. It's definitely feasible to try and preserve these fingerprints, or perhaps generate your own, but for now I've left them out for simplicity's sake.

I also had to uninstall ember-web-component-container because it was interfering: https://github.com/billyjov/ember-react-microfrontend/compare/master...Ravenstine:master#diff-7739ef01a01d2fec2b9c7a40af453f92771007f509619e2c9a46917e5c90322a

Not required, but I also added the links to the CSS files: https://github.com/billyjov/ember-react-microfrontend/compare/master...Ravenstine:master#diff-e3dd9433216572a204d2ab589ccf291c89fc1a72de4e69ead4299b05d62eef24

All those changes give me this: Screen Shot 2021-04-19 at 4 54 12 PM

Hopefully this helps you. Again, I pretty much know nothing about how React apps typically bundle things like this. This add-on pretty much leaves that detail up to whomever is using it in this way, but I will add some of these details to the documentation, which I will be working on reorganizing soon.

Ravenstine avatar Apr 20 '21 00:04 Ravenstine

Thanks for the explanations.. its works correctly. I will go a little deeper in my example . Thanks :)🎉

billyjov avatar Apr 20 '21 01:04 billyjov

@Ravenstine I'm not familiar with the ember-cli build system (comming from Angular world). Using Shadow DOM to encapsulate the app is the way i want to try. However its actually difficult because ember-cli create a separate css file. How would you include styles inside the ember-app.js directly and avoid styles to be override by external styles ? Does ember-cli provides something similar out of the box ?

billyjov avatar Apr 20 '21 01:04 billyjov

@billyjov There isn't really a way out of the box to bundle CSS as part of the JS, although it's conceivably possible to create that functionality through an add-on. If you don't mind still having the CSS files be generated and served by the server, one way you could achieve a similar effect is to take the <link> tags for the CSS out of the react-app/public/index.html and add them to the top of ember-app/app/templates/application.hbs without the %PUBLIC_URL% part. That way you can pass { useShadowRoot: true } to the customElement decorator, and the Ember app will be invoked inside the shadow root of your custom element and insert those link tags with the styles being isolated. (I tested that so I'm confident that works)

Of course, this requires the CSS files to always be served at the path at which your Ember app is expecting.

If you really want it so that you only need to serve the JS files for the Ember app, we'd have to figure out how to do it through ember-cli-build.js or by creating an add-on. I don't think it would be tremendously complicated, but it's not something I have muscle memory with. I might be able to investigate that tonight just cuz I'm curious about that myself as well. (from what I could tell last night, there doesn't seem to be any existing add-ons up to that task)

Ravenstine avatar Apr 20 '21 15:04 Ravenstine

@Ravenstine I found this package https://www.npmjs.com/package/ember-cli-concat that allow to concat all JS files into a single file and all css files into a single file.

billyjov avatar Jun 15 '21 13:06 billyjov