diff --git a/modules/server/components/HomePage.css b/modules/client/components/Home.css similarity index 100% rename from modules/server/components/HomePage.css rename to modules/client/components/Home.css diff --git a/modules/client/components/Home.js b/modules/client/components/Home.js new file mode 100644 index 0000000..c6a474c --- /dev/null +++ b/modules/client/components/Home.js @@ -0,0 +1,86 @@ +import React from 'react' +import './Home.css' + +const Home = React.createClass({ + render() { + return ( +
+
+

npmcdn

+
+
+

npmcdn is a CDN for packages that are published via npm. Use it to quickly and easily load files using a simple URL like https://npmcdn.com/package@version/path/to/file.

+

A few examples:

+ + +

You may also use a tag or version range instead of a fixed version number, or omit the version/tag entirely to use the latest tag.

+ + +

If you omit the file path, the main module will be served. This is especially useful for loading libaries that publish a UMD build as their main module.

+ + +

Append a / at the end of a URL to view a listing of all the files in a package.

+ + +

You may use the special /bower.zip file path in packages that contain a bower.json file to dynamically generate a zip file that Bower can use to install the package.

+ + +

Please note: We do NOT recommend JavaScript libraries use Bower. Bower places additional burdens on JavaScript package authors for little to no gain. npmcdn is intended to make it easier to publish code, not harder, so Bower support will be removed in January 2017. Please move to npm for installing packages and stop using Bower before that time. See here for our rationale.

+ +

Query Parameters

+ + + + + + + + + + + + + + + +
NameDefault ValueDescription
mainmainThe name of the field in package.json to use as the main entry point when there is no file path in the URL (e.g. ?main=browser).
+ +

Suggested Workflow

+

For npm package authors, npmcdn relieves the burden of publishing your code to a CDN in addition to the npm registry. All you need to do is include your UMD build in your npm package (not your repo, that's different!).

+

You can do this easily using the following setup:

+ +

That's it! Now when you npm publish you'll have a version available on npmcdn as well.

+ +

Feedback

+

If you think this is useful, I'd love to hear from you. Please reach out to @mjackson with any questions/concerns.

+

Also, please feel free to examine the source on GitHub.

+
+
+ ) + } +}) + +export default Home diff --git a/modules/client/home.js b/modules/client/home.js new file mode 100644 index 0000000..b84f713 --- /dev/null +++ b/modules/client/home.js @@ -0,0 +1,8 @@ +import React from 'react' +import { render } from 'react-dom' +import Home from './components/Home' + +render( + , + document.getElementById('app') +) diff --git a/modules/server/AssetsUtils.js b/modules/server/AssetsUtils.js new file mode 100644 index 0000000..e217567 --- /dev/null +++ b/modules/server/AssetsUtils.js @@ -0,0 +1,115 @@ +import fs from 'fs' +import invariant from 'invariant' +import webpack from 'webpack' + +const createAssets = (webpackStats) => { + const createURL = (asset) => + webpackStats.publicPath + asset + + const getAssets = (chunkName = 'main') => { + const assets = webpackStats.assetsByChunkName[chunkName] || [] + return Array.isArray(assets) ? assets : [ assets ] + } + + const getScriptURLs = (chunkName = 'main') => + getAssets(chunkName) + .filter(asset => (/\.js$/).test(asset)) + .map(createURL) + + const getStyleURLs = (chunkName = 'main') => + getAssets(chunkName) + .filter(asset => (/\.css$/).test(asset)) + .map(createURL) + + return { + createURL, + getAssets, + getScriptURLs, + getStyleURLs + } +} + +/** + * An express middleware that sets req.assets from the build + * info in the given stats file. Should be used in production. + */ +export const staticAssets = (webpackStatsFile) => { + let stats + try { + stats = JSON.parse(fs.readFileSync(webpackStatsFile, 'utf8')) + } catch (error) { + invariant( + false, + 'staticAssets middleware cannot read the build stats in %s; ' + + 'do `npm run build` before starting the server', + webpackStatsFile + ) + } + + const assets = createAssets(stats) + + return (req, res, next) => { + req.assets = assets + next() + } +} + +/** + * An express middleware that sets req.assets from the + * latest result from a running webpack compiler (i.e. using + * webpack-dev-middleware). Should only be used in dev. + */ +export const assetsCompiler = (webpackCompiler) => { + let assets + webpackCompiler.plugin('done', (stats) => { + assets = createAssets(stats.toJson()) + }) + + return (req, res, next) => { + invariant( + assets != null, + 'assetsCompiler middleware needs a running compiler; ' + + 'use webpack-dev-middleware in front of assetsCompiler' + ) + + req.assets = assets + next() + } +} + +/** + * Creates a webpack compiler that automatically inlines the + * webpack dev runtime in all entry points. + */ +export const createDevCompiler = (webpackConfig, webpackRuntimeModuleID) => + webpack({ + ...webpackConfig, + entry: prependModuleID( + webpackConfig.entry, + webpackRuntimeModuleID + ) + }) + +/** + * Returns a modified copy of the given webpackEntry object with + * the moduleID in front of all other assets. + */ +const prependModuleID = (webpackEntry, moduleID) => { + if (typeof webpackEntry === 'string') + return [ moduleID, webpackEntry ] + + if (Array.isArray(webpackEntry)) + return [ moduleID, ...webpackEntry ] + + if (webpackEntry && typeof webpackEntry === 'object') { + const entry = { ...webpackEntry } + + for (const chunkName in entry) + if (entry.hasOwnProperty(chunkName)) + entry[chunkName] = prependModuleID(entry[chunkName], moduleID) + + return entry + } + + throw new Error('Invalid webpack entry object') +} diff --git a/modules/server/MainController.js b/modules/server/MainController.js new file mode 100644 index 0000000..52ffa6f --- /dev/null +++ b/modules/server/MainController.js @@ -0,0 +1,16 @@ +import React from 'react' +import { renderToStaticMarkup } from 'react-dom/server' +import HomePage from './components/HomePage' + +const DOCTYPE = '' + +export const sendHomePage = (req, res) => { + const props = { + styles: req.assets.getStyleURLs('home'), + scripts: req.assets.getScriptURLs('home') + } + + res.send( + DOCTYPE + renderToStaticMarkup() + ) +} diff --git a/modules/server/components/HomePage.js b/modules/server/components/HomePage.js index e567e8f..d55d517 100644 --- a/modules/server/components/HomePage.js +++ b/modules/server/components/HomePage.js @@ -1,94 +1,35 @@ -import React from 'react' -import { readCSS } from '../StyleUtils' +import React, { PropTypes } from 'react' + +const assetType = PropTypes.string const HomePage = React.createClass({ - statics: { - css: readCSS(__dirname, './HomePage.css') + propTypes: { + styles: PropTypes.arrayOf(assetType), + scripts: PropTypes.arrayOf(assetType) + }, + + getDefaultProps() { + return { + styles: [], + scripts: [] + } }, render() { + const { styles, scripts } = this.props + return ( + + + npmcdn - - -