├── .gitignore
├── README.md
├── example
├── MyComponent.css
├── MyComponent.js
├── main.js
├── package.json
└── routes.js
├── lib
├── RWB.js
├── StandardWebpack.js
├── Workflows.js
├── entrypoint.js
├── index.html
├── index.js
├── main.js
└── template
│ ├── MyComponent.css
│ ├── MyComponent.js
│ ├── main.js
│ └── routes.js
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | example/dist
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # don't use this -- use create react app instead!
2 |
--------------------------------------------------------------------------------
/example/MyComponent.css:
--------------------------------------------------------------------------------
1 | .text {
2 | text-decoration: underline;
3 | }
4 |
5 | .MyComponent {
6 | color: red;
7 | font-family: sans-serif;
8 | }
9 |
--------------------------------------------------------------------------------
/example/MyComponent.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var React = require('react');
4 |
5 | var styles = require('./MyComponent.css');
6 |
7 | var MyComponent = React.createClass({
8 | render: function() {
9 | return (
10 |
Hello, world!
11 | );
12 | },
13 | });
14 |
15 | module.exports = MyComponent;
16 |
--------------------------------------------------------------------------------
/example/main.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var MyComponent = require('./MyComponent');
4 |
5 | module.exports = MyComponent;
6 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | },
13 | "devDependencies": {
14 | },
15 | "keywords": [
16 | "react"
17 | ],
18 | "react": {
19 | "main": "./main.js",
20 | "rwb": "0.0.1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/example/routes.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var MyComponent = require('./MyComponent');
4 | var React = require('react');
5 | var {Route} = require('react-router');
6 |
7 | module.exports = ;
8 |
--------------------------------------------------------------------------------
/lib/RWB.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var React = require('react');
4 | var Router = require('react-router');
5 |
6 | var history = null;
7 | var router = null;
8 |
9 | var RWB = {
10 | getHistory: function() {
11 | if (!history) {
12 | history = RWB_NO_HISTORY ? Router.createMemoryHistory('/') : Router.browserHistory;
13 | }
14 | return history;
15 | },
16 |
17 | getRouter: function() {
18 | if (!router) {
19 | // Lazily require() the routes because there may be circular dependencies.
20 | router = React.createElement(Router.Router, {history: RWB.getHistory()}, require('RWB_REACT_ROUTES'));
21 | }
22 | return router;
23 | },
24 | };
25 |
26 | module.exports = RWB;
27 |
--------------------------------------------------------------------------------
/lib/StandardWebpack.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var invariant = require('invariant');
4 |
5 | var REQUIRED_EXTENSIONS = ['css', 'jpg', 'png', 'svg', 'js', 'json'];
6 |
7 | function doesLoaderMatch(loaders, extension) {
8 | for (var i = 0; i < loaders.length; i++) {
9 | if (loaders[i].test.test('a.' + extension)) {
10 | return true;
11 | }
12 | }
13 | return false;
14 | }
15 |
16 | function noopRequire(module, filename) {
17 | module._compile('', filename);
18 | }
19 |
20 | var StandardWebpack = {
21 | validate: function(webpackConfig) {
22 | // throw an exception if the correct loader extensions aren't configured
23 | invariant(webpackConfig.hasOwnProperty('module'), 'Missing `module` field');
24 | invariant(Array.isArray(webpackConfig.module.loaders), '`module.loaders` is not an array');
25 | invariant(webpackConfig.hasOwnProperty('resolve'), 'Missing `resolve` field');
26 | invariant(webpackConfig.resolve.hasOwnProperty('alias'), 'Missing `resolve.alias` field');
27 | invariant(webpackConfig.resolve.alias.hasOwnProperty('react'), 'You must add a `resolve.alias.react` field');
28 | invariant(webpackConfig.resolve.hasOwnProperty('extensions'), 'Missing `resolve.extensions` field');
29 | invariant(webpackConfig.resolve.extensions.indexOf('.js') > -1, '.js missing from `resolve.extensions`');
30 | invariant(webpackConfig.resolve.extensions.indexOf('.web.js') > -1, '.web.js missing from `resolve.extensions`');
31 | REQUIRED_EXTENSIONS.forEach(function(extension) {
32 | var loaders = webpackConfig.module.loaders;
33 | invariant(
34 | doesLoaderMatch(webpackConfig.module.loaders, extension),
35 | 'You do not have a loader that handles files with the extension: %s',
36 | extension
37 | );
38 | });
39 | },
40 | };
41 |
42 | module.exports = StandardWebpack;
43 |
--------------------------------------------------------------------------------
/lib/Workflows.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var ReactDOMServer = require('react-dom/server');
4 | var StandardWebpack = require('./StandardWebpack');
5 | var WebpackDevServer = require('webpack-dev-server');
6 |
7 | var fs = require('fs');
8 | var myPackageJson = require('../package.json');
9 | var ncp = require('ncp');
10 | var open = require('open');
11 | var path = require('path');
12 | var temp = require('temp');
13 | var webpack = require('webpack');
14 |
15 | // TODO: SSL?
16 | // TODO: document these
17 | var PORT = process.env.RWB_PORT || 3000;
18 | var PUBLIC_URL = process.env.RWB_PUBLIC_URL || 'http://localhost:' + PORT + '/';
19 | var SKIP_SOURCEMAPS = !!JSON.parse(process.env.RWB_SKIP_SOURCEMAPS || 'false');
20 | var DOM_NODE_ID = process.env.RWB_DOM_NODE_ID || '.react-root';
21 |
22 | function errGuard(err) {
23 | if (err) {
24 | console.error(err);
25 | process.exit(1);
26 | }
27 | }
28 |
29 | var Workflows = {
30 | init: function(args) {
31 | var packageJson = path.join(
32 | args[0] || process.cwd(),
33 | 'package.json'
34 | );
35 |
36 | if (!fs.existsSync(packageJson)) {
37 | console.error(packageJson + ' does not exist. Did you forget to run `npm init`?');
38 | process.exit(1);
39 | }
40 |
41 | var packageJsonData = require(packageJson);
42 |
43 | if (packageJsonData.react) {
44 | console.error('This project has already been created.');
45 | process.exit(1);
46 | }
47 |
48 | packageJsonData.dependencies = packageJsonData.dependencies || {};
49 | packageJsonData.dependencies.react = packageJsonData.dependencies.react || myPackageJson.dependencies.react;
50 |
51 | packageJsonData.devDependencies = packageJsonData.devDependencies || {};
52 | packageJsonData.keywords = packageJsonData.keywords || [];
53 | if (packageJsonData.keywords.indexOf('react') === -1) {
54 | packageJsonData.keywords.push('react');
55 | }
56 | packageJsonData.react = packageJsonData.react || {};
57 | packageJsonData.react.main = packageJsonData.react.main || './main.js';
58 | packageJsonData.react.rwb = myPackageJson.version;
59 |
60 | packageJsonData.scripts = packageJsonData.scripts || {};
61 | packageJsonData.scripts.start = 'rwb serve';
62 |
63 | fs.writeFileSync(packageJson, JSON.stringify(packageJsonData, undefined, 2), {encoding: 'utf8'});
64 |
65 | ncp(path.join(__dirname, 'template'), process.cwd(), function(err) {
66 | errGuard(err);
67 | console.log('Project created. Don\'t forget to run `npm install`, since some dependencies may have changed.');
68 | });
69 | },
70 |
71 | serve: function(args) {
72 | args[0] = args[0] || '.';
73 | var packageRoot = path.resolve(args[0]);
74 | var packageJson = path.join(packageRoot, 'package.json');
75 |
76 | if (!fs.existsSync(packageJson)) {
77 | console.error(packageJson + ' does not exist.');
78 | process.exit(1);
79 | }
80 |
81 | var packageJsonData = require(packageJson);
82 |
83 | if (!packageJsonData.react || !packageJsonData.react.main) {
84 | console.error(
85 | 'react.main key does not exist in: ' + packageJson + '. Did you forget to run `rwb init`?'
86 | );
87 | process.exit(1);
88 | }
89 |
90 | temp.track();
91 | temp.mkdir('rwb-serve', function(err, dirPath) {
92 | errGuard(err);
93 | fs.writeFileSync(
94 | path.join(dirPath, 'index.html'),
95 | fs.readFileSync(
96 | path.join(__dirname, 'index.html')
97 | )
98 | );
99 |
100 | var webpackEntryPath = path.join(__dirname, 'entrypoint.js');
101 |
102 | var config = {
103 | devtool: SKIP_SOURCEMAPS ? undefined : 'cheap-module-eval-source-map',
104 | entry: [
105 | require.resolve('webpack-dev-server/client') + '?' + PUBLIC_URL,
106 | require.resolve('webpack/hot/only-dev-server'),
107 | webpackEntryPath,
108 | 'react-hot-loader/patch',
109 | ],
110 | output: {
111 | path: dirPath,
112 | publicPath: PUBLIC_URL,
113 | filename: 'bundle.js',
114 | devtoolModuleFilenameTemplate: '[absolute-resource-path]',
115 | },
116 | plugins: [
117 | new webpack.DefinePlugin({
118 | 'RWB_DOM_NODE_ID': JSON.stringify(DOM_NODE_ID),
119 | 'RWB_NO_HISTORY': JSON.stringify(false),
120 | }),
121 | new webpack.HotModuleReplacementPlugin(),
122 | new webpack.NoErrorsPlugin()
123 | ],
124 | resolve: {
125 | alias: {
126 | RWB_REACT_MAIN: path.join(
127 | packageRoot,
128 | packageJsonData.react.main
129 | ),
130 | react: path.dirname(require.resolve('react')),
131 | 'react-dom': path.dirname(require.resolve('react-dom')),
132 | },
133 | extensions: ['.web.js', '', '.js', '.json'],
134 | },
135 | module: {
136 | loaders: [
137 | {
138 | test: /\.js$/,
139 | loader: require.resolve('babel-loader'),
140 | query: {
141 | presets: ['es2015', 'react', 'stage-3']
142 | },
143 | include: packageRoot,
144 | },
145 | {
146 | test: /\.json$/,
147 | loader: require.resolve('json-loader'),
148 | },
149 | {
150 | test: /\.css$/,
151 | loader: require.resolve('style-loader'),
152 | },
153 | {
154 | test: /\.css$/,
155 | loader: require.resolve('css-loader') + '?safe',
156 | },
157 | {
158 | test: /\.css$/,
159 | loader: require.resolve('autoprefixer-loader'),
160 | },
161 | {
162 | test: /\.(png|jpg|svg)$/,
163 | loader: require.resolve('url-loader') + '?limit=8192'
164 | },
165 | ]
166 | },
167 | };
168 |
169 | StandardWebpack.validate(config);
170 |
171 | var compiler = webpack(config);
172 | new WebpackDevServer(compiler, {
173 | contentBase: dirPath,
174 | publicPath: config.output.publicPath,
175 | hot: true,
176 | historyApiFallback: true,
177 | headers: {
178 | 'Access-Control-Allow-Origin': '*',
179 | },
180 | }).listen(PORT, function (err, result) {
181 | errGuard(err);
182 | console.log('Serving ' + dirPath + ' at ' + PUBLIC_URL);
183 | });
184 |
185 | var opened = false;
186 | compiler.plugin('done', function() {
187 | if (!opened) {
188 | open(PUBLIC_URL);
189 | opened = true;
190 | }
191 | });
192 | });
193 | },
194 |
195 | validate: function(args) {
196 | if (!args[0]) {
197 | console.error('You must pass a path to a webpack config module');
198 | process.exit(1);
199 | }
200 | if (!fs.existsSync(args[0])) {
201 | console.error(args[0] + ' does not exist.');
202 | process.exit(1);
203 | }
204 | StandardWebpack.validate(require(path.resolve(args[0])));
205 | },
206 | };
207 |
208 | module.exports = Workflows;
209 |
--------------------------------------------------------------------------------
/lib/entrypoint.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('react-hot-loader/patch');
4 |
5 | var ReactHotLoader = require('react-hot-loader');
6 | var React = require('react');
7 | var ReactDOM = require('react-dom');
8 |
9 | ReactDOM.render(
10 | React.createElement(ReactHotLoader.AppContainer, null, React.createElement(require('RWB_REACT_MAIN'))),
11 | document.getElementById(RWB_DOM_NODE_ID)
12 | );
13 |
14 | if (module.hot) {
15 | module.hot.accept('RWB_REACT_MAIN', function() {
16 | ReactDOM.render(
17 | React.createElement(ReactHotLoader.AppContainer, null, React.createElement(require('RWB_REACT_MAIN'))),
18 | document.getElementById(RWB_DOM_NODE_ID)
19 | );
20 | });
21 | }
22 |
--------------------------------------------------------------------------------
/lib/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | rwb
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var index = {
4 | main: function() {
5 | require('./main');
6 | },
7 |
8 | validate: function(config) {
9 | var StandardWebpack = require('./StandardWebpack');
10 |
11 | return StandardWebpack.validate(config);
12 | },
13 | };
14 |
15 | module.exports = index;
16 |
--------------------------------------------------------------------------------
/lib/main.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict';
3 |
4 | var Workflows = require('./Workflows');
5 |
6 | var argv = require('yargs').argv;
7 |
8 | var command = argv._[0];
9 | if (!command) {
10 | console.error('No command provided.\nSee https://github.com/petehunt/rwb for help.');
11 | process.exit(1);
12 | }
13 | if (!Workflows.hasOwnProperty(command)) {
14 | console.error(
15 | 'Invalid command: ' + command + ' (acceptable commands: ' + Object.keys(Workflows).join(', ') + ')' +
16 | '\nSee https://github.com/petehunt/rwb for help.'
17 | );
18 | process.exit(1);
19 | }
20 |
21 | Workflows[command](argv._.slice(1));
22 |
--------------------------------------------------------------------------------
/lib/template/MyComponent.css:
--------------------------------------------------------------------------------
1 | :local(.MyComponent) {
2 | color: blue;
3 | font-family: sans-serif;
4 | }
--------------------------------------------------------------------------------
/lib/template/MyComponent.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var React = require('react');
4 |
5 | var styles = require('./MyComponent.css');
6 |
7 | var MyComponent = React.createClass({
8 | render: function() {
9 | return (
10 | Hello, world!
11 | );
12 | },
13 | });
14 |
15 | module.exports = MyComponent;
16 |
--------------------------------------------------------------------------------
/lib/template/main.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var MyComponent = require('./MyComponent');
4 |
5 | module.exports = MyComponent;
6 |
--------------------------------------------------------------------------------
/lib/template/routes.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var MyComponent = require('./MyComponent');
4 | var React = require('react');
5 | var {Route} = require('react-router');
6 |
7 | module.exports = ;
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rwb",
3 | "version": "0.0.21",
4 | "description": "",
5 | "main": "./lib/index.js",
6 | "bin": {
7 | "rwb": "./lib/main.js"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "autoprefixer-loader": "3.2.0",
13 | "babel-core": "6.18.2",
14 | "babel-loader": "6.2.7",
15 | "babel-preset-es2015": "^6.18.0",
16 | "babel-preset-react": "^6.16.0",
17 | "babel-preset-stage-3": "^6.17.0",
18 | "css-loader": "0.25.0",
19 | "file-loader": "0.9.0",
20 | "invariant": "2.2.1",
21 | "json-loader": "^0.5.3",
22 | "ncp": "2.0.0",
23 | "node-libs-browser": "1.0.0",
24 | "open": "0.0.5",
25 | "react": "^15.3.2",
26 | "react-dom": "^15.3.2",
27 | "react-hot-loader": "3.0.0-beta.6",
28 | "style-loader": "0.13.1",
29 | "temp": "0.8.3",
30 | "url-loader": "0.5.7",
31 | "webpack": "1.13.3",
32 | "webpack-dev-server": "1.16.2",
33 | "yargs": "6.3.0"
34 | },
35 | "preferGlobal": true,
36 | "files": [
37 | "lib"
38 | ],
39 | "engines": {
40 | "node": ">0.12.0"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------