carteb / carte-blanche

An isolated development space with integrated fuzz testing for your components. See them individually, explore them in different states and quickly and confidently develop them.
https://www.youtube.com/watch?v=6g3-TQ6aaw8
MIT License
1.5k stars 47 forks source link

Angular plugin #374

Open joaogarin opened 8 years ago

joaogarin commented 8 years ago

Hello

I am playing around with carte blance to attempt to create a prototype of it using angular2. the initial setup was pretty nice, and getting the carteblanche running the frontend in a working environment with webpack.

Now I have a couple of questions regarding the webpack hooks and the frontend. Mainly 2 things :

1 ) I am using the carte-blanche-plugin-before-processing hook to analyze my component. In angular2 components define inputs (equivalent to props in react). I am using http://typedoc.io/ to analyze the component and it gives me a nice representation of the inputs and its types (because most angular2 apps use typescript I am focusing on that now, simplifies a lot). Now the thing is this function is asyncronous and I get this value in a callback. Something like

compilation.plugin('carte-blanche-plugin-before-processing', (data) => {
    // Read the data from this component
    type_doc_parser(data.source, (parsedComponent) => {
        data.AngularSouce = parsedComponent;
    });
});

However this does not work, it is as if this hook is expecting whatever to get applied to the data object to be syncronous. If I do a simple assignment it works fine, but if I assign inside the callback or in any async way it does not work. Maybe something obvious..but I cant seem to figure out why. this can be seen here https://github.com/joaogarin/carte-blanche-angular2/blob/master/plugin.js#L89

2 ) The frontend essencially runs fine, but I am not sure how to actually render stuff in there if that makes sense. In the examples I see from the plugins you provide you use react which renders HTML directly in javscript. That's not how it works with angular. So in Angular the natural way to do this is to render a component which can then use something called the dynamic component loader to render other components dynamically. but for that I first need to be able to render something inside my frontend. Even if I try to just render static HTML in there, it does not work and prints it as a string only. https://github.com/joaogarin/carte-blanche-angular2/blob/master/frontend/index.ts Right now I am not really doing anything in there..but I would like to just figure out how to get my HTML to render in there properly. Maybe I need to understand better what the return in this function means, where does it go to.

I think cartblance would play very well with angular. There are some tricky things and I dont think getting the metadata from the components is that part, that is actually fairly easy at least with apps running typescript (which are the vast majority). But rendering might be the tricky part.

Angular needs to do a bootstrap to render stuff in the frontend. This means basically that I need to run a "Angular" app in the frontend. This means having a main HTML tag like and a piece of javascript that will take this and bootstrap the angular app inside it.

This angular app will then load a main component (much like your playground) which will be responsible for rendering the component dynamically depending on the inputs chosen by the user, or the randomize algorythm..I would get into that later as soon as I can render a simple component in the frontend. If I get a component rendering in the frontend everything after that will just fall into place.

If this does not make perfect sense I would say lets get the first issue going, that the second one I still can investigate more. I havent spend all that much time on it, also javascript is kind of my hobbie so I do have some limited experience with it. but seems like this can be a fun thing at least to kickstart and someone can pick up and improve it with me.

nikgraf commented 8 years ago

first of all, super cool that you already investigated so much 👌

I haven't tried right now as I'm in a branch debugging with complete different packages, but if I'm not wrong this should work:

compilation.plugin('carte-blanche-plugin-before-processing', (data,callback) => {
    // Read the data from this component
    type_doc_parser(data.source, (parsedComponent) => {
        data.AngularSouce = parsedComponent;
        callback();
    });
});

Regarding your second question: I just noticed we basically require you to have React. We should fix this so you can define your own template and use angular in there.

Let me know if the first hint worked, on the second one we can do some pair programming by the end of next Thursday/Friday in Vienna or via Skype :)

joaogarin commented 8 years ago

Yeah I tried the callback option before as I read it in the webpack docs, but it did not work. I do have something in there as the second parameter but its not a function. Its actually an object like the following :

{ data: undefined,
  inputValue: undefined,
  query: '?dest="carte-blanche"&commonsChunkFilename="undefined"',
  async: [Function: async],
  callback: [Function] }

So if I try callback() I get a type error

TypeError: callback is not a function

If I try callback.callback() (which is a function) it says

Error: callback(): The callback was already called.

I will keep digging a bit as I can. But yeah lets meet for the second part once this one is more or less on the run. I will try and do some homework on this angular dynamic component loader which seems to be the obvious choice for something like carte blanche.

