Update web-starter

This commit is contained in:
Michael Jackson
2016-07-20 12:26:15 -07:00
parent 7734f13091
commit 51ace69ccb
12 changed files with 127 additions and 29 deletions

5
modules/client/.eslintrc Normal file
View File

@ -0,0 +1,5 @@
{
"env": {
"browser": true
}
}

View File

@ -4,6 +4,11 @@ import { findDOMNode } from 'react-dom'
import Window from './Window'
class Layout extends React.Component {
static propTypes = {
location: PropTypes.object,
children: PropTypes.node
}
state = {
underlineLeft: 0,
underlineWidth: 0,

View File

@ -5,7 +5,8 @@ class NumberTextInput extends React.Component {
static propTypes = {
value: PropTypes.number,
parseNumber: PropTypes.func,
formatNumber: PropTypes.func
formatNumber: PropTypes.func,
onChange: PropTypes.func
}
static defaultProps = {

View File

@ -1,5 +1,4 @@
import React, { PropTypes } from 'react'
import { findDOMNode } from 'react-dom'
import formatBytes from 'byte-size'
import formatDate from 'date-fns/format'
import parseDate from 'date-fns/parse'
@ -21,8 +20,12 @@ const addValues = (a, b) => {
}
class Stats extends React.Component {
static propTypes = {
stats: PropTypes.object
}
static defaultProps = {
stats: window.NPMCDN_STATS
stats: window.npmcdnStats
}
state = {
@ -83,13 +86,13 @@ class Stats extends React.Component {
})
topContinents.forEach(continent => {
const name = ContinentsIndex[continent]
const continentName = ContinentsIndex[continent]
const { countries, requests, bandwidth } = continentData[continent]
if (bandwidth !== 0) {
regionRows.push(
<tr key={continent} className="continent-row">
<td>{ContinentsIndex[continent]}</td>
<td>{continentName}</td>
<td>{formatNumber(requests)} ({formatPercent(requests / totalRequests)}%)</td>
<td>{formatBytes(bandwidth)} ({formatPercent(bandwidth / totalBandwidth)}%)</td>
</tr>

View File

@ -31,6 +31,29 @@ const createBundle = (webpackStats) => {
}
}
/**
* An express middleware that sets req.manifest from the build manifest
* in the given file. Should be used in production to get consistent hashes.
*/
export const assetsManifest = (webpackManifestFile) => {
let manifest
try {
manifest = JSON.parse(fs.readFileSync(webpackManifestFile, 'utf8'))
} catch (error) {
invariant(
false,
'assetsManifest middleware cannot read the manifest file "%s"; ' +
'do `npm run build` before starting the server',
webpackManifestFile
)
}
return (req, res, next) => {
req.manifest = manifest
next()
}
}
/**
* An express middleware that sets req.bundle from the build
* info in the given stats file. Should be used in production.

View File

@ -26,11 +26,15 @@ const fetchStats = (callback) => {
}
export const sendHomePage = (req, res, next) => {
const chunks = [ 'vendor', 'home' ]
const props = {
styles: req.bundle.getStyleAssets([ 'vendor', 'home' ]),
scripts: req.bundle.getScriptAssets([ 'vendor', 'home' ])
styles: req.bundle.getStyleAssets(chunks),
scripts: req.bundle.getScriptAssets(chunks)
}
if (req.manifest)
props.webpackManifest = req.manifest
fetchStats((error, stats) => {
if (error) {
next(error)

View File

@ -2,10 +2,12 @@ import path from 'path'
export const id = 1
export const port = parseInt(process.env.PORT, 10) || 5000
export const timeout = parseInt(process.env.TIMEOUT, 10) || 20000
export const webpackConfig = require('../../webpack.config')
export const statsFile = path.resolve(__dirname, '../../stats.json')
export const publicDir = path.resolve(__dirname, '../../public')
export const webpackConfig = require('../../webpack.config')
export const manifestFile = path.resolve(publicDir, '__assets__/chunk-manifest.json')
export const timeout = parseInt(process.env.TIMEOUT, 10) || 20000
export const maxAge = process.env.MAX_AGE || '365d'
export const registryURL = process.env.REGISTRY_URL || 'https://registry.npmjs.org'
export const bowerBundle = process.env.BOWER_BUNDLE || '/bower.zip'

View File

@ -2,33 +2,39 @@ import React, { PropTypes } from 'react'
class HomePage extends React.Component {
static propTypes = {
webpackManifest: PropTypes.object,
styles: PropTypes.arrayOf(PropTypes.string),
scripts: PropTypes.arrayOf(PropTypes.string),
stats: PropTypes.object
}
static defaultProps = {
webpackManifest: {},
styles: [],
scripts: [],
stats: {}
}
render = () => {
const { styles, scripts, stats } = this.props
render() {
const { webpackManifest, styles, scripts, stats } = this.props
return (
<html>
<head>
<meta charSet="utf-8"/>
<meta httpEquiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="viewport" content="width=700,maximum-scale=1"/>
<meta name="timestamp" content={(new Date).toISOString()}/>
<title>npmcdn</title>
{styles.map(style => <link key={style} rel="stylesheet" href={style}/>)}
<script dangerouslySetInnerHTML={{ __html: `window.NPMCDN_STATS=${JSON.stringify(stats)}` }}/>
<script dangerouslySetInnerHTML={{ __html: "window.Promise || document.write('\\x3Cscript src=\"/es6-promise.min.js\">\\x3C/script>\\x3Cscript>ES6Promise.polyfill()\\x3C/script>')" }}/>
<script dangerouslySetInnerHTML={{ __html: "window.fetch || document.write('\\x3Cscript src=\"/fetch.min.js\">\\x3C/script>')" }}/>
<script dangerouslySetInnerHTML={{ __html: "window.webpackManifest = " + JSON.stringify(webpackManifest) }}/>
<script dangerouslySetInnerHTML={{ __html: "window.npmcdnStats = " + JSON.stringify(stats) }}/>
{styles.map(s => <link rel="stylesheet" key={s} href={s}/>)}
</head>
<body>
<div id="app"/>
{scripts.map(script => <script key={script} src={script}/>)}
{scripts.map(s => <script key={s} src={s}/>)}
</body>
</html>
)

View File

@ -8,7 +8,7 @@ import devErrorHandler from 'errorhandler'
import WebpackDevServer from 'webpack-dev-server'
import { createRequestHandler } from 'npm-http-server'
import * as DefaultServerConfig from './ServerConfig'
import { staticAssets, devAssets, createDevCompiler } from './AssetsUtils'
import { assetsManifest, staticAssets, devAssets, createDevCompiler } from './AssetsUtils'
import { sendHomePage } from './MainController'
import { logStats } from './StatsUtils'
@ -38,7 +38,8 @@ export const createServer = (config) => {
app.use(errorHandler)
app.use(cors())
app.use(express.static(config.publicDir, { maxAge: 60000 }))
app.use(express.static(config.publicDir, { maxAge: config.maxAge }))
app.use(assetsManifest(config.manifestFile))
app.use(staticAssets(config.statsFile))
app.use(createRouter(config))