Skip to content
This repository has been archived by the owner on Aug 5, 2022. It is now read-only.

Commit

Permalink
Week 7 typed ssr (#18)
Browse files Browse the repository at this point in the history
* Renames public folder to static

* Add next.js pages

* Update scripts and adds required libraries for ssr

* Add next.js related libraries

* Add utils/is-browser helper

* Add utils/kebab-case helper

* Add isBrowser checks before calling functions

* Add .next to the ignored files

* Remove macro import

* Add all ssr changes

* Remove demo file

* Replace components/PrivateRoute with PrivatePage

* Change to newer system to get styled components on server

* Replace window.location with Router.push

* Wrap content in PrivatePage component

* Remove unused code

* Remove Layout and unused code

* Update Readme

* Fix yarn.lock

* Fixed poor rebase :bida:
  • Loading branch information
Zaggen authored and dannytce committed May 5, 2019
1 parent a6968d1 commit bb8bf4c
Show file tree
Hide file tree
Showing 57 changed files with 1,593 additions and 4,444 deletions.
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["next/babel", "@zeit/next-typescript/babel"]
}
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/coverage

# production
/build
/.next

# misc
.DS_Store
Expand Down
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"typescript.tsdk": "node_modules/typescript/lib"
}
17 changes: 17 additions & 0 deletions lectures/09-ssr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# SSR

- [Presentation & Video](https://drive.google.com/drive/u/1/folders/134MBLY7YBzsv2KLG4lEhm6gMtoZQVINF)

## Homework (Optional)

- Convert your codebase into SSR using STRV branch as reference
- Remove `react-create-scripts`
- Add `next` and related libraries (`@zeit/next-css`, `@zeit/next-typescript`, `express`, `isomorphic-fetch`, `next-redux-wrapper`, `@types/next`)
- Adjusts scripts section of your `package.js` to work with next instead of `react-create-scripts`, check the one defined in the project for reference.
- Replace `useApi` hook usage on products and products details with `getInitialProps`, you could either set the data in redux or show it
right away as the hook did.
- If you are feeling like a ninja, implement the loading status in case you decide to go with the redux approach.

## Aditional info

- https://github.com/zeit/next.js/
4 changes: 4 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const withCSS = require('@zeit/next-css')
const withTypescript = require('@zeit/next-typescript')

module.exports = withTypescript(withCSS())
18 changes: 12 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
"version": "0.1.0",
"private": true,
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"start": "NODE_ENV=production node server/index.js",
"build": "next build",
"dev": "node server/index.js",
"format": "prettier --write '*/**/*.{js,css,md,json}'",
"lint:js": "eslint --ext .js,.ts,.tsx . --ignore-path .gitignore --fix",
"type-check": "tsc --skipLibCheck",
"lint:css": "stylelint 'src/**/*.js'",
"type-check": "tsc --skipLibCheck",
"cypress:open": "cypress open"
},
"jest": {
Expand Down Expand Up @@ -53,15 +52,20 @@
"not op_mini all"
],
"dependencies": {
"@zeit/next-css": "^1.0.1",
"@zeit/next-typescript": "^1.1.1",
"express": "^4.16.4",
"formik": "^1.5.2",
"isomorphic-fetch": "^2.2.1",
"next": "^8.1.0",
"next-redux-wrapper": "^3.0.0-alpha.2",
"qs": "^6.7.0",
"ramda": "^0.26.1",
"react": "^16.8.4",
"react-dom": "^16.8.4",
"react-redux": "^6.0.1",
"react-router": "^5.0.0",
"react-router-dom": "^5.0.0",
"react-scripts": "2.1.8",
"react-toastify": "^5.1.0",
"redux": "^4.0.1",
"redux-thunk": "^2.3.0",
Expand All @@ -75,6 +79,7 @@
"@strv/eslint-config-typescript": "^1.0.4",
"@strv/stylelint-config-styled-components": "^1.0.0",
"@types/jest": "^24.0.11",
"@types/next": "^8.0.5",
"@types/node": "^11.13.8",
"@types/react": "^16.8.14",
"@types/react-dom": "^16.8.4",
Expand All @@ -83,6 +88,7 @@
"@types/styled-components": "^4.1.14",
"@typescript-eslint/parser": "^1.7.0",
"cypress": "^3.2.0",
"eslint": "^5.16.0",
"eslint-config-prettier": "^4.1.0",
"eslint-plugin-cypress": "^2.2.1",
"eslint-plugin-react-hooks": "^1.6.0",
Expand Down
1 change: 1 addition & 0 deletions pages/_app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from '../src/App'
54 changes: 54 additions & 0 deletions pages/_document.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react'
import Document, { Head, Main, NextScript } from 'next/document'
import { ServerStyleSheet } from 'styled-components'

class CustomDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage

try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props => sheet.collectStyles(<App {...props} />),
})

const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
}
} finally {
sheet.seal()
}
}

render() {
return (
<html lang="en">
<Head>
<meta charSet="utf-8" />
<link rel="shortcut icon" href="/static/favicon.ico" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="/static/manifest.json" />
</Head>

<body>
<Main />
<NextScript />
</body>
</html>
)
}
}

export default CustomDocument
15 changes: 15 additions & 0 deletions pages/_error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react'
import { NotFound } from '../src/pages/NotFound'

