Skip to content
This repository has been archived by the owner on Oct 29, 2021. It is now read-only.

A sample app would be really helpful #11

Open
charl opened this issue Oct 10, 2015 · 35 comments
Open

A sample app would be really helpful #11

charl opened this issue Oct 10, 2015 · 35 comments

Comments

@charl
Copy link

charl commented Oct 10, 2015

There are a lot of moving parts to this setup and a sample app (say something like https://facebook.github.io/flux/docs/todo-list.html) would be really helpful.

@olebedev
Copy link
Owner

You mean docs that described what is going on or just simple app?

Btw, there is everything exactly like any regular isomorphic application except server rendering and data fetching. Good news that data fetching via fetch polyfill. It is new standard for client/server communication, see here.

Whatever, docs are required. I will make a detailed docs soon. Or maybe would you like to give me a hand?

@charl
Copy link
Author

charl commented Oct 14, 2015

I'd be happy to give you a hand @olebedev but I am just starting down this road.

I had a simple app in mind that illustrates how everything fits together as well as a description of the tooling you use to build apps with go-starter-kit for total beginners.

If there's anything a beginner can help with let me know and I'll pitch in.

@olebedev
Copy link
Owner

Hey @charl, thanks for you help. I am really appreciate it. And it seems that no need to be extraordinary experienced Gopher to improve README file here. All that we need just describe all steps in detail in some understandable way.

So, what about the new shiny application? At this moment I don't see any reason to develop something new. Because the existing app shows all specific isomorphic render cases. In particular there is only one thing that need to be clarify, it is data fetching at the server side. The rest are pretty regular things. More important things are about how the app executes, how to build the app and which endpoints the app has. Of course I ready to describe in draft any aspect if you will ask me in gitter chat.

For example we can start from more detailed what it contains description. And after we can describe the project structure(base on tree command output) and first developer steps(improving of install section). I am convinced that it will help some totally new developers to understand how to use it in right way. At the end we can describe some front-end goodies which the app contains. Again, I repeat it. No need to develop new app. Existing is cover all specific cases and even more.

There is only one reason why I cannot do it myself - english is not my native language. It would be great if you will help me with it. So, what can you say? Is it interesting for you?

@javiercbk
Copy link
Contributor

I'm making a quick single page app with a login (no database) just to see how that scenario would play out.

There are a couple of things I'm interested in:

  • How to render two templates (login and home page) using the react render. I know I could render the whole app without making a redirect, but I want to reduce the amount of js and css in the login page.
  • Use boostrap with react-boostrap. Even though the css can be included in the html template, I want to explore the best way to include boostrap's css classes (I might import the styles and let webpack do it's magic or append the css and user classnames to handle class injection, I really don't know yet).
  • Public and private API (using JWT tokens)
  • IF POSSIBLE: Generate swagger files to document the API

Thing I'm not interested in testing:

  • Database storage (or any storage layer), there are plenty of tutorials (and sample projects) that tackle these technologies.
  • Old browsers. If it runs on the latest Google Chrome, Safari and Firefox, it will be good enough for me.

If you guys think of any cool use case that might improve this sample app, I'm happy to hear from you.

@Kielan
Copy link

Kielan commented Jan 24, 2016

+1 in particular the make file seems to be causing a lot of people issues including myself. I had to rewrite it to get it to work.

There's no reason for so many moving parts and reserved values for file locations ect as it takes a while for someone jumping into the project to grok. This is an opinionated statement and I can see why some might disagree but based on the issues it seems to be a big problem with this repo.

@olebedev
Copy link
Owner

Obviously, It is hard to start different projects in the current state as it overengineered a bit. Now it looks like a framework and this is the problem. BTW, the same starter kits based on node.js overengineered as well. The project needs to be simplified.

As mentioned, I need help with it. In particular, I need to know what is the most important part for you. It could be the matter when I will start to simplify it. So guys, please tell me what is the most important part of it for you? Which things from here are sould get rid out as you see?

@Kielan what kind of rewriting was applied, could you provide it?

/cc @charl, @javiercbk, @whatisgravity, @smd686s

@whatisgravity
Copy link

I think a simple todo list that provides a CRUD example would be very helpful. With how much is there it is hard to see where to start.

@Kielan
Copy link

Kielan commented Jan 25, 2016

@olebedev Correction as I got ahead of myself, I am still re writing the makefile. Some documentation on what LDFLAGS is doing as well as BINDATA would be helpful. I don't see a bindata.go file in the server folder.

In general I don't want to have any version control method forced upon me.

I'm not sure why you are telling people to reset their gopath to a more specific folder, as the project should already be within their gopath.

Also curious about the command
go get ./...
does what exactly?

@widnyana
Copy link

@Kielan if I simplify it, that command will install all the required dependency into $GOPATH

we know npm has package.json on the root dir and we can install it all via npm i, in golang the tools will iterate through import statement listed on the source code, and install all the package.

the bad news, go get doesnt handle package versioning. it will fetch the master branch, that's why srlt, gopkg.in and etc exists

@kockok
Copy link

kockok commented May 24, 2016

A sample app with user authentication would be perfect! And how about production deploy on a VPS?

@olebedev
Copy link
Owner

Hi @kockok,
a sample app with user authentication is not the case for this repo. Bit I REALLY appreciate if some could do it separately.
Regarding deployment, you could just add deploy target as CI derective. Wercker allows us to deploy built artifact everywhere we want.

@kockok
Copy link

kockok commented May 27, 2016

I found this client side auth pretty neat. https://github.com/lynndylanhurley/redux-auth

@geir54
Copy link

geir54 commented Oct 18, 2016

I've started playing around with this in https://github.com/geir54/go-starter-kit if any one is still interested

@olebedev
Copy link
Owner

@geir54, looks good to me. Please, send a PR when you finish

@geir54
Copy link

geir54 commented Oct 19, 2016

@olebedev Do you want this as part of this repo? I was thinking to have a seperate full app repo

@olebedev
Copy link
Owner

@geir54, yup, it would be better. I will point the app in readme.

@kockok
Copy link

kockok commented Oct 25, 2016

I'm still struggling to deploy on a VPS(Digitalocean). I used to using Capistrano for that. Any tools similar for this kit? Thanks.

@iKonrad
Copy link

iKonrad commented Nov 26, 2016

@kockok I've used flightplan.js for my previous project. I see no reason why it wouldn't work with this one. It's quite simple to set up and extend.

@tanis2000
Copy link

@olebedev do you know if anyone actually used your repo to create an app with user authentication like you suggested?

@llitfkitfk
Copy link

add docker for mac quick start demo #72

@tanis2000
Copy link

@llitfkitfk that's nice. I did something similar for a project I'm working on that spawned from this repo.
BTW I have a working app with authentication so if there's anyone who has already made a repo for such an app we could get that running together.

@iKonrad
Copy link

iKonrad commented Mar 22, 2017

@tanis2000 nice! What did you use for authentication?

@tanis2000
Copy link

@iKonrad nothing fancy. It's just standard JWT through the echo framework. I had to do a bit of magic with cookies to keep the authentication working both on the client and with server side rendering, but that's all it takes.

@iKonrad
Copy link

iKonrad commented Mar 24, 2017

Is it session/cookie based or pure API?
Since this project is isomorphic I'd like to have authentication that takes advantage of server side rendering.

@tanis2000
Copy link

I initially went for localStorage but then moved to cookies for your same reasons. The good thing about cookies is that I can just grab them from the browser, push it to the server, bridge it to the JSVM and do whatever I need before rendering the page on the server. That way it works both client and server side the same way.

There's only one concern left which is retrieving data from promises of action creators on the server as the current implementation doesn't wait for promises to be resolved before rendering

@iKonrad
Copy link

iKonrad commented Mar 24, 2017

You need redux thunk middleware for that and register it in the router.js file.

`
import thunkMiddleware from 'redux-thunk';

// Add state logger
if (process.env.NODE_ENV !== 'production') {
middlewares.push(require('redux-logger')());
middlewares.push(thunkMiddleware);
}
`

And then, in your action creator you need to return the dispatch object so thunk can handle it

Change it from:
export function setConfig(config) { return { type: SET_CONFIG, config }; }

To:

export function setConfig(config) { return (dispatch) => { $.get('/api/users', (data) => { dispatch({ users: data }); }) } }

So thunk will keep the promise until your API call is finished

@tanis2000
Copy link

I'm already doing that but it's not enough.

here's the equivalent of the function run in onEnter in the /usage route:

export function loadConfig() {
  return function(dispatch) {
    return fetch('/api/v1/system/conf').then((r) => {
      return r.json();
    }).then((conf) => {
      dispatch(setConfig(conf));
    });
  };
}

The promise returned by fetch isn't being waited upon. I'm not sure this is actually an issue with @olebedev implementation of fetch or the way I'm using the thunk middleware that's wrong.

Calling that function from the onEnter like this leads to the fetch function being called but not waited to resolve:

  static onEnter({store, nextState, replaceState, callback}) {
    store.dispatch(loadConfig());
    callback();
  }

@tanis2000
Copy link

Since onEnter() isn't working as expected I thought I'd just do it another way and implement a static function called fetchData on all the components needing some initial data and wrap the renderToString call into a Promise chain.

In the component's class:

  static fetchData({ query, params, store, history }) {
    return store.dispatch(loadConfig());
  }

In toString.js:

          function getReduxPromise () {
            let { query, params } = renderProps;
            let comp = renderProps.components[renderProps.components.length - 1].WrappedComponent;
            let promise = comp.fetchData ?
              comp.fetchData({ query, params, store, /*history*/ }) :
              Promise.resolve();
            return promise;
          }
          
          getReduxPromise()
          .then(() => {
            result.app = renderToString(
              <Provider store={store}>
                <RouterContext {...renderProps} />
              </Provider>
            );
            const { title, meta } = Helmet.rewind();
            result.title = title.toString();
            result.meta = meta.toString();
            result.initial = JSON.stringify(store.getState());
            return cbk(result);
          });

That way all of my non authenticated routes are actually retrieving the data needed and rendering correctly.

But as you can guess, authenticated components are being composed within this kind of component:

export function requireAuthentication(Component) {

  class AuthenticatedComponent extends React.Component {

    componentWillMount() {
      this.checkAuth(this.props.isAuthenticated);
    }

    componentWillReceiveProps(nextProps) {
      this.checkAuth(nextProps.isAuthenticated);
    }

    checkAuth(isAuthenticated) {
      if (!isAuthenticated) {
        let redirectAfterLogin = this.props.location.pathname;
        this.context.router.push(`/?next=${redirectAfterLogin}`);
      }
    }

    render() {
      return (
                <div>
                    {this.props.isAuthenticated === true
                        ? <Component {...this.props} />
                        : null
                    }
                </div>
      );

    }
  }

  AuthenticatedComponent.contextTypes = {
    router: React.PropTypes.object.isRequired
  };

  const mapStateToProps = (state) => ({
    token: state.auth.token,
    userName: state.auth.userName,
    isAuthenticated: state.auth.isAuthenticated
  });

  return connect(mapStateToProps)(AuthenticatedComponent);

}

And this composed component is wrapping the inner component that needs to be protected from anonymous access and it doesn't expose the fetchData static method of the inner component.

This is where I am at the moment. I'm pretty sure there should be a way to either call the inner fetchData method from within the React markup or some other way to get down there in the chain.

This also rules out @olebedev fetch from the equation as it's definitely working fine.

@tanis2000
Copy link

The solution was easier than expected. I just needed to add a fetchData method to the AuthenticatedComponent that checks if the wrapped component has one and returns it or eventually returns an empty promise.

Here's the code:

    static fetchData({ query, params, store, history }) {
      let promise = Component.fetchData ? Component.fetchData({ query, params, store, history }) : Promise.resolve();
      return promise;
    }

That's basically all that's needed to have auth work on the server side apparently.

@skydiator
Copy link

@tanis2000 I am also playing around with the implementation of authentication part. Do you have the complete code in a repo to share with us?

@tanis2000
Copy link

@skydiator I have everything in a private repo as I'm using that for a private project. If there's enough interest and more contributors I'd be happy to create an open one to share with everybody :)

@iKonrad
Copy link

iKonrad commented Apr 2, 2017

@tanis2000 I'm having the same issue now (with rendering data from fetch on first call).

Would you mind posting your toString.js file and fetchData methods?

EDIT: I got it working - thanks for suggesting a solution with fetchData static method.

I just had to refactor some code as it didn't like when fetchData wasn't present in Component:

`let { query, params } = renderProps;
let comp = renderProps.components[renderProps.components.length - 1].WrappedComponent;
let promise;
if (typeof(comp.fetchData) !== 'undefined') {
promise = comp.fetchData({ query, params, store, /history/ });
promise.then(() => {
renderComponent();
});
} else {
renderComponent();
}

function renderComponent() {
result.app = renderToString(

<RouterContext {...renderProps} />

);
const { title, meta } = Helmet.rewind();
result.title = title.toString();
result.meta = meta.toString();
result.initial = JSON.stringify(store.getState());
return cbk(result);
}
`

@iKonrad
Copy link

iKonrad commented Apr 2, 2017

Now I have a different issue.

I'm in the middle of writing a custom cookie/session based authentication.

I've got a cookie "SESSION_ID" which is retrieved on the server and processed. But when I render the react template on the server, and it executes the 'fetchData' function, it doesn't pass any cookie to the /api endpoint and therefore I can't authenticate the request.
How did you solve that?

@kockok
Copy link

kockok commented Apr 12, 2017

@iKonrad Can you write a litter tutorial on how to use flightplan.js to do continuous deployment with this golang kit? Thanks.

@softgripper
Copy link

softgripper commented Jun 6, 2017

And I can't get this building on windows - and I'm no makefile guru, but it's doing some wizardry.

I'd love to be able to install this and run through an app/tutorial.

Right now, I think I'm going to just write my own :(

It was painless to get up and running on Linux in a VM, but I hate using that OS for development. Linux GUI still isn't quite at Windows/Mac level for developing - and my mac is old and dusty.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests