Initial version of the website and docs.

This commit is contained in:
Christopher Chedeau
2015-02-11 20:26:43 -08:00
parent dd78b09741
commit 9231d4f8f0
27 changed files with 3342 additions and 0 deletions

117
website/server/convert.js Normal file
View File

@@ -0,0 +1,117 @@
var fs = require('fs')
var glob = require('glob');
var mkdirp = require('mkdirp');
var optimist = require('optimist');
var path = require('path');
var argv = optimist.argv;
function splitHeader(content) {
var lines = content.split('\n');
for (var i = 1; i < lines.length - 1; ++i) {
if (lines[i] === '---') {
break;
}
}
return {
header: lines.slice(1, i + 1).join('\n'),
content: lines.slice(i + 1).join('\n')
};
}
function backtickify(str) {
var escaped = '`' + str.replace(/\\/g, '\\\\').replace(/`/g, '\\`') + '`';
// Replace require( with require\( so node-haste doesn't replace example
// require calls in the docs
return escaped.replace(/require\(/g, 'require\\(');
}
function execute() {
var MD_DIR = '../docs/';
glob('src/react-native/docs/*.*', function(er, files) {
files.forEach(function(file) {
try {
fs.unlinkSync(file);
} catch(e) {
/* seriously, unlink throws when the file doesn't exist :( */
}
});
});
var metadatas = {
files: [],
};
glob(MD_DIR + '**/*.*', function (er, files) {
files.forEach(function(file) {
var extension = path.extname(file);
if (extension === '.md' || extension === '.markdown') {
var content = fs.readFileSync(file, {encoding: 'utf8'});
var metadata = {};
// Extract markdown metadata header
var both = splitHeader(content);
var lines = both.header.split('\n');
for (var i = 0; i < lines.length - 1; ++i) {
var keyvalue = lines[i].split(':');
var key = keyvalue[0].trim();
var value = keyvalue.slice(1).join(':').trim();
// Handle the case where you have "Community #10"
try { value = JSON.parse(value); } catch(e) { }
metadata[key] = value;
}
metadatas.files.push(metadata);
if (metadata.permalink.match(/^https?:/)) {
return;
}
// Create a dummy .js version that just calls the associated layout
var layout = metadata.layout[0].toUpperCase() + metadata.layout.substr(1) + 'Layout';
var content = (
'/**\n' +
' * @generated\n' +
' * @jsx React.DOM\n' +
' */\n' +
'var React = require("React");\n' +
'var layout = require("' + layout + '");\n' +
'var content = ' + backtickify(both.content) + '\n' +
'var Post = React.createClass({\n' +
' render: function() {\n' +
' return layout({metadata: ' + JSON.stringify(metadata) + '}, content);\n' +
' }\n' +
'});\n' +
// TODO: Use React statics after upgrading React
'Post.content = content;\n' +
'module.exports = Post;\n'
);
var targetFile = 'src/react-native/' + metadata.permalink.replace(/\.html$/, '.js');
mkdirp.sync(targetFile.replace(new RegExp('/[^/]*$'), ''));
fs.writeFileSync(targetFile, content);
}
if (extension === '.json') {
var content = fs.readFileSync(file, {encoding: 'utf8'});
metadatas[path.basename(file, '.json')] = JSON.parse(content);
}
});
fs.writeFileSync(
'core/metadata.js',
'/**\n' +
' * @generated\n' +
' * @providesModule Metadata\n' +
' */\n' +
'module.exports = ' + JSON.stringify(metadatas, null, 2) + ';'
);
});
}
if (argv.convert) {
console.log('convert!')
execute();
}
module.exports = execute;

View File

@@ -0,0 +1,61 @@
var request = require('request');
var glob = require('glob');
var fs = require('fs.extra');
var mkdirp = require('mkdirp');
var server = require('./server.js');
// Sadly, our setup fatals when doing multiple concurrent requests
// I don't have the time to dig into why, it's easier to just serialize
// requests.
var queue = (function() {
var is_executing = false;
var queue = [];
function push(fn) {
queue.push(fn);
execute();
}
function execute() {
if (is_executing) {
return;
}
if (queue.length === 0) {
return;
}
var fn = queue.shift();
is_executing = true;
fn(function() {
is_executing = false;
execute()
});
}
return {push: push};
})();
glob('src/**/*.*', function(er, files) {
files.forEach(function(file) {
var targetFile = file.replace(/^src/, 'build');
if (file.match(/\.js$/)) {
targetFile = targetFile.replace(/\.js$/, '.html');
queue.push(function(cb) {
request('http://localhost:8079/' + targetFile.replace(/^build\//, ''), function(error, response, body) {
mkdirp.sync(targetFile.replace(new RegExp('/[^/]*$'), ''));
fs.writeFileSync(targetFile, body);
cb();
});
});
} else {
queue.push(function(cb) {
mkdirp.sync(targetFile.replace(new RegExp('/[^/]*$'), ''));
fs.copy(file, targetFile, cb);
});
}
});
queue.push(function(cb) {
server.close();
console.log('It is live at: http://facebook.github.io/react-native/')
cb();
});
});

53
website/server/server.js Normal file
View File

@@ -0,0 +1,53 @@
"use strict";
var connect = require('connect');
var http = require('http');
var optimist = require('optimist');
var path = require('path');
var reactMiddleware = require('react-page-middleware');
var convert = require('./convert.js');
var argv = optimist.argv;
var PROJECT_ROOT = path.resolve(__dirname, '..');
var FILE_SERVE_ROOT = path.join(PROJECT_ROOT, 'src');
var port = argv.port;
if (argv.$0 === 'node ./server/generate.js') {
// Using a different port so that you can publish the website
// and keeping the server up at the same time.
port = 8079;
}
var buildOptions = {
projectRoot: PROJECT_ROOT,
pageRouteRoot: FILE_SERVE_ROOT,
useBrowserBuiltins: false,
logTiming: true,
useSourceMaps: true,
ignorePaths: function(p) {
return p.indexOf('__tests__') !== -1;
},
serverRender: true,
dev: argv.dev !== 'false',
static: true
};
var app = connect()
.use(function(req, res, next) {
// convert all the md files on every request. This is not optimal
// but fast enough that we don't really need to care right now.
convert();
next();
})
.use(reactMiddleware.provide(buildOptions))
.use(connect['static'](FILE_SERVE_ROOT))
.use(connect.favicon(path.join(FILE_SERVE_ROOT, 'elements', 'favicon', 'favicon.ico')))
.use(connect.logger())
.use(connect.compress())
.use(connect.errorHandler());
var portToUse = port || 8080;
var server = http.createServer(app);
server.listen(portToUse);
console.log('Open http://localhost:' + portToUse + '/react-native/index.html');
module.exports = server;