Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthew Drake committed May 27, 2019
0 parents commit c7829d6
Show file tree
Hide file tree
Showing 24 changed files with 5,642 additions and 0 deletions.
59 changes: 59 additions & 0 deletions .babelrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const { NODE_ENV = 'development' } = process.env

const envServer = {
plugins: [],
presets: [
[
'@babel/preset-env',
{
'targets': {
'node': '8.11.3'
},
'useBuiltIns': false,
}
]
]
}

const envBrowser = {
plugins: [],
presets: [
[
'@babel/preset-env',
{
targets: {
browsers: [
'last 2 versions',
'safari >= 7',
'IE 8'
]
},
useBuiltIns: 'usage',
corejs: 3,
}
]
]
}

module.exports = function (api) {

const isWebpack = api.caller(caller => !!(caller && caller.name === 'babel-loader'))

api.cache.using(() => NODE_ENV)

const envConfig = isWebpack
? envBrowser
: envServer

return {
plugins: [
'@babel/plugin-proposal-object-rest-spread',
...envConfig.plugins,
],

presets: [
'@babel/preset-react',
...envConfig.presets,
],
}
}
2 changes: 2 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PORT=3000
WEBPACK_PORT=3010
33 changes: 33 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Github generate .gitignore for Node
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pids
*.pid
*.seed
*.pid.lock
lib-cov
coverage
.nyc_output
.grunt
bower_components
.lock-wscript
build/Release
node_modules/
jspm_packages/
typings/
.npm
.npmrc
.eslintcache
.node_repl_history
*.tgz
.yarn-integrity
.env
dist
stats
lib
out
.DS_Store
.env
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Another SSR Boilerplat

From the Riot Tech blog article on Universal Rendering.
52 changes: 52 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "another-ssr-boilerplate",
"version": "1.0.0",
"main": "index.js",
"author": "Matthew Drake <mdrake@riotgames.com>",
"license": "MIT",
"scripts": {
"postinstall": "node scripts/init",
"dev": "env-cmd run-p dev:*",
"dev:server": "nodemon src/start --exec \"babel-node\"",
"dev:client": "webpack-dev-server",
"clean": "rimraf dist lib",
"build": "yarn clean && env-cmd run-p build:*",
"build:server": "babel src --out-dir lib",
"build:client": "webpack",
"start": "node lib/start"
},
"dependencies": {
"axios": "^0.18.0",
"core-js": "^3.1.3",
"history": "^4.9.0",
"koa": "^2.7.0",
"koa-compose": "^4.1.0",
"koa-mount": "^4.0.0",
"koa-proxies": "^0.8.1",
"koa-router": "^7.4.0",
"koa-static": "^5.0.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-redux": "^7.1.0-alpha.5",
"react-router": "^5.0.0",
"react-router-dom": "^5.0.0",
"redux": "^4.0.1",
"redux-thunk": "^2.3.0"
},
"devDependencies": {
"@babel/cli": "^7.4.4",
"@babel/core": "^7.4.5",
"@babel/node": "^7.4.5",
"@babel/plugin-proposal-object-rest-spread": "^7.4.4",
"@babel/preset-env": "^7.4.5",
"@babel/preset-react": "^7.0.0",
"babel-loader": "^8.0.6",
"env-cmd": "^9.0.1",
"nodemon": "^1.19.1",
"npm-run-all": "^4.1.5",
"rimraf": "^2.6.3",
"webpack": "^4.32.2",
"webpack-cli": "^3.3.2",
"webpack-dev-server": "^3.4.1"
}
}
5 changes: 5 additions & 0 deletions scripts/init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const fs = require('fs')

if (!fs.existsSync(__dirname + '/../.env')) {
fs.copyFileSync(__dirname + '/../.env.template', __dirname + '/../.env')
}
25 changes: 25 additions & 0 deletions src/api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Router from 'koa-router'
import compose from 'koa-compose'
import mount from 'koa-mount'

const router = new Router()

router.get('/home', (ctx) => {
ctx.body = {
content: 'This is our home content. It was loaded from the server. Check src/api/index.js',
}
})

