├── .editorconfig ├── .eslintrc ├── .gitignore ├── LICENSE.md ├── README.md ├── buildConfig.js ├── esdoc.json ├── gulp ├── assets.js ├── build.js ├── custom-task.js ├── debug.js ├── index.js └── utils │ └── define-plugin.js ├── gulpfile.js ├── index.html ├── package.json ├── src ├── app.jsx ├── app │ └── index.js ├── components │ ├── chrome │ │ ├── index.js │ │ └── template.jsx │ ├── generated │ │ ├── index.js │ │ ├── store.js │ │ ├── style.less │ │ └── template.jsx │ └── navigation │ │ ├── index.js │ │ └── template.jsx ├── index.js ├── pages │ ├── index │ │ ├── index.js │ │ ├── page.js │ │ └── template.jsx │ ├── notfound │ │ ├── index.js │ │ ├── page.js │ │ └── template.jsx │ ├── other │ │ ├── index.js │ │ ├── page.js │ │ └── template.jsx │ └── test │ │ ├── index.js │ │ ├── page.js │ │ └── template.jsx └── routes.js ├── style └── main.less ├── test ├── app.jsx ├── component-generated.jsx ├── environment.js ├── index.js └── page-test.jsx ├── webpack.config.js └── webpack.config.prod.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig: http://EditorConfig.org 2 | # all files defaults 3 | [**] 4 | # Unix-style newlines with a newline ending 5 | end_of_line = lf 6 | insert_final_newline = true 7 | # Set default charset 8 | charset = utf-8 9 | # 4 space indentation 10 | indent_style = space 11 | indent_size = 4 12 | # trim whitespaces 13 | trim_trailing_whitespace = true 14 | # always insert final newline 15 | insert_final_newline = true 16 | 17 | # 2 spaces indent for config files 18 | [{package.json}] 19 | indent_style = space 20 | indent_size = 2 21 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | // I want to use babel-eslint for parsing! 3 | "parser": "babel-eslint", 4 | "env": { 5 | // I write for browser 6 | "browser": true, 7 | // in CommonJS 8 | "node": true, 9 | // use ES6 10 | "es6": true 11 | }, 12 | "ecmaProperties": { 13 | // enable JSX support 14 | "jsx": true 15 | }, 16 | "plugins": [ 17 | // enable react plugin 18 | "react" 19 | ], 20 | "globals": { 21 | "__WEBPACK__": true 22 | }, 23 | // To give you an idea how to override rule options 24 | "rules": { 25 | // Possible Errors 26 | "comma-dangle": 0, 27 | "no-console": 2, 28 | "no-debugger": 2, 29 | "no-dupe-keys": 2, 30 | "no-dupe-args": 2, 31 | "no-empty": 2, 32 | "no-extra-boolean-cast": 2, 33 | "no-extra-semi": 2, 34 | "no-invalid-regexp": 2, 35 | "no-irregular-whitespace": 2, 36 | "quote-props": [2, "consistent-as-needed", {"keywords": true}], 37 | "no-sparse-arrays": 2, 38 | "no-unreachable": 2, 39 | "use-isnan": 2, 40 | "valid-jsdoc": 2, 41 | "valid-typeof": 2, 42 | // Best Practices 43 | "consistent-return": 1, 44 | "curly": 2, 45 | "default-case": 2, 46 | "dot-notation": 2, 47 | "eqeqeq": 2, 48 | "no-alert": 2, 49 | "no-caller": 2, 50 | "no-else-return": 2, 51 | "no-eq-null": 2, 52 | "no-eval": 2, 53 | "no-extend-native": 2, 54 | "no-floating-decimal": 2, 55 | "no-implied-eval": 2, 56 | "no-iterator": 2, 57 | "no-labels": 2, 58 | "no-loop-func": 1, 59 | "no-lone-blocks": 2, 60 | "no-multi-spaces": 2, 61 | "no-native-reassign": 2, 62 | "no-new": 2, 63 | "no-new-func": 2, 64 | "no-new-wrappers": 2, 65 | "no-proto": 2, 66 | "no-redeclare": 2, 67 | "no-return-assign": 2, 68 | "no-script-url": 2, 69 | "no-self-compare": 2, 70 | "no-sequences": 2, 71 | "no-throw-literal": 2, 72 | "no-unused-expressions": 2, 73 | "no-void": 2, 74 | "radix": 2, 75 | "yoda": 0, 76 | // Strict Mode 77 | "strict": 0, 78 | // Variables 79 | "no-catch-shadow": 2, 80 | "no-delete-var": 2, 81 | "no-shadow": 2, 82 | "no-shadow-restricted-names": 2, 83 | "no-undef": 2, 84 | "no-unused-vars": [2, {"vars": "all", "args": "after-used"}], 85 | "no-use-before-define": 2, 86 | // Node 87 | "handle-callback-err": 2, 88 | "no-new-require": 2, 89 | "no-path-concat": 2, 90 | // Stylistic Issues 91 | "indent": 2, // 4 spaces 92 | "camelcase": 2, 93 | "comma-spacing": [2, {"before": false, "after": true}], 94 | "comma-style": [2, "last"], 95 | "eol-last": 2, 96 | "func-style": [2, "expression"], 97 | "max-nested-callbacks": [2, 3], 98 | "no-array-constructor": 2, 99 | "no-mixed-spaces-and-tabs": 2, 100 | "no-multiple-empty-lines": [1, {"max": 2}], 101 | "no-nested-ternary": 2, 102 | "no-new-object": 2, 103 | "semi-spacing": [2, {"before": false, "after": true}], 104 | "no-spaced-func": 2, 105 | "no-trailing-spaces": 2, 106 | "no-underscore-dangle": 2, 107 | "no-extra-parens": [2, "functions"], 108 | "quote-props": [1, "as-needed"], 109 | "quotes": [1, "single"], 110 | "semi": [2, "always"], 111 | "semi-spacing": [2, {"before": false, "after": true}], 112 | "space-before-function-paren": [1, {"anonymous": "never", "named": "never"}], 113 | "space-after-keywords": [1, "always"], 114 | "space-before-blocks": [1, "always"], 115 | "object-curly-spacing": [1, "never"], 116 | "array-bracket-spacing": [1, "never"], 117 | "computed-property-spacing": [1, "never"], 118 | "space-in-parens": [1, "never"], 119 | "key-spacing": [1, {"beforeColon": false, "afterColon": true}], 120 | "object-curly-spacing": [1, "never"], 121 | "space-infix-ops": 2, 122 | // complexity rules 123 | "max-depth": [2, 3], 124 | "max-statements": [1, 20], 125 | "complexity": [1, 3], 126 | "max-len": [2, 120], 127 | "max-params": [2, 2], 128 | // jsx rules 129 | "react/jsx-quotes": 1, 130 | "react/jsx-no-undef": 1, 131 | "react/jsx-uses-react": 1, 132 | "react/jsx-uses-vars": 1, 133 | "react/no-did-mount-set-state": 1, 134 | "react/no-did-update-set-state": 1, 135 | "react/no-multi-comp": 1, 136 | "react/react-in-jsx-scope": 1, 137 | "react/self-closing-comp": 1, 138 | "react/wrap-multilines": 1, 139 | // ES6 140 | "prefer-const": 2, 141 | "object-shorthand": [2, "always"], 142 | "no-var": 2 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore node deps 2 | node_modules/ 3 | 4 | # ignore compiled 5 | dist/ 6 | 7 | # ignore coverage report 8 | coverage/ 9 | 10 | # ignore docs 11 | esdoc/ 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Your license text here 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Awesome exampleApp application 2 | 3 | No description yet 4 | 5 | Made with [Turris.js](https://github.com/turrisjs) 6 | -------------------------------------------------------------------------------- /buildConfig.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | webpackConfig: { 3 | debug: require('./webpack.config.js'), 4 | production: require('./webpack.config.prod.js'), 5 | }, 6 | devServer: { 7 | // settings for webpack-dev-server 8 | proxy: { 9 | // put your custom proxy routes here, e.g.: 10 | // '/api/': 'http://localhost:8081' 11 | }, 12 | headers: { 13 | // put your custom headers here, e.g.: 14 | // 'X-TEST': 1, 15 | }, 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /esdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": "./src", 3 | "destination": "./esdoc", 4 | "coverage": true 5 | } 6 | -------------------------------------------------------------------------------- /gulp/assets.js: -------------------------------------------------------------------------------- 1 | export default (gulp) => { 2 | gulp.task('assets', function() { 3 | return gulp.src('./index.html').pipe(gulp.dest('./dist')); 4 | }); 5 | }; 6 | -------------------------------------------------------------------------------- /gulp/build.js: -------------------------------------------------------------------------------- 1 | import gutil from 'gulp-util'; 2 | import webpack from 'webpack'; 3 | import definePlugin from './utils/define-plugin.js'; 4 | 5 | // create optimizations array 6 | const optimizations = [ 7 | definePlugin, 8 | new webpack.optimize.DedupePlugin(), 9 | new webpack.optimize.UglifyJsPlugin({ 10 | output: { 11 | comments: false, 12 | }, 13 | compress: { 14 | warnings: false, 15 | }, 16 | }), 17 | ]; 18 | 19 | // get build config 20 | const buildConfig = require('../buildConfig'); 21 | // get webpack config 22 | const wpConfig = buildConfig.webpackConfig.production; 23 | 24 | // export initilizer 25 | export default (gulp) => { 26 | gulp.task('build', function(callback) { 27 | if (wpConfig.plugins) { 28 | wpConfig.plugins = wpConfig.plugins.concat(optimizations); 29 | } else { 30 | wpConfig.plugins = optimizations; 31 | } 32 | // run webpack 33 | webpack(wpConfig, function(err, stats) { 34 | if (err) { 35 | throw new gutil.PluginError('webpack', err); 36 | } 37 | // only log when errors 38 | gutil.log('[webpack]: ', stats.toString({ 39 | chunks: false, 40 | modules: false, 41 | colors: true, 42 | })); 43 | callback(); 44 | }); 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /gulp/custom-task.js: -------------------------------------------------------------------------------- 1 | module.exports = function(gulp) { 2 | gulp.task('custom-task', function() { 3 | console.log('custom task done!'); 4 | }); 5 | }; 6 | -------------------------------------------------------------------------------- /gulp/debug.js: -------------------------------------------------------------------------------- 1 | /* eslint no-console: 0 */ 2 | import webpack from 'webpack'; 3 | import WebpackDevServer from 'webpack-dev-server'; 4 | import definePlugin from './utils/define-plugin.js'; 5 | 6 | // create optimizations array 7 | const optimizations = [definePlugin]; 8 | 9 | // get build config 10 | const buildConfig = require('../buildConfig'); 11 | // get webpack config 12 | const wpConfig = buildConfig.webpackConfig.debug; 13 | 14 | // export initilizer 15 | export default (gulp) => { 16 | gulp.task('debug', function() { 17 | // append our define plugin 18 | wpConfig.plugins = wpConfig.plugins ? wpConfig.plugins.concat(optimizations) : optimizations; 19 | // get server config 20 | let proxy = {}; 21 | if (buildConfig.devServer && buildConfig.devServer.proxy) { 22 | proxy = buildConfig.devServer.proxy; 23 | } 24 | let headers = {}; 25 | if (buildConfig.devServer && buildConfig.devServer.headers) { 26 | headers = buildConfig.devServer.headers; 27 | } 28 | // run webpack 29 | const compiler = webpack(wpConfig); 30 | const server = new WebpackDevServer(compiler, { 31 | // webpack-dev-server options 32 | contentBase: wpConfig.context, 33 | 34 | hot: true, 35 | // Enable special support for Hot Module Replacement 36 | // Page is no longer updated, but a "webpackHotUpdate" message is send to the content 37 | // Use "webpack/hot/dev-server" as additional module in your entry point 38 | // Note: this does _not_ add the `HotModuleReplacementPlugin` like the CLI option does. 39 | 40 | // webpack-dev-middleware options 41 | quiet: false, 42 | noInfo: false, 43 | watchOptions: { 44 | aggregateTimeout: 300, 45 | poll: true 46 | }, 47 | headers, 48 | stats: { 49 | chunks: false, 50 | colors: true, 51 | }, 52 | // Set this as true if you want to access dev server from arbitrary url. 53 | // This is handy if you are using a html5 router. 54 | historyApiFallback: true, 55 | // Set this if you want webpack-dev-server to delegate a single path to an arbitrary server. 56 | // Use "*" to proxy all paths to the specified server. 57 | // This is useful if you want to get rid of 'http://localhost:8080/' in script[src], 58 | // and has many other use cases (see https://github.com/webpack/webpack-dev-server/pull/127 ). 59 | proxy, 60 | }); 61 | server.listen(8080, 'localhost', function() { 62 | console.log('Webpack-Dev-Server: started on port 8080'); 63 | }); 64 | }); 65 | }; 66 | -------------------------------------------------------------------------------- /gulp/index.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import gulp from 'gulp'; 3 | 4 | // blacklist self and utils folder 5 | const blacklist = ['index.js', 'utils']; 6 | // get local files 7 | const files = fs.readdirSync('./gulp').filter(f => !blacklist.includes(f)); 8 | 9 | // load custom tasks 10 | files.forEach(function(file) { 11 | require('./' + file)(gulp); 12 | }); 13 | 14 | gulp.task('default', ['debug']); 15 | gulp.task('deploy', ['build', 'assets']); 16 | -------------------------------------------------------------------------------- /gulp/utils/define-plugin.js: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack'; 2 | 3 | // definePlugin takes raw strings and inserts them, so you can put strings of JS if you want. 4 | const definePlugin = new webpack.DefinePlugin({ 5 | __WEBPACK__: true, // say we're the webpack 6 | __DEV__: process.env.BUILD_DEV, // dev environment indication 7 | }); 8 | 9 | export default definePlugin; 10 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | // enable babel 2 | require('babel/register'); 3 | // require gulp entry 4 | require('./gulp'); 5 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | exampleApp app 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "exampleApp", 3 | "version": "1.0.0", 4 | "description": "No description yet", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "tape ./test | faucet", 8 | "cover": "istanbul cover tape ./test", 9 | "docs": "esdoc -c esdoc.json", 10 | "start": "gulp", 11 | "build": "gulp build", 12 | "deploy": "gulp deploy" 13 | }, 14 | "author": "", 15 | "license": "MIT", 16 | "dependencies": { 17 | "bootstrap": "^3.3.4", 18 | "postal": "^1.0.7", 19 | "react": "^0.13.2", 20 | "react-router": "^0.13.3" 21 | }, 22 | "devDependencies": { 23 | "babel": "^5.8.19", 24 | "babel-core": "^5.8.19", 25 | "babel-eslint": "^4.0.5", 26 | "babel-loader": "^5.3.2", 27 | "css-loader": "^0.17.0", 28 | "eslint": "^1.1.0", 29 | "eslint-loader": "^1.0.0", 30 | "eslint-plugin-react": "^3.1.0", 31 | "extract-text-webpack-plugin": "^0.8.2", 32 | "faucet": "0.0.1", 33 | "file-loader": "^0.8.4", 34 | "gulp": "^3.9.0", 35 | "gulp-util": "^3.0.6", 36 | "istanbul": "^0.3.17", 37 | "jsdom": "^6.3.0", 38 | "less-loader": "^2.2.0", 39 | "localStorage": "^1.0.3", 40 | "react-hot-loader": "^1.3.0", 41 | "style-loader": "^0.12.3", 42 | "tape": "^4.0.1", 43 | "url-loader": "^0.5.6", 44 | "webpack": "^1.10.5", 45 | "webpack-dev-server": "^1.10.1" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/app.jsx: -------------------------------------------------------------------------------- 1 | // react 2 | import React from 'react'; 3 | import ReactRouter from 'react-router'; 4 | // app core 5 | import App from './app/index.js'; 6 | // user routes 7 | import routes from './routes.js'; 8 | 9 | const appInstance = ( 10 | 11 | {routes} 12 | 13 | ); 14 | 15 | const Bootstrapper = { 16 | start() { 17 | ReactRouter.run(appInstance, ReactRouter.HistoryLocation, function(Handler) { 18 | React.render(, document.getElementById('mainContainer')); 19 | }); 20 | }, 21 | }; 22 | 23 | export default Bootstrapper; 24 | -------------------------------------------------------------------------------- /src/app/index.js: -------------------------------------------------------------------------------- 1 | // react 2 | import React from 'react'; 3 | import {RouteHandler} from 'react-router'; 4 | 5 | // main class 6 | const App = React.createClass({ 7 | render() { 8 | return ; 9 | }, 10 | }); 11 | 12 | export default App; 13 | -------------------------------------------------------------------------------- /src/components/chrome/index.js: -------------------------------------------------------------------------------- 1 | // react 2 | import React from 'react'; 3 | import Template from './template.jsx'; 4 | 5 | const Chrome = React.createClass({ 6 | render: Template, 7 | }); 8 | 9 | export default Chrome; 10 | -------------------------------------------------------------------------------- /src/components/chrome/template.jsx: -------------------------------------------------------------------------------- 1 | // react 2 | import React from 'react'; 3 | import Navigation from '../navigation'; 4 | 5 | const render = function() { 6 | return ( 7 |
8 | 9 | 10 |
11 |
12 | {this.props.children} 13 |
14 |
15 |
16 | ); 17 | }; 18 | 19 | export default render; 20 | -------------------------------------------------------------------------------- /src/components/generated/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | */ 4 | import React from 'react'; 5 | import Template from './template.jsx'; 6 | import generatedChannel from './store.js'; 7 | 8 | // only load style when using webpack 9 | if (__WEBPACK__) { 10 | require('./style.less'); 11 | } 12 | 13 | const GeneratedComponent = React.createClass({ 14 | getInitialState() { 15 | generatedChannel.subscribe('response', this.onResponse); 16 | return { 17 | response: 'Click the button.', 18 | }; 19 | }, 20 | onResponse({data}) { 21 | this.setState({response: data}); 22 | }, 23 | handleClick() { 24 | generatedChannel.publish('request', {request: 'test'}); 25 | }, 26 | render: Template, 27 | }); 28 | 29 | export default GeneratedComponent; 30 | -------------------------------------------------------------------------------- /src/components/generated/store.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | */ 4 | import postal from 'postal'; 5 | 6 | const generatedChannel = postal.channel('generated'); 7 | 8 | generatedChannel.subscribe('request', ({request}) => { 9 | if (request === 'test') { 10 | generatedChannel.publish('response', {data: 'ok!'}); 11 | } 12 | }); 13 | 14 | export default generatedChannel; 15 | -------------------------------------------------------------------------------- /src/components/generated/style.less: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | */ 4 | .generated-component { 5 | // put you styles here 6 | h3 { 7 | color: red; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/components/generated/template.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | */ 4 | import React from 'react'; 5 | 6 | const render = function() { 7 | return ( 8 |
9 |

