├── .gitignore ├── .travis.yml ├── tests ├── files │ └── src │ │ └── client │ │ ├── index.html │ │ ├── App.jsx │ │ ├── index.js │ │ └── reducer.js ├── cli.test.js └── middleware.test.js ├── templates ├── .eslintrc.json └── tiny-todos │ └── src │ ├── client │ ├── index.html │ ├── reducer.js │ ├── index.js │ └── App.jsx │ └── server │ └── index.js ├── lib ├── app-emulation.js ├── webpack-prod-config.js ├── webpack-dev-config.js ├── cli.js ├── webpack-base-config.js └── main.js ├── LICENSE ├── CHANGELOG.md ├── README.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | npm-debug.log 4 | node_modules 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 6 4 | - 7 5 | - 8 6 | -------------------------------------------------------------------------------- /tests/files/src/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | -------------------------------------------------------------------------------- /templates/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "import/no-unresolved": 0, 4 | "import/no-extraneous-dependencies": 0 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/files/src/client/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default () => ( 4 |
5 |

Hello

6 |
7 | ); 8 | -------------------------------------------------------------------------------- /templates/tiny-todos/src/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Tiny TODOs 4 | 5 | 6 |
7 | 8 | 9 | -------------------------------------------------------------------------------- /templates/tiny-todos/src/server/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const app = express(); 4 | 5 | app.use(require('express-react-redux')()); 6 | 7 | app.listen(process.env.PORT || 3000); 8 | -------------------------------------------------------------------------------- /tests/files/src/client/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env browser */ 2 | 3 | import React from 'react'; 4 | import { render } from 'react-dom'; 5 | 6 | import App from './App'; 7 | 8 | render(React.createElement(App), document.getElementById('app')); 9 | -------------------------------------------------------------------------------- /tests/files/src/client/reducer.js: -------------------------------------------------------------------------------- 1 | export default (state = { todos: [] }, action) => { 2 | if (action.type === 'ADD_TODO') { 3 | return { 4 | ...state, 5 | todos: [...state.todos, action.todo], 6 | }; 7 | } 8 | return state; 9 | }; 10 | -------------------------------------------------------------------------------- /templates/tiny-todos/src/client/reducer.js: -------------------------------------------------------------------------------- 1 | export default (state = { todos: [] }, action) => { 2 | if (action.type === 'ADD_TODO') { 3 | return { 4 | ...state, 5 | todos: [...state.todos, action.todo], 6 | }; 7 | } 8 | return state; 9 | }; 10 | -------------------------------------------------------------------------------- /lib/app-emulation.js: -------------------------------------------------------------------------------- 1 | // emulating express middleware 2 | const app = { 3 | stack: [], 4 | use: func => app.stack.push(func), 5 | get: (url, func) => app.stack.push((req, res, next) => { 6 | if (req.method === 'get' && req.url === url) { 7 | func(req, res, next); 8 | } else { 9 | next(); 10 | } 11 | }), 12 | handle: (index, req, res, next) => { 13 | if (app.stack[index]) { 14 | app.stack[index](req, res, err => 15 | (err ? next(err) : app.handle(index + 1, req, res, next))); 16 | } else { 17 | next(); 18 | } 19 | }, 20 | }; 21 | 22 | module.exports = app; 23 | -------------------------------------------------------------------------------- /lib/webpack-prod-config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const merge = require('webpack-merge'); 3 | 4 | const baseConfig = require('./webpack-base-config.js'); 5 | 6 | module.exports = baseConfig.map(config => merge(config, { 7 | plugins: [ 8 | new webpack.LoaderOptionsPlugin({ 9 | minimize: true, 10 | debug: false, 11 | }), 12 | new webpack.DefinePlugin({ 13 | 'process.env': { 14 | NODE_ENV: JSON.stringify('production'), 15 | }, 16 | }), 17 | new webpack.optimize.UglifyJsPlugin({ 18 | beautify: false, 19 | mangle: { 20 | screw_ie8: true, 21 | keep_fnames: true, 22 | }, 23 | compress: { 24 | screw_ie8: true, 25 | }, 26 | comments: false, 27 | }), 28 | ], 29 | })); 30 | -------------------------------------------------------------------------------- /lib/webpack-dev-config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const merge = require('webpack-merge'); 3 | 4 | const baseConfig = require('./webpack-base-config.js'); 5 | 6 | module.exports = baseConfig.map(config => merge.smartStrategy({ 7 | entry: 'prepend', 8 | plugins: 'prepend', 9 | })(config, { 10 | entry: [ 11 | 'react-hot-loader/patch', 12 | 'webpack-hot-middleware/client', 13 | ], 14 | devtool: 'inline-source-map', 15 | plugins: [ 16 | new webpack.HotModuleReplacementPlugin(), 17 | ], 18 | module: { 19 | rules: [{ 20 | test: /\.jsx?$/, 21 | exclude: /node_modules/, 22 | use: [{ 23 | loader: 'babel-loader', 24 | options: { 25 | presets: [ 26 | ['@babel/env', { modules: false }], 27 | '@babel/react', 28 | '@babel/stage-3', 29 | ], 30 | compact: true, 31 | plugins: ['react-hot-loader/babel'], 32 | }, 33 | }], 34 | }], 35 | }, 36 | })); 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Daishi Kato 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /templates/tiny-todos/src/client/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env browser */ 2 | 3 | import { createElement as h } from 'react'; 4 | import ReactDOM from 'react-dom'; 5 | import { AppContainer } from 'react-hot-loader'; 6 | import { createStore } from 'redux'; 7 | import { Provider } from 'react-redux'; 8 | import { BrowserRouter } from 'react-router-dom'; 9 | 10 | import App from './App'; 11 | import reducer from './reducer'; 12 | 13 | const store = createStore(reducer, window.__PRELOADED_STATE__); 14 | 15 | const render = (Component) => { 16 | ReactDOM.render( 17 | h( 18 | AppContainer, {}, 19 | h( 20 | Provider, { store }, 21 | h( 22 | BrowserRouter, {}, 23 | h(Component), 24 | ), 25 | ), 26 | ), 27 | document.getElementById('app'), 28 | ); 29 | }; 30 | 31 | render(App); 32 | 33 | if (module.hot) { 34 | module.hot.accept('./App', () => { 35 | const NewApp = require('./App').default; 36 | render(NewApp); 37 | }); 38 | module.hot.accept('./reducer', () => { 39 | const newReducer = require('./reducer').default; 40 | store.replaceReducer(newReducer); 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /lib/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const path = require('path'); 4 | const program = require('commander'); 5 | const copyfiles = require('copyfiles'); 6 | const json = require('json'); 7 | 8 | program 9 | .command('import