router.get('/about', async (ctx) => {
await new Promise(resolve => setTimeout(resolve, 2000))
ctx.body = {
content: 'This is our about section. It took two seconds to load.',
}
})

const middleware = compose([
router.allowedMethods(),
router.routes(),
])

export default mount('/api', middleware)
18 changes: 18 additions & 0 deletions src/app/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react'
import Routes from './Routes'
import { Router } from 'react-router'
import { Provider as ReduxProvider } from 'react-redux'

const App = (props) => {
const { store, history } = props
return (
<ReduxProvider store={store}>
<Router history={history}>
<Routes />
</Router>
</ReduxProvider>
)
}


export default App
52 changes: 52 additions & 0 deletions src/app/Routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react'
import { Switch, Route, matchPath } from 'react-router'
import Home from './scenes/Home'
import About from './scenes/About'
import NotFound from './scenes/NotFound'
import {
loadAbout,
loadHome,
} from './services/loaders'

const HOME = {
exact: true,
path: '/',
}

const ABOUT = {
path: '/about',
}

const noop = () => undefined

export const loadDataForLocation = prevLocation => async (
dispatch,
getState,
extras,
) => {
const { history } = extras
const { location } = history

if (prevLocation && prevLocation.pathname === location.pathname) {
return noop;
}

if (matchPath(location.pathname, HOME)) {
return dispatch(loadHome())
}
if (matchPath(location.pathname, ABOUT)) {
return dispatch(loadAbout())
}

return noop
}

const Routes = () => (
<Switch>
<Route {...HOME} component={Home} />
<Route {...ABOUT} component={About} />
<Route component={NotFound} />
</Switch>
)

export default Routes
27 changes: 27 additions & 0 deletions src/app/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react'
import ReactDOM from 'react-dom'
import { createBrowserHistory as createHistory } from 'history'
import App from './App'
import configureStore from './services/store'
import configureClient from './services/client'
import { loadDataForLocation } from './Routes'

const initialState = window.__REDUX_STATE__

const services = {}
services.history = createHistory()
services.client = configureClient({ baseURL: '/' }, () => services)
services.store = configureStore(initialState, services)

let prevLocation = null
services.history.listen((location) => {
// you really should put this inside your app
// that way you can catch errors, etc
services.store.dispatch(loadDataForLocation(prevLocation))
prevLocation = location
})

ReactDOM.hydrate(
<App {...services} />,
document.getElementById('react-container'),
)
17 changes: 17 additions & 0 deletions src/app/scenes/About.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react'
import { useSelector } from 'react-redux'
import Nav from '../shared/Nav'
import { selectAbout } from '../services/reducer'

const About = () => {
const { content } = useSelector(selectAbout)
return (
<div>
<Nav />
<h1>About</h1>
{content || 'Loading...'}
</div>
)
}

export default About
17 changes: 17 additions & 0 deletions src/app/scenes/Home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react'
import { useSelector } from 'react-redux'
import Nav from '../shared/Nav'
import { selectHome } from '../services/reducer'

const Home = () => {
const { content } = useSelector(selectHome)
return (
<div>
<Nav />
<h1>Home</h1>
{content || 'Loading...'}
</div>
)
}

export default Home
13 changes: 13 additions & 0 deletions src/app/scenes/NotFound.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react'
import Nav from '../shared/Nav'

const NotFound = () => {
return (
<div>
<Nav />
<h1>Not Found</h1>
</div>
)
}

export default NotFound
11 changes: 11 additions & 0 deletions src/app/services/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import axios from 'axios'

const createClient = (config, getServices) => {
const client = axios.create(Object.assign({}, config))

client.interceptors.request.use(config => Object.assign(config, getServices()))

return client
}

export default createClient
15 changes: 15 additions & 0 deletions src/app/services/loaders.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { setHome, setAbout } from './reducer'

export const loadHome = () => async (dispatch, getState, services) => {
setHome(null)
const { data } = await services.client('/api/home')
dispatch(setHome(data))
return data;
};

export const loadAbout = () => async (dispatch, getState, services) => {
setAbout(null)
const { data } = await services.client('/api/about')
dispatch(setAbout(data))
return data;
};
Loading

0 comments on commit c7829d6

Please sign in to comment.