Coder Social home page Coder Social logo

hung-phan / koa-react-isomorphic Goto Github PK

View Code? Open in Web Editor NEW
127.0 19.0 16.0 2.68 MB

Boilerplate for Koa & React

License: MIT License

JavaScript 84.64% HTML 12.53% CSS 0.08% Shell 1.70% Dockerfile 1.05%
redux react relay koa immutablejs webpack boilerplate ssr

koa-react-isomorphic's Introduction

React and Koa boilerplate (deprecated. New project available at https://github.com/hung-phan/micro-nextjs)

build status codecov Dependency Status devDependency Status

The idea of this repository is to implement all new concepts and libraries which work great for React.js.

Requirement

Features

Explanation

Templates

Templates are written in marko.js with predefined template helpers. To see its usage, please refer to layout/application.marko.

Server side rendering

I use webpack-isomorphic-tools to support loading assets in the server side. You can see the configuration file under config folder.

Fetch data

  • For redux, data is fetched using redial hooks on the server side.

Takes a look at templates/todos, I will have sth like:

  createRedialEnhancer({
    [FETCH_DATA_HOOK]: ({ store }) => store.dispatch(fetchTodos()),
    [UPDATE_HEADER_HOOK]: ({ store }) => store.dispatch(updateLink([
      // window.javascriptAssets will be injected to do preload link for optimizing route
      { rel: 'preload', href: window.javascriptAssets['static-page'], as: 'script' },
    ])),
  })
  • For relay, data is fetched using isomorphic-relay-router on the server side.

Default require for node

The default require node statement has been modified by webpack-isomorphic-tools, so I remap it with nodeRequire under global. For example, you can use it like as below:

const { ROOT, PUBLIC } = global.nodeRequire('./config/path-helper');

Note: nodeRequire will resolve the path from project root directory.

Preload assets via redial

To be able to support for asynchronous chunks loading using <link rel='preload' ... />, I returned the javascript assets map for all the routes to the client via window.javascriptAssets.

You can use this to inject assets for the next page to improve performance. This is what I am trying to achieve preload-webpack-plugin.

This will map the hook with the current component and trigger it (Note: This will only be applied to root component).

Async react components

react-loadable

Idea to structure redux application

For now, the best way is to place all logic in the same place with components to make it less painful when scaling the application. Current structure is the combination of ideas from organizing-redux and ducks-modular-redux. Briefly, I will have our reducer, action-types, and actions in the same place with featured components.

alt text

Localize selectors

Some great ideas from scoped-selectors-for-redux-modules. You can create a localized scope for selector using globalizeSelectors.

export const mountPoint = 'todos';

export const selectors = globalizeSelectors({
  getTodos: identity, // it will also work with reselect library
}, mountPoint);

Then in main reducer, you can have sth like this, which helps reduce the coupling with React view

/* @flow */
import { combineReducers } from 'redux';
import todosReducer, { mountPoint as todosMountPoint } from './components/todos/logicBundle';
import routingReducer, { mountPoint as routingMountPoint } from './components/routing/logicBundle';
import helmetReducer, { mountPoint as helmetMountPoint } from './components/helmet/logicBundle';

export default combineReducers({
  [todosMountPoint]: todosReducer,
  [routingMountPoint]: routingReducer,
  [helmetMountPoint]: helmetReducer,
});

Sample for logicBundle:

export const mountPoint = "todos";

export const selectors = globalizeSelectors(
  {
    getTodos: identity
  },
  mountPoint
);

export const ADD_TODO = "todos/ADD_TODO";
export const REMOVE_TODO = "todos/REMOVE_TODO";
export const COMPLETE_TODO = "todos/COMPLETE_TODO";
export const SET_TODOS = "todos/SET_TODOS";

export const addTodo: AddTodoActionType = createAction(ADD_TODO);
export const removeTodo: RemoveTodoActionType = createAction(REMOVE_TODO);
export const completeTodo: CompleteTodoActionType = createAction(COMPLETE_TODO);
export const setTodos: SetTodosActionType = createAction(SET_TODOS);
export const fetchTodos = () =>
  (dispatch: Function): Promise<TodoType[]> =>
    fetch(getUrl("/api/v1/todos"))
      .then(res => res.json())
      .then((res: TodoType[]) => dispatch(setTodos(res)));

export default handleActions(
  {
    [ADD_TODO]: (state, { payload: text }) => update(state, {
      $push: [{ text, complete: false }]
    }),
    [REMOVE_TODO]: (state, { payload: index }) => update(state, {
      $splice: [[index, 1]]
    }),
    [COMPLETE_TODO]: (state, { payload: index }) => update(state, {
      $splice: [
        [index, 1],
        [index, 0, { ...state[index], complete: !state[index].complete }]
      ]
    }),
    [SET_TODOS]: (state, { payload: todos }) => todos
  },
  []
);

Upcoming

  • Phusion Passenger server with Nginx

Development

$ git clone [email protected]:hung-phan/koa-react-isomorphic.git
$ cd koa-react-isomorphic
$ yarn install

Hot reload

$ yarn run watch
$ yarn run dev

With server rendering - encourage for testing only

$ SERVER_RENDERING=true yarn run watch
$ yarn run dev

Enable flowtype in development

$ yarn run flow-watch
$ yarn run flow-stop # to terminate the server

You need to add annotation to the file to enable flowtype (// @flow)

Test

$ yarn test

Debug

$ yarn run watch
$ yarn run debug

Production

Start production server

$ yarn run build
$ SECRET_KEY=your_env_key yarn start

Docker container

$ docker-compose build
$ docker-compose up

Access http://localhost:3000 to see the application

QA

Feel free to open an issue on the repo.

koa-react-isomorphic's People

Contributors

hung-phan avatar jounqin avatar nqbao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

koa-react-isomorphic's Issues

When I update the title in `static-page`, content in browser not hot reload

Hi hung-phan,

In CLI, I start yarn run watch and yarn run dev, then I open the http://localhost:3000/ in Chrome browser.

When I do some change in share/components/static-page/index.jsx, I found the content not reload in browser, also from the Console, I found the Warning: [react-router] You cannot change ; it will be ignored.

Thanks.

Async actions

I saw section "Fetch data".
Still, can't understand how properly call async actions in this architecture.
For example, can you kindly explain, how to properly attach post request on the server, on the 'addTodo' action?

Hot reload cannot work

Hi,

Run npm run watch and npm run dev, and modified the /todos/todos-body/style.css(added color:red).
But, the hot reload cannot work, need to do a full reload.

image

image


After a full reload:
image

Some bugs in [email protected]

Hi,

  • del and debug are missing in package.json
# npm run watch
module.js:327
    throw err;
    ^
Error: Cannot find module 'del'
# ...
ERROR in ./app/server-app.js
Module not found: Error: Can't resolve 'debug' in '../koa-react-isomorphic/app'
 @ ./app/server-app.js 11:13-29
  • bugs with multi router in relay branch (SERVER_RENDERING=true npm run watch && npm run dev)
    • http://localhost:3000/test

      The content of div#app is replaced with empty.
      image

    • http://localhost:3000/

      The URL in the address bar is not changed after clicked the /test link on the home page.

// app/routes.js (add route: /test)
import Test from 'client/components/test';
//...
<Route path="/" component={Todos} queries={ViewerQuery} />
<Route path="/test" component={Test} />
// components/test/index.js (add component: test)
import React from 'react';
import { Link } from 'react-router';
const Test = () => (
  <div className="container">
      <Link to="/">Index</Link>
  </div>
);
export default Test;
// components/todos/index.js (add link: /test)
import { Link } from 'react-router';
// ...
<TodosBody viewer={viewer} />
<Link to="/test">test</Link>

Suggest add /test route by default.
Thanks :)

NPM installation failing

In a new, clean directory, npm i koa-react-isomorphic results in the following:

scripts/postinstall: line 1: [: =: unary operator expected
[...]/projects/koa-react-iso/inner
└─┬ [email protected]
  ├── UNMET PEER DEPENDENCY [email protected]
  ├─┬ [email protected]
  │ └── [email protected]  (git+http://ikt.pm2.io/ikt.git#3325a3e39a502418dc2e2e4bf21529cbbde96228)
  └── UNMET PEER DEPENDENCY [email protected]

npm WARN enoent ENOENT: no such file or directory, open '/Users/margaret.moser/Documents/projects/koa-react-iso/inner/package.json'
npm WARN [email protected] requires a peer of webpack@^1.4.0-beta6 but none was installed.
npm WARN [email protected] requires a peer of eslint@^2.9.0 but none was installed.
npm WARN [email protected] requires a peer of eslint@^2.9.0 but none was installed.
npm WARN [email protected] requires a peer of webpack@^1.9.11 but none was installed.
npm WARN [email protected] requires a peer of webpack@^1.9.11 but none was installed.
npm WARN [email protected] requires a peer of webpack@>=2.0.3-beta <3 but none was installed.

(Note, it's not complaining about parent directories anymore – that seems to have resolved after I deleted some files from parent directories.) The node_modules folder is created but no other koa-react-isomorphic files are present, including the package.json.

I don't think the unmet-peer messages are the root of the problem, but I do have [email protected] and [email protected] installed globally. I think I'm still getting the messages because of npm/npm#9857, but that doesn't explain why I'm not getting the rest of the files.

Not sure what's going on. I'll try installing from a git clone next and see what happens.

Bug with multi router when SERVER_RENDERING=true

// app/routes.js
// ...
<Route path='/' component={ Todos } />
<Route path='/test' component={ Test } />
SERVER_RENDERING=true npm run watch
npm run dev

http://localhost:3000/test always auto redirect to '/'.

Clear structure for koa.js app

I find very interesting document saying how we should structure the application for node.js app based. Have a look.

https://github.com/focusaurus/express_code_structure

Isomorphic (Universal) feature

Not sure if this is a bug or just overlooked behaviour. My understanding is that one of the reasons for isomorphic (Universal) applications is for screens to be served from server and clients even if javascript is disabled on browsers. I know the user might see a screen that is not functional as javascript is disabled and most of the functionality involves javascript (most of the time).
As of now if you disable javascript you won't see anything on any screen. My thinking is because of using jquery on document ready (I might be wrong).

So the question is, is this a valid and intended behaviour?

Integrate script for preload file

const fs = require('fs');
const manifest = require('../manifest.json');
const config = require('../config.json');
const configUpdated = Object.assign({}, config);

configUpdated.manifest = {
  js: manifestJs.assetsByChunkName.main,
};

configUpdated.routes = {};

manifestJs.chunks.forEach(chunk => {
  if ( chunk.entry === true ) {
    return;
  }

  const route = chunk.modules[0].name.match(
    /routes[/]([a-z][a-z-_/]+)[/]index.js$/
  );

  if ( route !== null ) {
    if ( route[1] === 'home' ) {
      configUpdated.routes['/'] = chunk.files[0];
    } else {
      configUpdated.routes[`/${route[1]}`] = chunk.files[0];
    }
  }
});

fs.writeFileSync(
  './config.json',
  JSON.stringify(configUpdated, null, 2)
);

webpack peerDependencies invalid

npm ERR! Linux 3.13.0-65-generic
npm ERR! argv "/usr/local/bin/node" "/usr/local/bin/npm" "install"
npm ERR! node v4.4.1
npm ERR! npm  v2.14.20
npm ERR! code EPEERINVALID

npm ERR! peerinvalid The package [email protected] does not satisfy its siblings' peerDependencies requirements!
npm ERR! peerinvalid Peer [email protected] wants webpack@1 || ^2.1.0-beta
npm ERR! peerinvalid Peer [email protected] wants webpack@^1.4.0-beta6
npm ERR! peerinvalid Peer [email protected] wants webpack@^1.9.11
npm ERR! peerinvalid Peer [email protected] wants webpack@^1.9.11
npm ERR! peerinvalid Peer [email protected] wants webpack@^1.12.6
npm ERR! peerinvalid Peer [email protected] wants webpack@>=2.0.3-beta <3

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.