I am new generated component.

10 | Here's response from store: {this.state.response}
11 | 12 |
13 | ); 14 | }; 15 | 16 | export default render; 17 | -------------------------------------------------------------------------------- /src/components/navigation/index.js: -------------------------------------------------------------------------------- 1 | // react 2 | import React from 'react'; 3 | import Template from './template.jsx'; 4 | 5 | const Navbar = React.createClass({ 6 | render: Template, 7 | }); 8 | 9 | export default Navbar; 10 | -------------------------------------------------------------------------------- /src/components/navigation/template.jsx: -------------------------------------------------------------------------------- 1 | // react 2 | import React from 'react'; 3 | import ReactRouter from 'react-router'; 4 | 5 | const render = function() { 6 | return ( 7 |
8 |
9 |
10 | 16 | exampleApp 17 |
18 | 19 |
20 |
    21 |
  • Home
  • 22 |
  • Other
  • 23 |
  • Test
  • 24 |
25 |
26 |
27 |
28 | ); 29 | }; 30 | 31 | export default render; 32 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* istanbul ignore if */ 2 | if (__WEBPACK__) { 3 | require('bootstrap/dist/css/bootstrap.css'); 4 | require('../style/main.less'); 5 | } 6 | import App from './app.jsx'; 7 | 8 | App.start(); 9 | -------------------------------------------------------------------------------- /src/pages/index/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {DefaultRoute} from 'react-router'; 3 | import IndexPage from './page'; 4 | 5 | const IndexRoute = React.createElement(DefaultRoute, {name: 'home', key: 'route_default', handler: IndexPage}); 6 | 7 | export default IndexRoute; 8 | -------------------------------------------------------------------------------- /src/pages/index/page.js: -------------------------------------------------------------------------------- 1 | // react 2 | import React from 'react'; 3 | import Template from './template.jsx'; 4 | 5 | const IndexPage = React.createClass({ 6 | getInitialState() { 7 | // init state 8 | return { 9 | // your stuff here 10 | }; 11 | }, 12 | render: Template, 13 | }); 14 | 15 | export default IndexPage; 16 | -------------------------------------------------------------------------------- /src/pages/index/template.jsx: -------------------------------------------------------------------------------- 1 | // react 2 | import React from 'react'; 3 | import Chrome from '../../components/chrome/index.js'; 4 | import Generated from '../../components/generated/index.js'; 5 | 6 | const render = function() { 7 | return ( 8 | 9 |

