commit 7388190d8100c79d4c33f05149156db3ddcae2d7
parent d1b98c9b2e8816dbed6b5bd652bdcbec7deeeb9c
Author: Konstantin Tarkus <hello@tarkus.me>
Date: Thu, 24 Sep 2015 04:56:32 +0300
Update npm modules; remove lodash; create Html (shell) component
Diffstat:
9 files changed, 105 insertions(+), 85 deletions(-)
diff --git a/README.md b/README.md
@@ -17,15 +17,15 @@ Join [#react-starter-kit](https://gitter.im/kriasoft/react-starter-kit) chatroom
### Documentation
- * **General**
- - [React Style Guide](./docs/react-style-guide.md)
- - [How to configure text editors and IDEs](./docs/how-to-configure-text-editors.md)
- * **Questions**
- - [Which module bundler should I use?](https://github.com/kriasoft/react-starter-kit/issues/3)
- - [Which Flux implementation should I use?](https://github.com/kriasoft/react-starter-kit/issues/22)
- * **Recipes**
- - [How to Implement Routing and Navigation](./docs/recipes/how-to-implement-routing.md)
- - [How to Integrate Disqus](./docs/recipes/how-to-integrate-disqus.md)
+ * **General**
+ - [React Style Guide](./docs/react-style-guide.md)
+ - [How to configure text editors and IDEs](./docs/how-to-configure-text-editors.md)
+ * **Questions**
+ - [Which module bundler should I use?](https://github.com/kriasoft/react-starter-kit/issues/3)
+ - [Which Flux implementation should I use?](https://github.com/kriasoft/react-starter-kit/issues/22)
+ * **Recipes**
+ - [How to Implement Routing and Navigation](./docs/recipes/how-to-implement-routing.md)
+ - [How to Integrate Disqus](./docs/recipes/how-to-integrate-disqus.md)
### Directory Layout
@@ -35,8 +35,8 @@ Join [#react-starter-kit](https://gitter.im/kriasoft/react-starter-kit) chatroom
├── /docs/ # Documentation files for the project
├── /node_modules/ # 3rd-party libraries and utilities
├── /src/ # The source code of the application
-│ ├── /api/ # REST API / Relay endpoints
│ ├── /actions/ # Action creators that allow to trigger a dispatch to stores
+│ ├── /api/ # REST API / Relay endpoints
│ ├── /components/ # React components
│ ├── /constants/ # Constants (action types etc.)
│ ├── /content/ # Static content (plain HTML or Markdown, Jade, you name it)
@@ -44,9 +44,10 @@ Join [#react-starter-kit](https://gitter.im/kriasoft/react-starter-kit) chatroom
│ ├── /decorators/ # Higher-order React components
│ ├── /public/ # Static files which are copied into the /build/public folder
│ ├── /stores/ # Stores contain the application state and logic
-│ ├── /templates/ # HTML templates for server-side rendering, emails etc.
│ ├── /utils/ # Utility classes and functions
│ ├── /app.js # Client-side startup script
+│ ├── /config.js # Global application settings
+│ ├── /routes.js # Universal (isomorphic) application routes
│ └── /server.js # Server-side startup script
├── /tools/ # Build automation scripts and utilities
│ ├── /lib/ # Library for utility snippets
@@ -64,8 +65,7 @@ Join [#react-starter-kit](https://gitter.im/kriasoft/react-starter-kit) chatroom
### Getting Started
-Just [clone](github-windows://openRepo/https://github.com/kriasoft/react-starter-kit) or
-[fork](https://github.com/kriasoft/react-starter-kit/fork) the repo and start hacking:
+Just clone the repo and start hacking:
```shell
$ git clone -o react-starter-kit -b master --single-branch \
@@ -127,33 +127,29 @@ Test any javascript module by creating a `__tests__/` directory where
the file is. Name the test by appending `-test.js` to the js file.
[Jest](https://facebook.github.io/jest/) will do the rest.
-### Customizations
-
- * [Azure deployment](https://github.com/kriasoft/react-starter-kit/pull/106)
-
### Related Projects
- * [React Static Boilerplate](https://github.com/koistya/react-static-boilerplate) — Generates a static website from React components
- * [Babel Starter Kit](https://github.com/kriasoft/babel-starter-kit) — A boilerplate for authoring JavaScript/React.js libraries
- * [React Decorators](https://github.com/kriasoft/react-decorators) — A collection of higher-order React components
+ * [React Static Boilerplate](https://github.com/koistya/react-static-boilerplate) — Generates a static website from React components
+ * [Babel Starter Kit](https://github.com/kriasoft/babel-starter-kit) — A boilerplate for authoring JavaScript/React.js libraries
+ * [React Decorators](https://github.com/kriasoft/react-decorators) — A collection of higher-order React components
### Learn More
- * [Getting Started with React.js](http://facebook.github.io/react/)
- * [React.js Wiki on GitHub](https://github.com/facebook/react/wiki)
- * [React.js Questions on StackOverflow](http://stackoverflow.com/questions/tagged/reactjs)
- * [React.js Discussion Board](https://discuss.reactjs.org/)
- * [Flux Architecture for Building User Interfaces](http://facebook.github.io/flux/)
- * [Jest - Painless Unit Testing](http://facebook.github.io/jest/)
- * [Flow - A static type checker for JavaScript](http://flowtype.org/)
- * [The Future of React](https://github.com/reactjs/react-future)
- * [Learn ES6](https://babeljs.io/docs/learn-es6/), [ES6 Features](https://github.com/lukehoban/es6features#readme)
+ * [Getting Started with React.js](http://facebook.github.io/react/)
+ * [Getting Started with GraphQL and Relay](https://quip.com/oLxzA1gTsJsE)
+ * [React.js Questions on StackOverflow](http://stackoverflow.com/questions/tagged/reactjs)
+ * [React.js Discussion Board](https://discuss.reactjs.org/)
+ * [Flux Architecture for Building User Interfaces](http://facebook.github.io/flux/)
+ * [Jest - Painless Unit Testing](http://facebook.github.io/jest/)
+ * [Flow - A static type checker for JavaScript](http://flowtype.org/)
+ * [The Future of React](https://github.com/reactjs/react-future)
+ * [Learn ES6](https://babeljs.io/docs/learn-es6/), [ES6 Features](https://github.com/lukehoban/es6features#readme)
### Support
- * [#react-starter-kit](https://gitter.im/kriasoft/react-starter-kit) on Gitter
- * [Live help sessions](http://start.thinkful.com/react/?utm_source=github&utm_medium=badge&utm_campaign=react-starter-kit) on Thinkful
- * [@koistya](https://www.codementor.io/koistya) on Codementor
+ * [#react-starter-kit](https://gitter.im/kriasoft/react-starter-kit) on Gitter — Feedback, feature requests, Q&A
+ * [@koistya](https://www.codementor.io/koistya) on Codementor — Mentorship, code reviews
+ * support@kriasoft.com — Customization requests, help with GraphQL/Relay back-ends etc.
### License
diff --git a/package.json b/package.json
@@ -14,9 +14,8 @@
"fbjs": "0.2.1",
"flux": "2.1.1",
"front-matter": "1.0.0",
- "history": "1.9.1",
+ "history": "1.10.1",
"jade": "1.11.0",
- "lodash": "3.10.1",
"normalize.css": "3.0.3",
"react": "0.14.0-rc1",
"react-dom": "0.14.0-rc1",
@@ -28,11 +27,11 @@
"autoprefixer": "^6.0.3",
"babel-eslint": "^4.1.3",
"babel-loader": "^5.3.2",
- "browser-sync": "^2.9.3",
- "css-loader": "^0.18.0",
+ "browser-sync": "^2.9.6",
+ "css-loader": "^0.19.0",
"csscomb": "^3.1.8",
"del": "^2.0.2",
- "eslint": "^1.5.0",
+ "eslint": "^1.5.1",
"eslint-config-airbnb": "0.0.8",
"eslint-loader": "^1.0.0",
"eslint-plugin-react": "^3.4.2",
@@ -41,9 +40,10 @@
"glob": "^5.0.14",
"jest-cli": "^0.5.7",
"jscs": "^2.1.1",
+ "lodash.merge": "^3.3.2",
"mkdirp": "^0.5.1",
"ncp": "^2.0.0",
- "postcss": "^5.0.5",
+ "postcss": "^5.0.6",
"postcss-cssnext": "^2.1.0",
"postcss-import": "^7.0.0",
"postcss-loader": "^0.6.0",
diff --git a/src/components/Html/Html.js b/src/components/Html/Html.js
@@ -0,0 +1,55 @@
+/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */
+
+import React, { Component, PropTypes } from 'react';
+import { googleAnalyticsId } from '../../config';
+
+class Html extends Component {
+
+ static propTypes = {
+ title: PropTypes.string,
+ description: PropTypes.string,
+ css: PropTypes.string,
+ body: PropTypes.string.isRequired,
+ };
+
+ static defaultProps = {
+ title: '',
+ description: '',
+ };
+
+ goolgeAnalytics() {
+ // TODO: Change UA-XXXXX-X to be your site's ID.
+ return ({__html:
+ `(function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=` +
+ `function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date;` +
+ `e=o.createElement(i);r=o.getElementsByTagName(i)[0];` +
+ `e.src='https://www.google-analytics.com/analytics.js';` +
+ `r.parentNode.insertBefore(e,r)}(window,document,'script','ga'));` +
+ `ga('create','${googleAnalyticsId}','auto');ga('send','pageview');`,
+ });
+ }
+
+ render() {
+ return (
+ <html className="no-js" lang="">
+ <head>
+ <meta charSet="utf-8" />
+ <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
+ <title>{this.props.title}</title>
+ <meta name="description" content={this.props.description} />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <link rel="apple-touch-icon" href="apple-touch-icon.png" />
+ <style id="css" dangerouslySetInnerHTML={{__html: this.props.css}} />
+ </head>
+ <body>
+ <div id="app" dangerouslySetInnerHTML={{__html: this.props.body}} />
+ <script src="/app.js"></script>
+ <script dangerouslySetInnerHTML={this.goolgeAnalytics()} />
+ </body>
+ </html>
+ );
+ }
+
+}
+
+export default Html;
diff --git a/src/components/Html/package.json b/src/components/Html/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "Html",
+ "version": "0.0.0",
+ "private": true,
+ "main": "./Html.js"
+}
diff --git a/src/config.js b/src/config.js
@@ -0,0 +1,5 @@
+/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */
+
+export default {
+ googleAnalyticsId: 'UA-XXXXX-X',
+};
diff --git a/src/server.js b/src/server.js
@@ -1,12 +1,12 @@
/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */
import 'babel/polyfill';
-import _ from 'lodash';
-import fs from 'fs';
import path from 'path';
import express from 'express';
+import React from 'react';
import ReactDOM from 'react-dom/server';
import Router from './routes';
+import Html from './components/Html';
const server = global.server = express();
@@ -21,11 +21,6 @@ server.use('/api/content', require('./api/content'));
//
// Register server-side rendering middleware
// -----------------------------------------------------------------------------
-
-// The top-level React component + HTML template for it
-const templateFile = path.join(__dirname, 'templates/index.html');
-const template = _.template(fs.readFileSync(templateFile, 'utf8'));
-
server.get('*', async (req, res, next) => {
try {
let statusCode = 200;
@@ -43,8 +38,8 @@ server.get('*', async (req, res, next) => {
data.css = css.join('');
});
- const html = template(data);
- res.status(statusCode).send(html);
+ const html = ReactDOM.renderToStaticMarkup(<Html {...data} />);
+ res.status(statusCode).send('<!doctype html>\n' + html);
} catch (err) {
next(err);
}
diff --git a/src/templates/index.html b/src/templates/index.html
@@ -1,28 +0,0 @@
-<!doctype html>
-<html class="no-js" lang="">
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
- <title><%- title %></title>
- <meta name="description" content="<%- description %>">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="apple-touch-icon" href="apple-touch-icon.png">
- <style id="css"><%= css %></style>
- </head>
- <body>
- <!--[if lt IE 8]>
- <p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
- <![endif]-->
- <div id="app"><%= body %></div>
- <script src="/app.js"></script>
- <!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
- <script>
- (function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=
- function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date;
- e=o.createElement(i);r=o.getElementsByTagName(i)[0];
- e.src='//www.google-analytics.com/analytics.js';
- r.parentNode.insertBefore(e,r)}(window,document,'script','ga'));
- ga('create','UA-XXXXX-X', 'auto');ga('send','pageview');
- </script>
- </body>
-</html>
diff --git a/tools/config.js b/tools/config.js
@@ -9,7 +9,7 @@
import path from 'path';
import webpack, { DefinePlugin, BannerPlugin } from 'webpack';
-import merge from 'lodash/object/merge';
+import merge from 'lodash.merge';
const DEBUG = !process.argv.includes('release');
const VERBOSE = process.argv.includes('verbose');
diff --git a/tools/copy.js b/tools/copy.js
@@ -19,18 +19,9 @@ import watch from './lib/watch';
export default async () => {
console.log('copy');
await Promise.all([
-
- // Static files
copy('src/public', 'build/public'),
-
- // Files with content (e.g. *.md files)
copy('src/content', 'build/content'),
-
- // Website and email templates
- copy('src/templates', 'build/templates'),
-
copy('package.json', 'build/package.json'),
-
]);
replace({