mxstbr commented 8 years ago

Woah awesome @joaogarin!! I'm currently on holiday, but I'll gladly help you with this as well once I'm back next week!

joaogarin commented 8 years ago

great! Sure thing

joaogarin commented 8 years ago

So @mxstbr do you have any insight on this callback thing? Basically I need to do something that will return something in a callback inside this hook. When I do that I see the data there, everything looks great but it doesn't pass it to the frontend (I think basically it has already gone through it) so something like this callback() call form webpack seems to be the right fit as metioned here https://github.com/webpack/docs/wiki/how-to-write-a-plugin#async-compilation-plugins

mxstbr commented 8 years ago

Hmm, the the carte-blanche-plugin-before-processing hook needs to run sync at the moment. Let me have a think about this, not sure how we could solve it.

Regarding your second question, we expect you to return react code from your plugin, e.g.

import React from 'react';

function angularPlugin(frontendData, pluginData, Component, componentPath) {
  return (
    <div>{componentPath}</div>
  );
}

While I agree that we should change this, could we work around this for now by somehow rendering the Angular 2 components with react? (something like ngReact but the other way around?)

joaogarin commented 8 years ago

Yes second one works. But for that I have to turn on Jsx for typescript (using .tsx files and turning some options on the compiler to use jsx). However that might affect the way it will work with my angular app that I need to render the components, because it does not work with jsx, or maybe it does I am not sure.. is there a ES6 equivalent for that?

Regarding the first one, let me then figure out how I can do that..the reason is that typedoc what I am using to get the info from the component is actually writing to a file and I have to read from that file to get the info..but maybe there is a way to get around that. I will dig into it.

joaogarin commented 8 years ago

React.createElement seems to be what I was looking for;P

joaogarin commented 8 years ago

Good news! The first issue I managed to get around in getting the info async so dont really need antyhing being done there anymore.

Also I have now my frontend app being delivered in this Jsx thing. So basically


import * as React from 'react';
import {main} from './src/main.ts';

export default function playground(frontendData, pluginData, Component, componentPath) {
  console.log(pluginData);
  // Bootstrap the angular app
  main();
  return <div className="cbapp">{componentPath}</div>;
}

cbapp is just he placeholder where my angular2 app will bootstrap on. the base element so to say..So now basically I already have my app running inside carteblanche with the info on each component.

app

This is just a demo app to prove the concept that I can render the angular2 app inside react.

Now I will be playing around with the data from the component like Inputs and Input types (similar to react props and prop types) to be able to generate different versions of the components. I will take some ideas on the react plugin to get that popup to manage the inputs etc..

So now everything is on my side;P let you know of the progress soon.

mxstbr commented 8 years ago

Awesome!! :+1: :+1:

joaogarin commented 8 years ago

Hello,

I am trying to make some progress. I am now basically able to render components inside cart blanche, but struggling on some issues that I think maybe taking some ideas from the way you are doing the react plugin might share some light.

Can you briefly describe to me the process of how the plugin works in terms of rendering the component? My understanding is you are taking the user bundle, putting it in an iframe and rendering the component there? But maybe I am wrong.

My approach at the moment is different as I actually get the info from the component from this kid of documentation generator (typedoc) and put it inside my own app. That works well for pure dumb components that rely only on inputs of primitive types but that can have some tricky situations if the user has some dependency on that component on a part of his app that is not in my app (maybe that's why you include the user's bundle in there?) or if the component renders a child component inside, this last part I cant seem to get over it..and its quite common I am sure the same happens in react.

So my question is more or less how are you dealing with the fact people just do some weird stuff with components that you might not have access to? My perception is carte-blanche is for highly reusable and testable components that receive inputs and depend only on those inputs.

Maybe just understanding better the react plugin can help me take some idea that might be useful.

joaogarin commented 8 years ago

Hello guys any feedback n this?

joaogarin commented 8 years ago

Hello guys. Sorry been on vacation so was a bit quiet.. I did do some progress on the sample app. basically I have some basic rendering going on for most simple components, and now would be nice to start getting into making variations and generating metadata for the components.

I noticed in the react plugin Faker.js is being used to generate the metadata for the components.I still have some doubts on the workflow like how to you specify that a component property is a avatar or a phone for example.

I will dig into this topic this week and hopefully get something real working where you can already save variations and generate real metadata for component properties.