├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── README.md ├── apptime.config.dev.js ├── apptime.config.prod.js ├── client ├── components │ ├── App.js │ ├── App.styl │ ├── favicon.ico │ └── react-logo.png ├── index.js ├── lib │ └── vars.styl └── routes.js ├── docker-compose.yml ├── package.json ├── scripts └── generate-nginx-conf.js ├── template.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // You can also add 'zen/flow' if you want Flow linting support 3 | extends: ['zen/base', 'zen/react'], 4 | }; 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.DS_Store 3 | build/ 4 | .tmp/ 5 | nginx.conf 6 | npm-debug.log 7 | .idea 8 | node_modules.bak 9 | my-site.conf 10 | .apptime 11 | TODO.md 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ⚠️ **UNMAINTAINED** ⚠️ This project is no longer maintained because I've found [Gatsby](https://www.gatsbyjs.org/) does everything I originally wanted and more. So feel free to use/fork this project, but it is no longer under active development. 2 | 3 | --- 4 | 5 | ![React Static Boilerplate](http://dropsinn.s3.amazonaws.com/Screen%20Shot%202016-01-03%20at%208.39.55%20PM.png) 6 | 7 | # React Static Boilerplate 8 | 9 | A boilerplate for building static sites with [Webpack][], [React][] and [React Router][]. 10 | 11 | **Quick Start:** 12 | 13 | * `git clone https://github.com/iansinnott/react-static-boilerplate my-static-site` 14 | * `cd my-static-site && rm -rf .git` 15 | * `npm install` 16 | * `npm start` to run a dev server 17 | * Write an awesome client-side app... 18 | * `npm run build` to minify, package and generate static HTML files from your routes 19 | 20 | Now you're all set to deploy to your favorite hosting solution :beers: 21 | 22 | To check your production build use pushstate-server 23 | `npm install pushstate-server -g` 24 | `pushstate-server build` 25 | 26 | **NOTE:** It's important to run `npm run build` and **not** `npm build`. The latter will silently exit because it is a native NPM command. 27 | 28 | ## Changes Jan 2017 29 | 30 | Webpack 2 was just released. In celebration, here are some fun new features: 31 | 32 | * Dev tooling is a dependency! It is no longer part of this repo. This means future upgrades will be a breeze. 33 | * Support for Webpack 2 34 | * Fully mocked client side environment, so code that requires the DOM/BOM should still compile 35 | * Support for [webpack-dashbaord][] + improved dev server logging (`npm run start:dashboard`) 36 | * Asset fingerprinting to make long-term caching a breeze (Adds hash to output files. Ex `app.72266bec.js`) 37 | * Analyze the size of your bundle [webpack-bundle-analyzer plugin][] (`npm run build:analyze`. See screenshot below of output below) 38 | 39 | [webpack-bundle-analyzer plugin]: https://github.com/th0r/webpack-bundle-analyzer 40 | [webpack-dashbaord]: https://github.com/FormidableLabs/webpack-dashboard 41 | 42 | ## Usage Commands 43 | 44 | **`npm run start`**: Start a dev server 45 | 46 | **`npm run start:dashboard`**: Start a dev server with Webpack Dashboard 47 | 48 | **`npm run build`**: Compile, minify and fingerprint everything and create static files from routes 49 | 50 | **`npm run build:analyze`**: Same as above, but will also output `webpack-bundle-analyzer-stats.json` and `webpack-bundle-analyzer-report.html` for you to analyze. Open the HTML file in a web browser to analyze the bundle. Or from the CLI: 51 | 52 | ``` 53 | open build/webpack-bundle-analyzer-report.html 54 | ``` 55 | 56 | **`npm run eject`**: This project uses another project of mine, [app-time][], to run builds. That means all the nasty webpack config stuff is hidden away. But sometimes you really just need to customize the hell out of the build process so if you need to you can run this command to remove the app-time dependency and bring all the config files into your own project. This cannot be undone once you've made changes to the config, but if you do change your mind before modifying any code you can always revert: 57 | 58 | ``` 59 | git checkout . 60 | rm -rf apptime 61 | ``` 62 | 63 | [app-time]: https://github.com/iansinnott/app-time/ 64 | 65 | ![webpack-bundle-analyzer](http://dropsinn.s3.amazonaws.com/Screen%20Shot%202017-01-18%20at%2012.05.15%20PM.png) 66 | 67 | ## Project Goals 68 | 69 | * A single source of truth: Your routes 70 | * Intuitive. Leverage existing front-end knowledge 71 | * Awesome developer experience 72 | * Flexible. No file structure or naming conventions required. Use whatever modules you want 73 | 74 | ## Dynamic Routes 75 | 76 | **Important Note:** This boilerplate does not yet support generating static sites for dynamic routes such as `post/:id`. That's the next major feature addition (see the [Roadmap below](#roadmap)) but it hasn't been implemented yet. 77 | 78 | For more info see [this issue on the react-static-webpack-plugin repo](https://github.com/iansinnott/react-static-webpack-plugin/issues/2). 79 | 80 | ## Opinionated styling 81 | 82 | This boilerplate is slightly opinionated, especially when it comes to CSS. Don't worry, you can easily change any of this but by default I use [Stylus][] and [CSS Modules][] for compiling CSS. 83 | 84 | ### Stylus 85 | 86 | There is certainly no need to use Stylus for styling your static pages. Use whatever you like best. But Stylus does support standard CSS syntax so if you don't want to set up anything new just start writing CSS in any of the `*.styl` files and watch it compile as expected :satisfied: 87 | 88 | This boilerplate uses Stylus for page styling by default. It's pretty simple to swap out stylus for Sass, Less or even plain CSS. Just update the Webpack config files (both `webpack.config.dev.js` and `webpack.config.prod.js`) to use your loader of choice. If you're not sure how to do this check out the [Webpack loaders documentation](https://webpack.github.io/docs/loaders.html). 89 | 90 | ### CSS Modules 91 | 92 | CSS Modules are provided as part of the css-loader itself. For more info check out the [CSS Loader docs][css-loader-modules]. If you haven't heard of CSS Modules check out [GitHub repo][CSS Modules]. Basically it lets you write styles local to any component or file. In my experience it makes styling much more pleasant and much less error prone. 93 | 94 | Of course **if you don't want to use this feature you don't have to.** 95 | 96 | To disable CSS modules you just need to replace to Webpack config lines for dev and prod: 97 | 98 | ```js 99 | // webpack.config.dev.js 100 | 101 | // Replace this... 102 | 'css?modules&importLoaders=2&localIdentName=[name]__[local]__[hash:base64:6]', 103 | 104 | // ...with this. 105 | 'css', 106 | ``` 107 | 108 | ```js 109 | // webpack.config.prod.js 110 | 111 | // Replace this... 112 | loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=2!autoprefixer!stylus'), 113 | 114 | // ...with this. 115 | loader: ExtractTextPlugin.extract('style', 'css!autoprefixer!stylus'), 116 | ``` 117 | 118 | 119 | ## Serving static files 120 | 121 | This project will generate all the static files you need to server a full, production-ready website. However your server will likely need some configuration so that it maps the same URLs React Router uses to actual static files. For example, the "about" page might have the following URL according to React Router: `/about`. 122 | 123 | However, a static server without any configuration would see the URL `/about` and return a 404 because it expects a URL of `/about.html` to actually server the file. There are many ways to handle this on different systems. Here is how you might handle it with Nginx. 124 | 125 | ### Nginx 126 | 127 | This project contains a script to help generate a usable Nginx config. To run it: 128 | 129 | ``` 130 | npm run -s conf 131 | ``` 132 | 133 | This will output the config to stdout. Redirect it as you see fit to save it to disk: 134 | 135 | ``` 136 | npm run -s conf > my-site.conf 137 | ``` 138 | 139 | Once you've saved the file you can sym link it into place and reload Nginx. This is just an example, your path to Nginx will vary based on system: 140 | 141 | ``` 142 | ln -s $PWD/my-site.conf /path/to/nginx/conf-files/static-fun.conf 143 | nginx -s reload 144 | ``` 145 | 146 | ### Testing the static site with Docker 147 | 148 | First, make sure you [have Docker installed](https://www.docker.com/products/docker-toolbox) and running on your system. Then proceed. 149 | 150 | This repository includes a Docker Compose config file for quickly setting up an Nginx server to test your static site. To run it, simply run: 151 | 152 | ``` 153 | npm run -s conf > nginx.conf 154 | docker-compose up 155 | ``` 156 | 157 | Now run `docker ps` to get the IP address and port where the container is running. If you're using Docker Machine this will likely be something like `192.168.99.100:8080`. 158 | 159 | ### Testing the static site with Nginx on a Mac 160 | 161 | If you don't have Nginx yet install it with `brew`: 162 | 163 | ``` 164 | brew install nginx 165 | ``` 166 | 167 | Now generate an Nginx config file using the script in this project: 168 | 169 | ``` 170 | npm run -s conf > nginx.conf 171 | ``` 172 | 173 | Then link that file we just created in to the global Nginx config file and reload Nginx: 174 | 175 | ``` 176 | mkdir -p /usr/local/etc/nginx/servers 177 | ln -s $PWD/nginx.conf /usr/local/etc/nginx/servers/static-fun.conf 178 | nginx -s reload 179 | ``` 180 | 181 | ## Technology Used 182 | 183 | For further reading on the primary tech used in this boilerplate see the links below: 184 | 185 | * [Webpack][] 186 | * [Babel][] 187 | * [React][] 188 | * [React Router][] 189 | * [Stylus][] 190 | * [CSS Modules][] 191 | 192 | ## Roadmap 193 | 194 | - [x] Add [Docker Compose][] to run a production-like server on demand for manual testing 195 | - [x] Add readme docs for testing a prod site with Docker and Docker compose 196 | - [ ] Support for [dynamic content](https://github.com/iansinnott/react-static-webpack-plugin/issues/2) 197 | - [ ] Leverage code splitting for efficient bundling and async module loading 198 | - [ ] Improved SVG tooling 199 | 200 | ## Redux 201 | 202 | Redux is supported. Just be sure to tell the plugin where to find your store so that it can be passed through a `` during the static rendering. You can configure this in `apptime.config.prod.js` using the `ReactStaticPlugin` configuration function: 203 | 204 | ```js 205 | // apptime.config.prod.js 206 | module.exports = (config, apptime) => ({ 207 | ...config, // Base config 208 | 209 | ...apptime.ReactStaticPlugin({ 210 | routes: './client/routes.js', 211 | reduxStore: './client/redux/store.js', // Add redux store 212 | template: './template.js', 213 | }), 214 | }); 215 | ``` 216 | 217 | ```js 218 | // ./client/store.js 219 | import { createStore } from 'redux'; 220 | 221 | import someReducer from '../reducers'; 222 | 223 | const store = createStore(someReducer); 224 | 225 | export default store; 226 | ``` 227 | 228 | 👉 [Go here for a full working Redux example.](https://github.com/iansinnott/react-static-webpack-plugin/blob/master/example/redux/webpack.config.prod.js#L45) 229 | 230 | ## Troubleshooting 231 | 232 | ### Babel Env 233 | 234 | Make sure `BABEL_ENV` is not set to `development` when building. If it is babel will likely throw a hot module replacement error since HMR transformations are getting run on everything that goes through babel. 235 | 236 | ### Font Awesome Webpack 237 | 238 | The `font-awesome-webpack` module does not seem to work with the approach of generating files as UMD modules then requiring them from the public dir. It throws an error about window not being defined. 239 | 240 | [React]: http://facebook.github.io/react/ 241 | [Webpack]: https://webpack.js.org/ 242 | [Babel]: https://babeljs.io/ 243 | [Stylus]: https://learnboost.github.io/stylus/ 244 | [CSS Modules]: https://github.com/css-modules/css-modules 245 | [css-loader-modules]: https://github.com/webpack/css-loader#css-modules 246 | [Express]: http://expressjs.com/ 247 | [Waterline]: https://github.com/balderdashy/waterline 248 | [Flux]: https://facebook.github.io/flux/docs/overview.html 249 | [React Router]: https://github.com/rackt/react-router 250 | [Redux]: https://github.com/rackt/redux 251 | [Docker Compose]: https://docs.docker.com/compose/ 252 | -------------------------------------------------------------------------------- /apptime.config.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file allows you to customize how the app is built in development mode. 3 | * By default all we do is modify the entry point to include normalize.css and 4 | * font-awesome. Feel free to remove them if you don't want/need them. 5 | * 6 | * NOTE: This file is completely optional, but it's likely that you will want to 7 | * customize certain things about the build process at some point so it is 8 | * provided for you here. Furthermore, if you wish to completely opt-out of all 9 | * defaults you can simply not make use of the `config` passed in to the 10 | * function and return a full webpack config of your own making. 11 | */ 12 | module.exports = (config, apptime) => ({ 13 | ...config, 14 | entry: { 15 | app: [ 16 | 'normalize.css', 17 | 'font-awesome/css/font-awesome.css', 18 | apptime.hmrEntry, 19 | './client/index.js', 20 | ], 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /apptime.config.prod.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file allows you to customize how the app is built in development mode. 3 | * By default all we do is modify the entry point to include normalize.css and 4 | * font-awesome. Feel free to remove them if you don't want/need them. 5 | * 6 | * NOTE: This file is completely optional, but it's likely that you will want to 7 | * customize certain things about the build process at some point so it is 8 | * provided for you here. Furthermore, if you wish to completely opt-out of all 9 | * defaults you can simply not make use of the `config` passed in to the 10 | * function and return a full webpack config of your own making. 11 | */ 12 | module.exports = (config, apptime) => ({ 13 | ...config, 14 | 15 | //// If you need to wrap your compiled pages in a redux store before render you 16 | //// can use this option 17 | // 18 | // ...apptime.ReactStaticPlugin({ 19 | // routes: './client/routes.js', 20 | // template: './template.js', 21 | // reduxStore: './client/store.js', 22 | // }), 23 | 24 | entry: { 25 | ...config.entry, // Make sure the vendor entry point is included 26 | app: [ 27 | 'normalize.css', 28 | 'font-awesome/css/font-awesome.css', 29 | apptime.polyfill, 30 | './client/index.js', 31 | ], 32 | }, 33 | }); 34 | -------------------------------------------------------------------------------- /client/components/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import T from 'prop-types'; 3 | import { Link, IndexLink } from 'react-router'; 4 | import classnames from 'classnames/bind'; 5 | 6 | // Using CSS Modules so we assign the styles to a variable 7 | import s from './App.styl'; 8 | const cx = classnames.bind(s); 9 | import logo from './react-logo.png'; 10 | 11 | // Favicon link is in the template, this just makes webpack package it up for us 12 | import './favicon.ico'; 13 | 14 | export class Home extends React.Component { 15 | render() { 16 | return ( 17 |
18 |
19 | React Logo 20 |