I am index page

10 | 11 |
12 | ); 13 | }; 14 | 15 | export default render; 16 | -------------------------------------------------------------------------------- /src/pages/notfound/index.js: -------------------------------------------------------------------------------- 1 | // imports 2 | import React from 'react'; 3 | import {NotFoundRoute} from 'react-router'; 4 | import NotFoundPage from './page'; 5 | 6 | const route = React.createElement(NotFoundRoute, {name: 'notfound', key: 'route_notfound', handler: NotFoundPage}); 7 | 8 | export default route; 9 | -------------------------------------------------------------------------------- /src/pages/notfound/page.js: -------------------------------------------------------------------------------- 1 | // imports 2 | import React from 'react'; 3 | import Template from './template.jsx'; 4 | 5 | const NotFoundPage = React.createClass({ 6 | render: Template, 7 | }); 8 | 9 | export default NotFoundPage; 10 | -------------------------------------------------------------------------------- /src/pages/notfound/template.jsx: -------------------------------------------------------------------------------- 1 | // imports 2 | import React from 'react'; 3 | import Chrome from '../../components/chrome/index.js'; 4 | 5 | const render = function() { 6 | return ( 7 | 8 |

404 - page not found!

9 |
10 | ); 11 | }; 12 | 13 | export default render; 14 | -------------------------------------------------------------------------------- /src/pages/other/index.js: -------------------------------------------------------------------------------- 1 | // react 2 | import React from 'react'; 3 | import {Route} from 'react-router'; 4 | import OtherPage from './page'; 5 | 6 | const route = React.createElement(Route, {name: 'other', key: 'route_other', handler: OtherPage}); 7 | 8 | export default route; 9 | -------------------------------------------------------------------------------- /src/pages/other/page.js: -------------------------------------------------------------------------------- 1 | // react 2 | import React from 'react'; 3 | import Template from './template.jsx'; 4 | 5 | const OtherPage = React.createClass({ 6 | render: Template, 7 | }); 8 | 9 | export default OtherPage; 10 | -------------------------------------------------------------------------------- /src/pages/other/template.jsx: -------------------------------------------------------------------------------- 1 | // react 2 | import React from 'react'; 3 | import Chrome from '../../components/chrome/index.js'; 4 | 5 | const render = function() { 6 | return ( 7 | 8 |

