commit 2fe7a9c40bbc22a3d28b83e21cf558b54078de3f
parent a17c01f7200c68970ddf7f2ed5c2dd6d1e1bbb5a
Author: Konstantin Tarkus <hello@tarkus.me>
Date: Sun, 5 Oct 2014 14:34:00 +0400
Add pre-rendering at compile-time. Issue #4
Diffstat:
10 files changed, 178 insertions(+), 148 deletions(-)
diff --git a/gulpfile.js b/gulpfile.js
@@ -87,14 +87,16 @@ gulp.task('images', function () {
// HTML pages
gulp.task('pages', function () {
- src.pages = 'src/pages/**/*.html';
+ src.pages = ['src/pages/**/*.jsx', 'src/pages/404.html'];
return gulp.src(src.pages)
- .pipe($.changed(DEST))
+ .pipe($.changed(DEST, {extension: '.html'}))
+ .pipe($.if('*.jsx', $.render({template: './src/pages/_template.html'})))
+ .pipe($.replace('UA-XXXXX-X', GOOGLE_ANALYTICS_ID))
.pipe($.if(RELEASE, $.htmlmin({
removeComments: true,
collapseWhitespace: true,
minifyJS: true
- })))
+ }), $.jsbeautifier()))
.pipe(gulp.dest(DEST))
.pipe($.size({title: 'pages'}));
});
@@ -150,6 +152,8 @@ gulp.task('build', ['clean'], function (cb) {
// Launch a lightweight HTTP Server
gulp.task('serve', function (cb) {
+ var url = require('url');
+ var fs = require('fs');
watch = true;
runSequence('build', function () {
@@ -161,7 +165,19 @@ gulp.task('serve', function (cb) {
// Note: this uses an unsigned certificate which on first access
// will present a certificate warning in the browser.
// https: true,
- server: DEST
+ server: {
+ baseDir: DEST,
+ // Allow web page requests without .html file extension in URLs
+ middleware: function (req, res, cb) {
+ var uri = url.parse(req.url);
+ if (uri.pathname.length > 1 &&
+ path.extname(uri.pathname) === '' &&
+ fs.existsSync(DEST + uri.pathname + '.html')) {
+ req.url = uri.pathname + '.html' + (uri.search || '');
+ }
+ cb();
+ }
+ }
});
gulp.watch(src.assets, ['assets']);
diff --git a/package.json b/package.json
@@ -15,7 +15,7 @@
"browser-sync": "^1.5.2",
"del": "^0.1.3",
"gulp": "^3.8.8",
- "gulp-autoprefixer": "1.0.1",
+ "gulp-autoprefixer": "^1.0.1",
"gulp-cache": "^0.2.2",
"gulp-changed": "^1.0.0",
"gulp-csscomb": "^3.0.2",
@@ -23,11 +23,14 @@
"gulp-htmlmin": "^0.2.0",
"gulp-if": "^1.2.4",
"gulp-imagemin": "^1.0.1",
+ "gulp-jsbeautifier": "^0.0.3",
"gulp-jshint": "^1.8.5",
"gulp-less": "^1.3.6",
"gulp-load-plugins": "^0.6.0",
"gulp-minify-css": "^0.3.10",
"gulp-plumber": "^0.6.5",
+ "gulp-render": "^0.0.2",
+ "gulp-replace": "^0.4.0",
"gulp-size": "^1.1.0",
"gulp-uglify": "^1.0.1",
"gulp-util": "^3.0.1",
diff --git a/src/App.js b/src/App.js
@@ -4,17 +4,19 @@ var React = require('react');
var {Router} = require('director');
var AppDispatcher = require('./AppDispatcher');
var ActionTypes = require('./constants/ActionTypes');
+var HomePage = require('./pages/Index.jsx');
// Export React so the dev tools can find it
(window !== window.top ? window.top : window).React = React;
function render(component) {
React.renderComponent(component(), document.body);
+ document.title = component.defaultProps.title || HomePage.defaultProps.title;
}
var routes = {
- '/': () => render(require('./pages/HomePage.jsx')),
- '/privacy': () => render(require('./pages/PrivacyPage.jsx'))
+ '/': () => render(HomePage),
+ '/privacy': () => render(require('./pages/Privacy.jsx'))
};
var router = new Router(routes).configure({html5history: true}).init();
diff --git a/src/components/Link.jsx b/src/components/Link.jsx
@@ -9,8 +9,7 @@ var RouteActions = require('../actions/RouteActions');
var Link = React.createClass({
propTypes: {
- to: React.PropTypes.string.isRequired,
- children: React.PropTypes.component.isRequired
+ to: React.PropTypes.string.isRequired
},
render() {
this.props.href =
diff --git a/src/pages/HomePage.jsx b/src/pages/HomePage.jsx
@@ -1,49 +0,0 @@
-/**
- * @jsx React.DOM
- */
-
-'use strict';
-
-var React = require('react');
-var DefaultLayout = require('../layouts/DefaultLayout.jsx');
-
-var HomePage = React.createClass({
- render() {
- return (
- <DefaultLayout>
- <div className="container">
- <div className="row">
- <div className="col-sm-4">
- <h3>Runtime Components</h3>
- <dl>
- <dt><a href="https://facebook.github.io/react/">React</a></dt>
- <dd>A JavaScript library for building user interfaces, developed by Facebook</dd>
- <dt><a href="https://github.com/rackt/react-router">React-Router</a></dt>
- <dd>A complete routing library for React</dd>
- <dt><a href="http://getbootstrap.com/">Bootstrap</a></dt>
- <dd>CSS framework for developing responsive, mobile first interfaces</dd>
- </dl>
- </div>
- <div className="col-sm-4">
- <h3>Development Tools</h3>
- <dl>
- <dt><a href="http://gulpjs.com">Gulp</a></dt>
- <dd>JavaScript streaming build system and task automation</dd>
- <dt><a href="http://webpack.github.io/">Webpack</a></dt>
- <dd>Compiles front-end source code into modules / bundles</dd>
- <dt><a href="http://www.browsersync.io/">BrowserSync</a></dt>
- <dd>A lightweight HTTP server for development</dd>
- </dl>
- </div>
- <div className="col-sm-4">
- <h3>Fork me on GitHub</h3>
- <p><a href="https://github.com/kriasoft/react-starter-kit">github.com/kriasoft/react-starter-kit</a></p>
- </div>
- </div>
- </div>
- </DefaultLayout>
- );
- }
-});
-
-module.exports = HomePage;
diff --git a/src/pages/Index.jsx b/src/pages/Index.jsx
@@ -0,0 +1,55 @@
+/**
+ * @jsx React.DOM
+ */
+
+'use strict';
+
+var React = require('react');
+var DefaultLayout = require('../layouts/DefaultLayout.jsx');
+
+var HomePage = React.createClass({
+ getDefaultProps() {
+ return {
+ title: 'React.js Starter Kit',
+ description: 'A skeleton for a web application built with Facebook\'s React.js Library'
+ };
+ },
+ render() {
+ return (
+ <DefaultLayout title={this.props.title}>
+ <div className="container">
+ <div className="row">
+ <div className="col-sm-4">
+ <h3>Runtime Components</h3>
+ <dl>
+ <dt><a href="https://facebook.github.io/react/">React</a></dt>
+ <dd>A JavaScript library for building user interfaces, developed by Facebook</dd>
+ <dt><a href="https://github.com/rackt/react-router">React-Router</a></dt>
+ <dd>A complete routing library for React</dd>
+ <dt><a href="http://getbootstrap.com/">Bootstrap</a></dt>
+ <dd>CSS framework for developing responsive, mobile first interfaces</dd>
+ </dl>
+ </div>
+ <div className="col-sm-4">
+ <h3>Development Tools</h3>
+ <dl>
+ <dt><a href="http://gulpjs.com">Gulp</a></dt>
+ <dd>JavaScript streaming build system and task automation</dd>
+ <dt><a href="http://webpack.github.io/">Webpack</a></dt>
+ <dd>Compiles front-end source code into modules / bundles</dd>
+ <dt><a href="http://www.browsersync.io/">BrowserSync</a></dt>
+ <dd>A lightweight HTTP server for development</dd>
+ </dl>
+ </div>
+ <div className="col-sm-4">
+ <h3>Fork me on GitHub</h3>
+ <p><a href="https://github.com/kriasoft/react-starter-kit">github.com/kriasoft/react-starter-kit</a></p>
+ </div>
+ </div>
+ </div>
+ </DefaultLayout>
+ );
+ }
+});
+
+module.exports = HomePage;
diff --git a/src/pages/Privacy.jsx b/src/pages/Privacy.jsx
@@ -0,0 +1,67 @@
+/**
+ * @jsx React.DOM
+ */
+
+'use strict';
+
+var React = require('react');
+var DefaultLayout = require('../layouts/DefaultLayout.jsx');
+
+var PrivacyPage = React.createClass({
+ getDefaultProps() {
+ return {
+ title: 'Privacy Policy'
+ };
+ },
+ render() {
+ return (
+ <DefaultLayout title={this.props.title}>
+ <div className="container">
+ <h2>{this.props.title}</h2>
+ <p>
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean consequat tortor fermentum mi
+ fermentum dignissim. Nullam vel ipsum ut ligula elementum lobortis. Maecenas aliquam, massa laoreet
+ lacinia pretium, nisi urna venenatis tortor, nec imperdiet tellus libero efficitur metus. Fusce
+ semper posuere ligula, et facilisis metus bibendum interdum. Mauris at mauris sit amet sem pharetra
+ commodo a eu leo. Nam at est non risus cursus maximus. Nam feugiat augue libero, id consectetur
+ tortor bibendum non. Quisque nec fringilla lorem. Nullam efficitur vulputate mauris, nec maximus leo
+ dignissim id.
+ </p>
+ <p>
+ In hac habitasse platea dictumst. Duis sagittis dui ac ex suscipit maximus. Morbi pellentesque
+ venenatis felis sed convallis. Nulla varius, nibh vitae placerat tempus, mauris sem elementum ipsum,
+ eget sollicitudin nisl est vel purus. Fusce malesuada odio velit, non cursus leo fermentum id. Cras
+ pharetra sodales fringilla. Etiam quis est a dolor egestas pellentesque. Maecenas non scelerisque
+ purus, congue cursus arcu. Donec vel dapibus mi. Mauris maximus posuere placerat. Sed et libero eu
+ nibh tristique mollis a eget lectus. Donec interdum augue sollicitudin vehicula hendrerit. Vivamus
+ justo orci, molestie ac sollicitudin ac, lobortis at tellus. Etiam rhoncus ullamcorper risus eu
+ tempor. Sed porttitor, neque ac efficitur gravida, arcu lacus pharetra dui, in consequat elit tellus
+ auctor nulla. Donec placerat elementum diam, vitae imperdiet lectus luctus at.
+ </p>
+ <p>
+ Nullam eu feugiat mi. Quisque nec tristique nisl, dignissim dictum leo. Nam non quam nisi. Donec
+ rutrum turpis ac diam blandit, id pulvinar mauris suscipit. Pellentesque tincidunt libero ultricies
+ risus iaculis, sit amet consequat velit blandit. Fusce quis varius nulla. Nullam nisi nisi, suscipit
+ ut magna quis, feugiat porta nibh. Sed id enim lectus. Suspendisse elementum justo sapien, sit amet
+ consequat orci accumsan et. Aliquam ornare ullamcorper sem sed finibus. Nullam ac lacus pulvinar,
+ egestas felis ut, accumsan est.
+ </p>
+ <p>
+ Pellentesque sagittis vehicula sem quis luctus. Proin sodales magna in lorem hendrerit aliquam.
+ Integer eu varius orci. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
+ cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia
+ Curae; Ut at mauris nibh. Suspendisse maximus ac eros at vestibulum.
+ </p>
+ <p>
+ Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque egestas tortor et dui
+ consequat faucibus. Nunc vitae odio ornare, venenatis ligula a, vulputate nisl. Aenean congue varius
+ ex, sit amet bibendum odio posuere at. Nulla facilisi. In finibus, nulla vitae tincidunt ornare,
+ sapien nulla fermentum mauris, sed consectetur tortor arcu eget arcu. Vestibulum vel quam enim.
+ </p>
+ </div>
+ </DefaultLayout>
+ );
+ }
+});
+
+module.exports = PrivacyPage;
diff --git a/src/pages/PrivacyPage.jsx b/src/pages/PrivacyPage.jsx
@@ -1,62 +0,0 @@
-/**
- * @jsx React.DOM
- */
-
-'use strict';
-
-var React = require('react');
-var DefaultLayout = require('../layouts/DefaultLayout.jsx');
-
-var PrivacyPage = React.createClass({
- render() {
- return (
- <DefaultLayout>
- <div className="container">
- <h2>Privacy Policy</h2>
- <p>
- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean consequat tortor fermentum mi
- fermentum dignissim. Nullam vel ipsum ut ligula elementum lobortis. Maecenas aliquam, massa laoreet
- lacinia pretium, nisi urna venenatis tortor, nec imperdiet tellus libero efficitur metus. Fusce
- semper posuere ligula, et facilisis metus bibendum interdum. Mauris at mauris sit amet sem pharetra
- commodo a eu leo. Nam at est non risus cursus maximus. Nam feugiat augue libero, id consectetur
- tortor bibendum non. Quisque nec fringilla lorem. Nullam efficitur vulputate mauris, nec maximus leo
- dignissim id.
- </p>
- <p>
- In hac habitasse platea dictumst. Duis sagittis dui ac ex suscipit maximus. Morbi pellentesque
- venenatis felis sed convallis. Nulla varius, nibh vitae placerat tempus, mauris sem elementum ipsum,
- eget sollicitudin nisl est vel purus. Fusce malesuada odio velit, non cursus leo fermentum id. Cras
- pharetra sodales fringilla. Etiam quis est a dolor egestas pellentesque. Maecenas non scelerisque
- purus, congue cursus arcu. Donec vel dapibus mi. Mauris maximus posuere placerat. Sed et libero eu
- nibh tristique mollis a eget lectus. Donec interdum augue sollicitudin vehicula hendrerit. Vivamus
- justo orci, molestie ac sollicitudin ac, lobortis at tellus. Etiam rhoncus ullamcorper risus eu
- tempor. Sed porttitor, neque ac efficitur gravida, arcu lacus pharetra dui, in consequat elit tellus
- auctor nulla. Donec placerat elementum diam, vitae imperdiet lectus luctus at.
- </p>
- <p>
- Nullam eu feugiat mi. Quisque nec tristique nisl, dignissim dictum leo. Nam non quam nisi. Donec
- rutrum turpis ac diam blandit, id pulvinar mauris suscipit. Pellentesque tincidunt libero ultricies
- risus iaculis, sit amet consequat velit blandit. Fusce quis varius nulla. Nullam nisi nisi, suscipit
- ut magna quis, feugiat porta nibh. Sed id enim lectus. Suspendisse elementum justo sapien, sit amet
- consequat orci accumsan et. Aliquam ornare ullamcorper sem sed finibus. Nullam ac lacus pulvinar,
- egestas felis ut, accumsan est.
- </p>
- <p>
- Pellentesque sagittis vehicula sem quis luctus. Proin sodales magna in lorem hendrerit aliquam.
- Integer eu varius orci. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
- cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia
- Curae; Ut at mauris nibh. Suspendisse maximus ac eros at vestibulum.
- </p>
- <p>
- Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque egestas tortor et dui
- consequat faucibus. Nunc vitae odio ornare, venenatis ligula a, vulputate nisl. Aenean congue varius
- ex, sit amet bibendum odio posuere at. Nulla facilisi. In finibus, nulla vitae tincidunt ornare,
- sapien nulla fermentum mauris, sed consectetur tortor arcu eget arcu. Vestibulum vel quam enim.
- </p>
- </div>
- </DefaultLayout>
- );
- }
-});
-
-module.exports = PrivacyPage;
diff --git a/src/pages/_template.html b/src/pages/_template.html
@@ -0,0 +1,27 @@
+<!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="stylesheet" href="css/bootstrap.css">
+ </head>
+ <body>
+ <!--[if lt IE 8]>
+ <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
+ <![endif]-->
+ <%= body %>
+ <script src="app.js"></script>
+ <!-- Google Analytics -->
+ <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');ga('send','pageview');
+ </script>
+ </body>
+</html>
diff --git a/src/pages/index.html b/src/pages/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>Facebook React Starter Kit</title>
- <meta name="description" content="">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="stylesheet" href="css/bootstrap.css">
- </head>
- <body>
- <!--[if lt IE 8]>
- <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
- <![endif]-->
-
- <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');ga('send','pageview');
- </script>
- </body>
-</html>