diff --git a/.babelrc b/.babelrc index 8b3e3f8..a8bd1bb 100644 --- a/.babelrc +++ b/.babelrc @@ -5,9 +5,10 @@ ], "plugins": [ "react-hot-loader/babel", + "transform-es2015-modules-commonjs", "transform-class-properties", "transform-decorators", - "transform-object-rest-spread", - ["resolver", { "resolveDirs": ["common"] }] + "transform-export-extensions", + "transform-object-rest-spread" ] } diff --git a/.gitignore b/.gitignore index 239ee66..c2ae5c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,12 @@ +npm-error.log .env node_modules npm-debug.log* .DS_Store # ignore built static files -dist/ -webpack-assets.json +/dist +/webpack-assets.json + +# webpack-built server files +server/renderer/*.built.js diff --git a/README.md b/README.md index 65b82a5..590e337 100644 --- a/README.md +++ b/README.md @@ -11,20 +11,15 @@ promise that future updates will not break your existing application.** ## Get started -Install [yarn](https://github.com/yarnpkg/yarn) if you don't have it already: -``` -npm install -g yarn -``` - -Then copy environment variables and edit them if necessary: +Copy environment variables and edit them if necessary: ``` cp .env.example .env ``` Then: ``` -yarn install -yarn start +npm install +npm start ``` Direct your browser to `http://localhost:3000`. @@ -32,10 +27,14 @@ Direct your browser to `http://localhost:3000`. For production builds: ``` -yarn run prod:start +npm run prod:build +npm run serve ``` -Note: pm2 must be installed to run production builds. +For Heroku, simply add a `Procfile`: +``` +web: npm run serve +``` ## Directory Structure ``` @@ -93,13 +92,13 @@ Make sure you have it installed: npm install -g mocha ``` -Tests should reside alongside the component/module/selector/etc that it is -testing. For example: +Tests should reside in `test/spec` in their appropriate folders: ``` -├── reducers -│   ├── todos.js -│   ├── todos.test.js +├── test +│   ├── spec +│   │   ├── api +│   │   │   ├── todos.test.js ``` Tests can be written with ES2015, since it passes through `babel-register`. diff --git a/client/index.js b/client/index.js index 4838cce..693b893 100644 --- a/client/index.js +++ b/client/index.js @@ -10,12 +10,6 @@ import App from 'containers/App'; const history = createHistory(); -/* Images - * This space is reserved for images that are required by server rendering, - * e.g. the favicon and any other images that need to be in the base HTML file. - */ -import '../common/images/favicon.png'; - // The root element of your app const rootElement = document.getElementById('app'); @@ -25,7 +19,7 @@ const initialState = window.__INITIAL_STATE__; const store = configureStore(initialState, history); const render = (Component) => { - ReactDOM.render( + ReactDOM.hydrate( diff --git a/common/css/_functions.scss b/common/css/_functions.scss deleted file mode 100644 index 18463fe..0000000 --- a/common/css/_functions.scss +++ /dev/null @@ -1 +0,0 @@ -/* Import or define any sass mixins and functions below */ diff --git a/common/css/_variables.scss b/common/css/_variables.scss deleted file mode 100644 index fce00e2..0000000 --- a/common/css/_variables.scss +++ /dev/null @@ -1 +0,0 @@ -// Variables, like colors and widths/heights here. diff --git a/common/css/base/_fonts.scss b/common/css/base/_fonts.scss new file mode 100644 index 0000000..6c38f26 --- /dev/null +++ b/common/css/base/_fonts.scss @@ -0,0 +1,2 @@ +// Import fonts here, from google, or whereever. +@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,600'); diff --git a/common/css/base/_overrides.scss b/common/css/base/_overrides.scss new file mode 100644 index 0000000..e69de29 diff --git a/common/css/base/_styles.scss b/common/css/base/_styles.scss new file mode 100644 index 0000000..248579b --- /dev/null +++ b/common/css/base/_styles.scss @@ -0,0 +1,19 @@ +html, body { + height: 100%; + font-family: 'Open Sans', sans-serif; + + p { + font-size: 16px; + line-height: 24px; + } +} + +body { + background-color: $white; +} + +#app { + height: 100%; + width: 100%; + margin: 0 auto; +} diff --git a/common/css/base/_vendors.scss b/common/css/base/_vendors.scss new file mode 100644 index 0000000..f0e1a5b --- /dev/null +++ b/common/css/base/_vendors.scss @@ -0,0 +1,9 @@ +// Import bootstrap-sass as needed +$bootstrap-sass-asset-helper: true; +@import "~bootstrap-sass/assets/stylesheets/bootstrap/variables"; + +$screen-lg-min: $app-max-width !global; +$container-lg: $app-max-width !global; + +@import "~bootstrap-sass/assets/stylesheets/bootstrap/mixins"; +@import "~bootstrap-sass/assets/stylesheets/bootstrap/grid"; diff --git a/common/css/base/index.scss b/common/css/base/index.scss new file mode 100644 index 0000000..f79f228 --- /dev/null +++ b/common/css/base/index.scss @@ -0,0 +1,9 @@ +// Vendors and resource files (.e.g. variables, mixins, etc) +@import '../resources/variables'; +@import 'vendors'; +@import '../resources/mixins'; + +// The following are non-vendor, non-resource files. +@import 'fonts'; +@import 'overrides'; +@import 'styles'; diff --git a/common/css/resources/_colors.scss b/common/css/resources/_colors.scss new file mode 100644 index 0000000..546db39 --- /dev/null +++ b/common/css/resources/_colors.scss @@ -0,0 +1,2 @@ +$white: #fff; +$dark-gray: #333; diff --git a/common/css/resources/_mixins.scss b/common/css/resources/_mixins.scss new file mode 100644 index 0000000..e69de29 diff --git a/common/css/resources/_variables.scss b/common/css/resources/_variables.scss new file mode 100644 index 0000000..e69de29 diff --git a/common/css/_vendors.scss b/common/css/resources/_vendors.scss similarity index 100% rename from common/css/_vendors.scss rename to common/css/resources/_vendors.scss diff --git a/common/js/actions/todos.js b/common/js/actions/todos.js index dabcfa8..632728f 100644 --- a/common/js/actions/todos.js +++ b/common/js/actions/todos.js @@ -2,8 +2,8 @@ import { ADD_TODO, REMOVE_TODO, TOGGLE_TODO, FETCH_TODOS_REQUEST, FETCH_TODOS_SUCCESS, FETCH_TODOS_FAILURE } from 'constants/index'; -import { fetch } from 'lib/api'; -import generateActionCreator from 'lib/generateActionCreator'; +import api from 'helper/api'; +import generateActionCreator from 'helper/generateActionCreator'; export const addTodo = generateActionCreator(ADD_TODO, 'text'); export const removeTodo = generateActionCreator(REMOVE_TODO, 'id'); @@ -14,15 +14,19 @@ export const fetchTodosSuccess = generateActionCreator(FETCH_TODOS_SUCCESS, 'tod export const fetchTodosFailure = generateActionCreator(FETCH_TODOS_FAILURE, 'error'); export const fetchTodos = () => { - return async (dispatch) => { + return (dispatch) => { dispatch(fetchTodosRequest()); - try { - const response = await fetch('/api/todos', { method: 'GET' }); - const todos = await response.json(); - dispatch(fetchTodosSuccess(todos)); - } catch (e) { - dispatch(fetchTodosFailure(e.message)); - } + return api.get('/api/todos') + .then(todos => { + dispatch(fetchTodosSuccess(todos)); + + return Promise.resolve(todos); + }) + .catch(error => { + dispatch(fetchTodosFailure(error)); + + return Promise.reject(error); + }); }; }; diff --git a/common/js/components/ErrorPage/index.js b/common/js/components/common/ErrorPage/index.js similarity index 100% rename from common/js/components/ErrorPage/index.js rename to common/js/components/common/ErrorPage/index.js diff --git a/common/js/components/Footer/index.js b/common/js/components/common/Footer/index.js similarity index 100% rename from common/js/components/Footer/index.js rename to common/js/components/common/Footer/index.js diff --git a/common/js/components/Header/index.js b/common/js/components/common/Header/index.js similarity index 100% rename from common/js/components/Header/index.js rename to common/js/components/common/Header/index.js diff --git a/common/js/components/common/RouteWithSubRoutes/index.js b/common/js/components/common/RouteWithSubRoutes/index.js new file mode 100644 index 0000000..339de9e --- /dev/null +++ b/common/js/components/common/RouteWithSubRoutes/index.js @@ -0,0 +1,31 @@ +import React from 'react'; +import { Route } from 'react-router'; + +const RouteWithSubRoutes = props => { + const { + path, + computedMatch, + component: Component, + routes, + restProps + } = props; + + return ( + { + // pass the sub-routes down to keep nesting + return ( + + ); + }} + /> + ); +}; + +export default RouteWithSubRoutes; diff --git a/common/js/components/common/index.js b/common/js/components/common/index.js new file mode 100644 index 0000000..5b01228 --- /dev/null +++ b/common/js/components/common/index.js @@ -0,0 +1,4 @@ +export { default as ErrorPage } from './ErrorPage'; +export { default as Footer } from './Footer'; +export { default as Header } from './Header'; +export { default as RouteWithSubRoutes } from './RouteWithSubRoutes'; diff --git a/common/js/containers/App/index.js b/common/js/containers/App/index.js index dfe15a4..3e466e7 100644 --- a/common/js/containers/App/index.js +++ b/common/js/containers/App/index.js @@ -1,15 +1,17 @@ import React from 'react'; -import { Switch, Route } from 'react-router-dom'; +import { Switch } from 'react-router-dom'; +import { RouteWithSubRoutes } from 'components/common'; import { Container } from 'semantic-ui-react'; -import Header from 'components/Header'; -import Footer from 'components/Footer'; +import { Header, Footer } from 'components/common'; import routes from 'routes'; const App = () => (
- {routes.map(route => )} + {routes.map(route => ( + + ))}