class Error extends React.Component {
static getInitialProps({ res, err }) {
const statusCode = res ? res.statusCode : err ? err.statusCode : null
return { statusCode }
}

render() {
return <NotFound />
}
}

export default Error
3 changes: 3 additions & 0 deletions pages/account.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Account } from '../src/pages/Account'

export default Account
3 changes: 3 additions & 0 deletions pages/cart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Cart } from '../src/pages/Cart'

export default Cart
3 changes: 3 additions & 0 deletions pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { ProductList } from '../src/pages/ProductList'

export default ProductList
3 changes: 3 additions & 0 deletions pages/login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { LogIn } from '../src/pages/LogIn'

export default LogIn
3 changes: 3 additions & 0 deletions pages/logout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Logout } from '../src/pages/Logout'

export default Logout
3 changes: 3 additions & 0 deletions pages/product.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { ProductDetail } from '../src/pages/ProductDetail'

export default ProductDetail
3 changes: 3 additions & 0 deletions pages/products.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { ProductList } from '../src/pages/ProductList'

export default ProductList
3 changes: 3 additions & 0 deletions pages/signup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { SignUp } from '../src/pages/SignUp'

export default SignUp
41 changes: 0 additions & 41 deletions public/index.html

This file was deleted.

33 changes: 33 additions & 0 deletions server/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* eslint-env node */
const express = require('express')
const next = require('next')

const PORT = process.env.PORT || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app
.prepare()
.then(() => {
const server = express()

server.get('/products/:id/:name', (req, res) => {
return app.render(req, res, '/product', req.params)
})

server.get('*', (req, res) => {
return handle(req, res)
})

server.listen(PORT, err => {
if (err) {
throw err
}
console.log('> Ready on http://localhost:' + PORT) // eslint-disable-line no-console
})
})
.catch(ex => {
console.error(ex.stack)
process.exit(1)
})
69 changes: 32 additions & 37 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,51 +1,46 @@
import React from 'react'
import { Switch, Route, Redirect } from 'react-router-dom'
import App, { Container } from 'next/app'
import { Provider } from 'react-redux'
import withRedux from 'next-redux-wrapper'
import { ToastContainer, toast } from 'react-toastify'

import Layout from './components/Layout'
import GlobalStyles from './globalStyles'
import { ProductList } from './pages/ProductList'
import { ProductDetail } from './pages/ProductDetail'
import { Cart } from './pages/Cart'
import { SignUp } from './pages/SignUp'
import { LogIn } from './pages/LogIn'
import { Logout } from './pages/Logout'
import { Account } from './pages/Account'
import { NotFound } from './pages/NotFound'
import { PrivateRoute } from './components/PrivateRoute'
import { ErrorBoundary } from './components/ErrorBoundary'
import { getCustomer } from './utils/customer'
import { configureStore } from './store'
import * as routes from './routes'

const defaultStore = configureStore({
customer: getCustomer(),
})
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
let pageProps = {}
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx)
}

const App = ({ store }) => (
<Provider store={store || defaultStore}>
<React.Fragment>
<GlobalStyles />
<ToastContainer position={toast.POSITION.BOTTOM_RIGHT} />
<ErrorBoundary>
<Switch>
<Route
path={routes.HOMEPAGE}
exact
render={() => <Redirect to={routes.PRODUCT_LIST} />}
/>
<Route path={routes.PRODUCT_LIST} exact component={ProductList} />
<Route path={routes.PRODUCT_DETAIL} component={ProductDetail} />
<Route path={routes.CART} component={Cart} />
<Route path={routes.SIGN_UP} component={SignUp} />
<Route path={routes.LOGIN} component={LogIn} />
<Route path={routes.LOGOUT} component={Logout} />
<PrivateRoute path={routes.ACCOUNT} component={Account} />
<Route component={NotFound} />
</Switch>
</ErrorBoundary>
</React.Fragment>
</Provider>
)
return { pageProps }
}

export { App }
render() {
const { Component, pageProps } = this.props
return (
<Container>
<Provider store={this.props.store}>
<React.Fragment>
<GlobalStyles />
<ToastContainer position={toast.POSITION.BOTTOM_RIGHT} />
<ErrorBoundary>
<Layout>
<Component {...pageProps} />
</Layout>
</ErrorBoundary>
</React.Fragment>
</Provider>
</Container>
)
}
}

export default withRedux(configureStore)(MyApp)
4 changes: 3 additions & 1 deletion src/api/api-client.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/* eslint-disable no-constant-condition */
/* eslint-disable no-await-in-loop */
import fetch from 'isomorphic-fetch'
import Router from 'next/router'

import config from '../config'
import { LOGOUT } from '../routes'
Expand Down Expand Up @@ -46,7 +48,7 @@ export const api = async (url, options) => {
// Here is a place to handle special cases
// CASE: second 401 we need to logout
if (response && response.status === 401) {
window.location.assign(LOGOUT)
Router.push(LOGOUT)
}

// If everything went fine just return the result
Expand Down
2 changes: 1 addition & 1 deletion src/components/Button/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import styled from 'styled-components/macro'
import styled from 'styled-components'
import theme from '../../common/theme'

const Button = styled.button`
Expand Down
Loading

0 comments on commit bb8bf4c

Please sign in to comment.