I am other page

9 |
10 | ); 11 | }; 12 | 13 | export default render; 14 | -------------------------------------------------------------------------------- /src/pages/test/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | */ 4 | import React from 'react'; 5 | import {Route} from 'react-router'; 6 | import TestPage from './page.js'; 7 | 8 | const route = React.createElement(Route, {name: 'test', key: 'route_test', handler: TestPage}); 9 | 10 | export default route; 11 | -------------------------------------------------------------------------------- /src/pages/test/page.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | */ 4 | import React from 'react'; 5 | import Template from './template.jsx'; 6 | 7 | const TestPage = React.createClass({ 8 | render: Template, 9 | }); 10 | 11 | export default TestPage; 12 | -------------------------------------------------------------------------------- /src/pages/test/template.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | */ 4 | import Chrome from '../../components/chrome'; 5 | import React from 'react'; 6 | 7 | const render = function() { 8 | return ( 9 |

I am new test page

10 | ); 11 | }; 12 | 13 | export default render; 14 | -------------------------------------------------------------------------------- /src/routes.js: -------------------------------------------------------------------------------- 1 | // import all routes 2 | import Test from './pages/test/index.js'; 3 | import Index from './pages/index/index.js'; 4 | import Other from './pages/other/index.js'; 5 | import NotFound from './pages/notfound/index.js'; 6 | 7 | // create route array 8 | const routes = [ 9 | Test, 10 | Index, 11 | Other, 12 | NotFound, 13 | ]; 14 | 15 | export default routes; 16 | -------------------------------------------------------------------------------- /style/main.less: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | } 4 | -------------------------------------------------------------------------------- /test/app.jsx: -------------------------------------------------------------------------------- 1 | // import helpers 2 | import test from 'tape'; 3 | 4 | // import app 5 | import App from '../src/app.jsx'; 6 | 7 | test('App suite', function(it) { 8 | it.test('# should render', function(t) { 9 | // render 10 | App.start(); 11 | // verify it exists 12 | t.equal(1, document.getElementById('mainContainer').children.length); 13 | t.end(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test/component-generated.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | */ 4 | /* global describe, it */ 5 | // import helpers 6 | import test from 'tape'; 7 | import React from 'React/addons'; 8 | const {TestUtils} = React.addons; 9 | 10 | // import page 11 | import Component from '../src/components/generated/index.js'; 12 | 13 | test('Generated component suite', function(it) { 14 | it.test('# should render', function(t) { 15 | // render 16 | const comp = TestUtils.renderIntoDocument(); 17 | 18 | // check if link and name are correct 19 | const divs = TestUtils.scryRenderedDOMComponentsWithTag(comp, 'div'); 20 | t.equal(1, divs.length); 21 | t.end(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/environment.js: -------------------------------------------------------------------------------- 1 | import localStorage from 'localStorage'; 2 | import {jsdom} from 'jsdom'; 3 | 4 | // say we're not in webpack environment 5 | // this is required to skip including styles 6 | global.__WEBPACK__ = false; // eslint-disable-line no-underscore-dangle 7 | 8 | // init jsdom 9 | global.document = jsdom('
'); 10 | global.window = global.document.defaultView; 11 | global.navigator = global.window.navigator; 12 | 13 | // mock location 14 | global.window.location.href = 'http://localhost/'; 15 | 16 | // local storage polyfill 17 | global.window.localStorage = localStorage; 18 | global.localStorage = localStorage; 19 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | require('babel/register'); 2 | require('./environment'); 3 | require('./app.jsx'); 4 | require('./page-test.jsx'); 5 | require('./component-generated.jsx'); 6 | -------------------------------------------------------------------------------- /test/page-test.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | */ 4 | /* global describe, it */ 5 | // import helpers 6 | import test from 'tape'; 7 | import React from 'React/addons'; 8 | const {TestUtils} = React.addons; 9 | 10 | // import page 11 | import Page from '../src/pages/test/page.js'; 12 | 13 | test('Test page suite', function(it) { 14 | it.test('# should render', function(t) { 15 | // render 16 | const comp = TestUtils.renderIntoDocument(); 17 | 18 | // check if link and name are correct 19 | const divs = TestUtils.scryRenderedDOMComponentsWithTag(comp, 'h1'); 20 | t.equal(1, divs.length); 21 | t.end(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | devtool: 'inline-source-map', 6 | debug: true, 7 | context: path.resolve(__dirname), 8 | entry: [ 9 | 'webpack-dev-server/client?http://0.0.0.0:8080', // WebpackDevServer host and port 10 | 'webpack/hot/only-dev-server', // "only" prevents reload on syntax errors 11 | './src/index.js', 12 | ], 13 | output: { 14 | path: path.resolve(__dirname, 'dist'), 15 | publicPath: '/', 16 | filename: 'app.min.js', 17 | }, 18 | resolve: { 19 | root: path.resolve(__dirname), 20 | extensions: ['', '.js', '.jsx'], 21 | modulesDirectories: ['node_modules'], 22 | }, 23 | node: { 24 | fs: 'empty', 25 | }, 26 | eslint: { 27 | configFile: path.join(__dirname, '.eslintrc'), 28 | }, 29 | module: { 30 | preLoaders: [ 31 | { 32 | test: /\.jsx?$/, 33 | exclude: /node_modules/, 34 | loader: 'eslint' 35 | }, 36 | ], 37 | loaders: [ 38 | { 39 | test: /\.css$/, 40 | loaders: ['style', 'css'], 41 | }, 42 | { 43 | test: /\.json$/, 44 | loader: 'json', 45 | }, 46 | { 47 | test: /\.less$/, 48 | loaders: ['style', 'css', 'less'], 49 | }, 50 | { 51 | test: /\.scss$/, 52 | loaders: ['style', 'css', 'sass'], 53 | }, 54 | { 55 | test: /\.styl$/, 56 | loaders: ['style', 'css', 'stylus'], 57 | }, 58 | { 59 | test: /\.jsx?$/, 60 | exclude: /node_modules/, 61 | loaders: ['react-hot', 'babel'], 62 | }, 63 | { 64 | test: /\.woff\d?(\?.+)?$/, 65 | loader: 'url?limit=10000&minetype=application/font-woff', 66 | }, 67 | { 68 | test: /\.ttf(\?.+)?$/, 69 | loader: 'url?limit=10000&minetype=application/octet-stream', 70 | }, 71 | { 72 | test: /\.eot(\?.+)?$/, 73 | loader: 'url?limit=10000', 74 | }, 75 | { 76 | test: /\.svg(\?.+)?$/, 77 | loader: 'url?limit=10000&minetype=image/svg+xml', 78 | }, 79 | { 80 | test: /\.png$/, 81 | loader: 'url?limit=10000&mimetype=image/png', 82 | }, 83 | { 84 | test: /\.gif$/, 85 | loader: 'url?limit=10000&mimetype=image/gif' 86 | } 87 | ], 88 | }, 89 | plugins: [ 90 | new webpack.HotModuleReplacementPlugin(), 91 | ], 92 | }; 93 | -------------------------------------------------------------------------------- /webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 3 | 4 | module.exports = { 5 | context: path.resolve(__dirname), 6 | entry: './src/index.js', 7 | output: { 8 | path: path.join(__dirname, 'dist'), 9 | filename: 'app.min.js', 10 | }, 11 | resolve: { 12 | root: path.resolve(__dirname), 13 | packageMains: ['style', 'main'], 14 | extensions: ['', '.js', '.jsx'], 15 | modulesDirectories: ['node_modules'], 16 | }, 17 | node: { 18 | fs: 'empty', 19 | }, 20 | module: { 21 | loaders: [ 22 | { 23 | test: /\.css$/, 24 | loader: ExtractTextPlugin.extract('style', 'css'), 25 | }, 26 | { 27 | test: /\.json$/, 28 | loader: 'json', 29 | }, 30 | { 31 | test: /\.less$/, 32 | loader: ExtractTextPlugin.extract('style', 'css!less'), 33 | }, 34 | { 35 | test: /\.scss$/, 36 | loader: ExtractTextPlugin.extract('style', 'css!sass'), 37 | }, 38 | { 39 | test: /\.styl$/, 40 | loader: ExtractTextPlugin.extract('style', 'css!stylus'), 41 | }, 42 | { 43 | test: /\.jsx?$/, 44 | exclude: /node_modules/, 45 | loader: 'babel', 46 | }, 47 | { 48 | test: /\.woff\d?(\?.+)?$/, 49 | loader: 'url?limit=1000&minetype=application/font-woff', 50 | }, 51 | { 52 | test: /\.ttf(\?.+)?$/, 53 | loader: 'url?limit=1000&minetype=application/octet-stream', 54 | }, 55 | { 56 | test: /\.eot(\?.+)?$/, 57 | loader: 'url?limit=1000', 58 | }, 59 | { 60 | test: /\.svg(\?.+)?$/, 61 | loader: 'url?limit=1000&minetype=image/svg+xml', 62 | }, 63 | { 64 | test: /\.png$/, 65 | loader: 'url?limit=1000&mimetype=image/png', 66 | }, 67 | { 68 | test: /\.gif$/, 69 | loader: 'url?limit=1000&mimetype=image/gif' 70 | } 71 | ], 72 | }, 73 | plugins: [ 74 | new ExtractTextPlugin('style.css', {allChunks: true}), 75 | ], 76 | }; 77 | --------------------------------------------------------------------------------