React Static Boilerplate

21 |
22 |

Why React static?

23 | 28 |
29 | ); 30 | } 31 | } 32 | 33 | export class About extends React.Component { 34 | render() { 35 | return ( 36 |
37 |
38 |

About Page

39 |
40 |

Welcome to the about page...

41 |
42 | ); 43 | } 44 | } 45 | 46 | export class NotFound extends React.Component { 47 | render() { 48 | return ( 49 |
50 |

Not found

51 |
52 | ); 53 | } 54 | } 55 | 56 | /** 57 | * NOTE: As of 2015-11-09 react-transform does not support a functional 58 | * component as the base compoenent that's passed to ReactDOM.render, so we 59 | * still use createClass here. 60 | */ 61 | export class App extends React.Component { 62 | static propTypes = { 63 | children: T.node, 64 | }; 65 | 66 | render() { 67 | return ( 68 |
69 | 73 | {this.props.children} 74 |
75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /client/components/App.styl: -------------------------------------------------------------------------------- 1 | @require '../lib/vars.styl' 2 | 3 | * 4 | box-sizing border-box 5 | 6 | body 7 | background react-blue 8 | font-family helvetica 9 | color darken(white, 10%) 10 | font-size 18px 11 | 12 | h1 13 | margin 20px 0 14 | 15 | pre 16 | font-family mono 17 | line-height 1.5 18 | border-radius 3px 19 | border 1px solid border-gray 20 | 21 | .page 22 | padding 20px 23 | 24 | .siteTitle 25 | display flex 26 | align-items center 27 | 28 | +below(420px) 29 | display block 30 | 31 | img 32 | display inline-block 33 | width 80px 34 | height 80px 35 | margin-right 20px 36 | 37 | +below(420px) 38 | display block 39 | margin 0 auto 40 | 41 | .hl 42 | font-weight bold 43 | color react-blue 44 | .App 45 | background black 46 | min-width 320px 47 | 48 | h1 49 | color react-blue 50 | font-weight 300 51 | font-size 52px 52 | 53 | p 54 | color white 55 | 56 | .nav 57 | background darken(black, 10%) 58 | padding-left 20px 59 | 60 | a 61 | display inline-block 62 | padding 20px 63 | text-transform uppercase 64 | text-decoration none 65 | color darken(white, 20%) 66 | &:hover 67 | color white 68 | 69 | .active 70 | background black 71 | 72 | -------------------------------------------------------------------------------- /client/components/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iansinnott/react-static-boilerplate/56781cec6a8a87e8feb07e04340cafff36133d93/client/components/favicon.ico -------------------------------------------------------------------------------- /client/components/react-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iansinnott/react-static-boilerplate/56781cec6a8a87e8feb07e04340cafff36133d93/client/components/react-logo.png -------------------------------------------------------------------------------- /client/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import { Router, browserHistory } from 'react-router'; 4 | 5 | // Import your routes so that you can pass them to the component 6 | import routes from './routes.js'; 7 | 8 | render(( 9 | 10 | ), document.getElementById('root')); 11 | -------------------------------------------------------------------------------- /client/lib/vars.styl: -------------------------------------------------------------------------------- 1 | mono = Consolas, 'Liberation Mono', Menlo, Courier, monospace 2 | helvetica = 'Helvetica Neue', Helvetica, Arial, sans-serif 3 | js-yellow = #f5da55 4 | react-blue = #00d8ff 5 | black = #333 6 | 7 | // Use with inputs / buttons you don't want users to interact with 8 | uninteractive() 9 | user-select none 10 | pointer-events none 11 | cursor not-allowed 12 | -------------------------------------------------------------------------------- /client/routes.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Route, IndexRoute } from 'react-router'; 3 | 4 | import { App, About, Home, NotFound } from './components/App.js'; 5 | 6 | export const routes = ( 7 | 8 | 9 | 10 | 11 | 12 | ); 13 | 14 | export default routes; 15 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # This Docker Compose config will get a full static site up and running on nginx 2 | # quickly so you can test out how the site will run on a real server. 3 | static: 4 | image: nginx:1.9 5 | ports: 6 | - "8080:80" 7 | - "8443:443" 8 | volumes: 9 | - "./nginx.conf:/etc/nginx/nginx.conf" 10 | - "./public:/var/www/html" 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-static-boilerplate", 3 | "version": "3.1.2", 4 | "description": "A boilerplate for building static sites with React and React Router", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/iansinnott/react-static-boilerplate" 8 | }, 9 | "bugs": { 10 | "url": "https://github.com/iansinnott/react-static-boilerplate/issues" 11 | }, 12 | "author": "Ian Sinnott (http://iansinnott.com)", 13 | "license": "MIT", 14 | "homepage": "", 15 | "devDependencies": { 16 | "app-time": "^0.10.2", 17 | "babel-eslint": "^7.1.1", 18 | "cross-env": "^3.1.3", 19 | "eslint": "^3.11.1", 20 | "eslint-config-zen": "^2.0.0", 21 | "eslint-plugin-flowtype": "^2.29.1", 22 | "eslint-plugin-react": "^6.8.0", 23 | "rimraf": "^2.5.2" 24 | }, 25 | "dependencies": { 26 | "classnames": "^2.2.5", 27 | "font-awesome": "^4.7.0", 28 | "history": "^4.5.0", 29 | "normalize.css": "^5.0.0", 30 | "prop-types": "^15.5.8", 31 | "react": "^15.1.0 || ^16.0.0 || ^17.0.0", 32 | "react-dom": "^15.1.0 || ^16.0.0 || ^17.0.0", 33 | "react-router": "^3.0.0" 34 | }, 35 | "apptime": { 36 | "vendorLibs": [ 37 | "core-js", 38 | "classnames", 39 | "history", 40 | "react", 41 | "react-dom", 42 | "react-router" 43 | ] 44 | }, 45 | "scripts": { 46 | "postinstall": "app-time setup", 47 | "start": "app-time start", 48 | "start:dashboard": "app-time start --dashboard", 49 | "prebuild": "rimraf build", 50 | "build": "app-time build", 51 | "build:analyze": "app-time build --analyze", 52 | "eject": "app-time eject", 53 | "lint": "eslint client", 54 | "conf": "node ./scripts/generate-nginx-conf.js", 55 | "test": "echo 'No tests specified.'", 56 | "preversion": "npm test", 57 | "postversion": "git push && git push --tags", 58 | "bump:patch": "npm version patch -m \"v%s\"", 59 | "bump:minor": "npm version minor -m \"v%s\"", 60 | "bump:major": "npm version major -m \"v%s\"", 61 | "bump": "npm run bump:patch" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /scripts/generate-nginx-conf.js: -------------------------------------------------------------------------------- 1 | console.log( 2 | `# NOTE: This file uses the nginx.conf from the official nginx docker image as a 3 | # starting point. Feel free to customize as you see fit, but remember things may 4 | # break if you change configurations you aren't familiar with. 5 | # 6 | # NOTE: Although we don't define it here, this container will be run 7 | # non-daemonized so that docker can manage the process. The official nginx 8 | # container specifies the non daemon option on its own so adding it here will 9 | # cause a duplication error when you try to run nginx. 10 | 11 | user nginx; 12 | worker_processes 1; 13 | 14 | error_log /var/log/nginx/error.log warn; 15 | pid /var/run/nginx.pid; 16 | 17 | 18 | events { 19 | worker_connections 1024; 20 | } 21 | 22 | 23 | http { 24 | include /etc/nginx/mime.types; 25 | default_type application/octet-stream; 26 | 27 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 28 | '$status $body_bytes_sent "$http_referer" ' 29 | '"$http_user_agent" "$http_x_forwarded_for"'; 30 | 31 | access_log /var/log/nginx/access.log main; 32 | 33 | sendfile on; 34 | #tcp_nopush on; 35 | 36 | keepalive_timeout 65; 37 | 38 | # CUSTOM CONFIG 39 | # This is how we host our static React site. 40 | server { 41 | 42 | # Listen on this port. This would be 80 or 443 on a prod server. Adjust this 43 | # to suit your own needs. 44 | listen 80; 45 | 46 | # Server base URL goes here if applicable 47 | #server_name trustar.co; 48 | 49 | location / { 50 | 51 | # Enable gzip. NOTE: text/html files are always gzipped when enabled 52 | gzip on; 53 | gzip_min_length 1000; 54 | gzip_types text/plain text/css application/javascript application/json image/x-icon; 55 | 56 | # The location of the static files to server 57 | root /var/www/html; 58 | 59 | # Remove trailing slashes. /about/ -> /about 60 | # This is important because of how static files are generated. 61 | rewrite ^/(.*)/$ /$1 permanent; 62 | 63 | # If migrating from a dynamic site you may want to redirect requests to a 64 | # certain path to a different server. This example redirects all traffic 65 | # to /blog to blog.example.com 66 | #rewrite ^/blog(.*)$ $scheme://blog.example.com$1 redirect; 67 | 68 | # Use 404.html as the error page 69 | error_page 404 /404.html; 70 | 71 | # If a matching file can't be found, handle this request as a 404, which 72 | # will return the 404 page because of the above directive 73 | try_files $uri $uri.html $uri/index.html =404; 74 | 75 | } 76 | 77 | } 78 | }` 79 | ); 80 | -------------------------------------------------------------------------------- /template.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/no-danger */ 2 | const React = require('react'); 3 | const T = require('prop-types'); 4 | 5 | const Html = ({ title = 'Amazing Default Title', body, manifest }) => { 6 | return ( 7 | 8 | 9 | 10 | 11 | 12 | {title} 13 | 14 | 15 | {/* If you have a favicon file you can add by modifying the next line */} 16 | {/* */} 17 | 18 | 19 |
20 |