14 | );
15 | }
16 | }
17 |
18 | export default App;
19 |
--------------------------------------------------------------------------------
/src/items.kmocha.jsx:
--------------------------------------------------------------------------------
1 | import { expect, React, ReactDOM, TestUtils } from './util/karma-setup';
2 | import App from './app';
3 |
4 | const { renderIntoDocument, Simulate } = TestUtils;
5 | const DATA = require('../public/fake-api.json');
6 |
7 | describe('items', () => {
8 |
9 | let renderedComp;
10 | let domNode;
11 | beforeEach(() => {
12 | renderedComp = renderIntoDocument(
13 |
14 | );
15 | domNode = ReactDOM.findDOMNode(renderedComp);
16 | });
17 |
18 | it('should display all items', () => {
19 | Simulate.click(domNode); // can click on or change things
20 | const li = domNode.querySelectorAll('.items li');
21 | expect(li.length).toBe(DATA.items.length);
22 | });
23 |
24 | });
25 |
--------------------------------------------------------------------------------
/bs-config.js:
--------------------------------------------------------------------------------
1 |
2 | // http://www.browsersync.io/docs/options/
3 |
4 | module.exports = {
5 | // uses default browser or you can specify your own choice
6 | // browser: ['google chrome'],
7 | // browser: ['google chrome canary'],
8 | // browser: ['firefox'],
9 | ghostMode: false,
10 | port: 3005,
11 | // proxy: 'localhost:8005',
12 | reloadDelay: 500,
13 | reloadDebounce: 500,
14 | files: [
15 | 'public/*.html',
16 | 'public/*.json'
17 | // since we are using browser-sync-webpack-plugin
18 | // and webpack is now building js and css, it will trigger reload
19 | // for the following files
20 | // 'dist/main.js',
21 | // 'dist/style.min.css'
22 | ],
23 | server: {
24 | baseDir: './public',
25 | routes: {
26 | '/dist': './dist'
27 | }
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Jeff Barczewski
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/src/browser.jsx:
--------------------------------------------------------------------------------
1 | import './util/polyfill'; // first import polyfills
2 | import React from 'react';
3 | import ReactDOM from 'react-dom';
4 | import httpClient from 'axios';
5 | import App from './app';
6 |
7 | /*
8 | Example which fetches a list of items from a REST api
9 | and renders it to the screen. Also logs and renders
10 | renders the error message if one occurs.
11 | */
12 |
13 |
14 | const appContainerDiv = document.querySelector('#appContainer');
15 |
16 | function render(data) {
17 | ReactDOM.render(, appContainerDiv);
18 | }
19 |
20 | function renderError(err) {
21 | const errMsg = (err.statusText) ?
22 | `Error: ${err.data} - ${err.statusText}` :
23 | err.toString();
24 | ReactDOM.render(
{errMsg}
, appContainerDiv);
25 | }
26 |
27 | function fetchData() {
28 | return httpClient({ url: '/fake-api.json' });
29 | }
30 |
31 | function fetchDataAndRender() {
32 | fetchData()
33 | .then(resp => render(resp.data))
34 | .catch(err => {
35 | console.error(err); // eslint-disable-line no-console
36 | renderError(err);
37 | });
38 | }
39 |
40 | fetchDataAndRender();
41 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "mocha": true,
5 | "node": true
6 | },
7 | "extends": ["airbnb-base", "plugin:react/recommended"],
8 | "rules": {
9 | "arrow-body-style": [1, "as-needed"],
10 | // don't require dangling commas
11 | "comma-dangle": 0,
12 | // polyfills need to come first
13 | "import/imports-first": 0,
14 | // causing issues with codacy
15 | "import/no-unresolved": 0,
16 | "indent": 0,
17 | "no-shadow": 0,
18 | // don't require functions to be declared before use
19 | "no-use-before-define": [2, { "functions": false, "classes": true }],
20 | // Disable until Flow supports let and const
21 | "no-var": 0,
22 | "object-property-newline": 0,
23 | "padded-blocks": 0,
24 | "react/jsx-uses-react": 1,
25 | "react/jsx-no-undef": 2,
26 | "react/jsx-wrap-multilines": 2,
27 | "react/no-find-dom-node": 0,
28 | "react/prop-types": 0,
29 | "valid-jsdoc": 2
30 | },
31 | "parser": "babel-eslint",
32 | "parserOptions": {
33 | "ecmaFeatures": {
34 | "experimentalObjectRestSpread": true,
35 | "impliedStrict": true,
36 | "jsx": true
37 | }
38 | },
39 | "plugins": [
40 | "react"
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "react"
4 | ],
5 | "plugins": [
6 | ["transform-es2015-template-literals", { "loose": true }],
7 | "transform-es2015-literals",
8 | "transform-es2015-function-name",
9 | "transform-es2015-arrow-functions",
10 | "transform-es2015-block-scoped-functions",
11 | ["transform-es2015-classes", { "loose": true }],
12 | "transform-es2015-object-super",
13 | "transform-es2015-shorthand-properties",
14 | ["transform-es2015-computed-properties", { "loose": true }],
15 | ["transform-es2015-for-of", { "loose": true }],
16 | "transform-es2015-sticky-regex",
17 | "transform-es2015-unicode-regex",
18 | "check-es2015-constants",
19 | ["transform-es2015-spread", { "loose": true }],
20 | "transform-es2015-parameters",
21 | ["transform-es2015-destructuring", { "loose": true }],
22 | "transform-es2015-block-scoping",
23 | "transform-object-rest-spread",
24 | "transform-es3-member-expression-literals",
25 | "transform-es3-property-literals"
26 | ],
27 | "env": {
28 | "commonjs": {
29 | "plugins": [
30 | ["transform-es2015-modules-commonjs", { "loose": true }]
31 | ]
32 | },
33 | "es": {
34 | "plugins": [
35 | ]
36 | },
37 | "test": {
38 | "plugins": [
39 | ["transform-es2015-modules-commonjs", { "loose": true }]
40 | ]
41 | }
42 | },
43 | "ignore": [
44 | "**/flycheck*"
45 | ]
46 | }
47 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 |
3 | module.exports = function karmaConfig(config) {
4 | config.set({
5 |
6 | // base path that will be used to resolve all patterns (eg. files, exclude)
7 | basePath: '',
8 |
9 |
10 | // frameworks to use
11 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
12 | frameworks: ['mocha', 'phantomjs-shim'],
13 |
14 | // list of files / patterns to load in the browser
15 | files: [
16 | 'src/**/*.kmocha.js*'
17 | ],
18 |
19 |
20 | // list of files to exclude
21 | exclude: [
22 | '**/flycheck_*'
23 | ],
24 |
25 |
26 | // preprocess matching files before serving them to the browser
27 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
28 | preprocessors: {
29 | 'src/**/*.kmocha.js*': ['webpack']
30 | },
31 |
32 | quiet: true,
33 |
34 | webpack: {
35 | devtool: 'inline-source-map',
36 | module: {
37 | loaders: [
38 | { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel' },
39 | { test: /\.json$/, loader: 'json-loader' }
40 | ]
41 | },
42 | resolve: {
43 | extensions: ['', '.json', '.js', '.jsx']
44 | }
45 | },
46 |
47 | webpackMiddleware: {
48 | stats: 'errors-only',
49 | noInfo: true
50 | },
51 |
52 | // test results reporter to use
53 | // possible values: 'dots', 'progress'
54 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
55 | reporters: ['mocha'],
56 |
57 | mochaReporter: {
58 | output: 'autowatch'
59 | },
60 |
61 | // web server port
62 | port: 9876,
63 |
64 |
65 | // enable / disable colors in the output (reporters and logs)
66 | colors: true,
67 |
68 |
69 | // level of logging
70 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
71 | logLevel: config.LOG_ERROR,
72 |
73 |
74 | // enable / disable watching file and executing tests whenever any file changes
75 | autoWatch: true,
76 |
77 |
78 | // start these browsers
79 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
80 | browsers: ['PhantomJS'],
81 | // browsers: ['Chrome'],
82 |
83 |
84 | // Continuous Integration mode
85 | // if true, Karma captures browsers, runs the tests and exits
86 | singleRun: false
87 | });
88 | };
89 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var webpack = require('webpack');
4 | var ExtractTextPlugin = require("extract-text-webpack-plugin");
5 | var autoprefixer = require('autoprefixer');
6 | var postcssConfig = require('./postcss.json');
7 | var WebpackShellPlugin = require('webpack-shell-plugin');
8 | var BrowserSyncPlugin = require('browser-sync-webpack-plugin');
9 | var browserSyncConfig = require('./bs-config');
10 | var CleanCSSLoader = require('clean-css-loader');
11 |
12 | var env = process.env.NODE_ENV || 'development';
13 | var isProd = (env === 'production');
14 | // I'm setting this to single for single run, non-watch building
15 | var isSingle = (process.env.WEBPACK_MODE === 'single');
16 |
17 | var config = {
18 | devServer: {
19 | stats: {
20 | chunks: false
21 | }
22 | },
23 | entry: {
24 | main: ['./src/browser.jsx'],
25 | style: ['./style/site.less']
26 | },
27 | output: {
28 | path: __dirname + '/dist',
29 | libary: '[name]',
30 | libraryTarget: 'umd',
31 | umdNamedDefine: true,
32 | filename: '[name].js'
33 | },
34 | module: {
35 | loaders: [
36 | {
37 | test: /\.jsx?$/,
38 | exclude: /node_modules/,
39 | loaders: ['babel-loader']
40 | },
41 | { test: /\.json$/, loaders: ['json-loader'] },
42 | {
43 | test: /\.(css|less)$/,
44 | // only using clean-css in production build
45 | loader: ExtractTextPlugin.extract('style',
46 | (isProd) ?
47 | 'css!clean-css!postcss!less' :
48 | 'css!postcss!less'
49 | )
50 | }
51 | // can uncomment this if need to compile joi, isemail, hoek, topo
52 | // {
53 | // // need to babelify joi, isemail, hoek, and topo's lib
54 | // test: /\/node_modules\/(joi\/lib\/|isemail\/lib\/|hoek\/lib\/|topo\/lib\/)/,
55 | // loaders: ['babel-loader']
56 | // }
57 | ]
58 | },
59 | postcss: function () {
60 | // provide autoprefixer config from postcss.json
61 | return [autoprefixer(postcssConfig.autoprefixer)];
62 | },
63 | "clean-css":{
64 | // set any clean-css options
65 | },
66 | // most of the time we don't want this bloat
67 | node: {
68 | crypto: 'empty',
69 | net: 'empty',
70 | dns: 'empty'
71 | },
72 | resolve: {
73 | extensions: ['', '.json', '.js', '.jsx']
74 | },
75 | plugins: [
76 | new webpack.optimize.OccurrenceOrderPlugin(),
77 | new webpack.DefinePlugin({
78 | 'process.env.NODE_ENV': JSON.stringify(env)
79 | }),
80 | new ExtractTextPlugin("[name].min.css"), // ouputs at {output.path}/style.min.css
81 | new BrowserSyncPlugin(browserSyncConfig),
82 |
83 | // for slimming down moment
84 | // english locale is included, exclude the rest
85 | // new webpack.IgnorePlugin(/locale/, /moment$/),
86 |
87 | new WebpackShellPlugin({
88 | dev: false, // run onBuildEnd even during watch changes
89 | onBuildEnd: [
90 | 'rimraf dist/style.js' // clean up this, not needed
91 | ],
92 | onBuildExit: (isSingle) ? // non-watch builds
93 | [
94 | 'ngzip dist/style.min.css > dist/style.min.css.gz',
95 | 'uglifyjs dist/main.js -c warnings=false -m | ntee dist/main.min.js | ngzip > dist/main.min.js.gz'
96 | ] :
97 | [] // watch builds
98 | })
99 | ]
100 | };
101 |
102 | module.exports = config;
103 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is a **minimal React.js boilerplate with a cross-platform auto build environment** which you can fork and clone to easily setup your own projects.
2 |
3 | Tip (on platforms with bash): Using [git-clone-init](https://github.com/jeffbski/git-clone-init) makes this very simple.
4 |
5 | `git-clone-init https://github.com/jeffbski/base-react-min.git myProjectName`
6 |
7 | TODO: Replace this boilerplate with your project description
8 |
9 | Features:
10 |
11 | - **React.js JSX example which fetches from REST source and renders**
12 | - **simple build and auto rebuild** (watch) using npm run scripts
13 | - **browser-sync** for auto reloading in browser on change
14 | - **ES6/7 and JSX compiling** to ES5 with **babeljs**
15 | - **eslint** for linting
16 | - **webpack** for bundling javascript for the browser
17 | - **uglify** for js minification
18 | - **less** CSS style compiler
19 | - **autoprefixer** for automatically adding css prefixes
20 | - **cleancss** for css minification
21 | - **karma** for js unit testing in browsers or phantomjs
22 | - **phantomjs** for headless testing in browser
23 | - **npm-run-all** for simple parallel/serial npm script exec
24 | - **axios** for promise based HTTP client
25 | - **cross platform** - runs on Mac OS X, linux, unix, windows
26 |
27 |
28 | Structure:
29 |
30 | - package.json - dependencies and build commands
31 | - public/index.html - main HTML
32 | - public/fake-api.json - mock REST api returning json data
33 | - src/browser.jsx - React.js JSX code which fetches REST data and renders App component into the main HTML
34 | - src/app.jsx - Main app component used to display data
35 | - src/items.kmocha.jsx - sample karma mocha test for items
36 | - src/util/polyfill.js - Import any core-js or other polyfills here
37 | - src/util/karma-setup.js - common karma setup
38 | - style/site.less - CSS styles used by site, edit or import into
39 | - .babelrc - babel configuration
40 | - .eslintrc - eslint configuration
41 | - bs-config.js - browser-sync config, set browser to launch
42 | - karma.conf.js - karma test configuration
43 | - postcss.json - postcss config controls autoprefixer
44 | - webpack.config.js - webpack configuration
45 | - dist/ - contains compiled and minified css and js
46 |
47 |
48 | ## Installation
49 |
50 | Tested with node.js >= 4.4.0
51 |
52 |
53 | ```bash
54 | npm install ## install all dependencies
55 | ```
56 |
57 | ## Usage
58 |
59 | TODO: update with your usage
60 |
61 | Primary use - auto build and reload browser
62 | ```bash
63 | # use control-c to exit the autobuild watch
64 | npm start # build and watch, auto recompile and load changes
65 | ```
66 |
67 | Build only
68 | ```bash
69 | npm run build # build only
70 | ```
71 |
72 | Single run of tests
73 | ```bash
74 | npm test
75 | ```
76 |
77 | Build for Production
78 | ```bash
79 | npm run prod-build # sets NODE_ENV=production then builds
80 | ```
81 |
82 |
83 | ## Goals
84 |
85 | TODO: Add your goals here
86 |
87 | ## Why
88 |
89 | TODO: Add your description of why you created this
90 |
91 | ## Get involved
92 |
93 | If you have input or ideas or would like to get involved, you may:
94 |
95 | - contact me via twitter @jeffbski -
96 | - open an issue on github to begin a discussion -
97 | - fork the repo and send a pull request (ideally with tests) -
98 |
99 | ## License
100 |
101 | - [MIT license](http://github.com/jeffbski/PROJECT_NAME/raw/master/LICENSE)
102 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "PROJECT_NAME",
3 | "description": "",
4 | "version": "0.2.0",
5 | "author": "Jeff Barczewski ",
6 | "repository": {
7 | "type": "git",
8 | "url": "http://github.com/jeffbski/PROJECT_NAME.git"
9 | },
10 | "bugs": {
11 | "url": "http://github.com/jeffbski/PROJECT_NAME/issues"
12 | },
13 | "license": "MIT",
14 | "browser": {
15 | "main": "src/browser.jsx"
16 | },
17 | "browserify": {
18 | "transform": [
19 | "loose-envify"
20 | ]
21 | },
22 | "scripts": {
23 | "clean": "mkdirp dist && rimraf dist/*",
24 | "build": "cross-env BABEL_ENV=commonjs WEBPACK_MODE=single webpack",
25 | "lint": "eslint --ext .js --ext .jsx src",
26 | "prebuild": "npm run clean",
27 | "postbuild": "echo \"Finished\"",
28 | "prepublish": "npm run prod-build",
29 | "prewatch": "npm run clean",
30 | "prod-build": "npm run build --production",
31 | "start": "npm run watch",
32 | "test": "cross-env BABEL_ENV=test karma start --single-run",
33 | "watch": "run-p -c watch:*",
34 | "watch:webpack": "cross-env BABEL_ENV=commonjs webpack --watch",
35 | "watch:karma": "cross-env BABEL_ENV=test karma start"
36 | },
37 | "engines": {
38 | "node": ">=4.4.0"
39 | },
40 | "devDependencies": {
41 | "autoprefixer": "^6.4.0",
42 | "babel-core": "^6.13.2",
43 | "babel-eslint": "^6.1.2",
44 | "babel-loader": "^6.2.5",
45 | "babel-plugin-check-es2015-constants": "^6.8.0",
46 | "babel-plugin-transform-es2015-arrow-functions": "^6.8.0",
47 | "babel-plugin-transform-es2015-block-scoped-functions": "^6.8.0",
48 | "babel-plugin-transform-es2015-block-scoping": "^6.10.1",
49 | "babel-plugin-transform-es2015-classes": "^6.9.0",
50 | "babel-plugin-transform-es2015-computed-properties": "^6.8.0",
51 | "babel-plugin-transform-es2015-destructuring": "^6.9.0",
52 | "babel-plugin-transform-es2015-for-of": "^6.8.0",
53 | "babel-plugin-transform-es2015-function-name": "^6.9.0",
54 | "babel-plugin-transform-es2015-literals": "^6.8.0",
55 | "babel-plugin-transform-es2015-modules-commonjs": "^6.11.5",
56 | "babel-plugin-transform-es2015-object-super": "^6.8.0",
57 | "babel-plugin-transform-es2015-parameters": "^6.11.4",
58 | "babel-plugin-transform-es2015-shorthand-properties": "^6.8.0",
59 | "babel-plugin-transform-es2015-spread": "^6.8.0",
60 | "babel-plugin-transform-es2015-sticky-regex": "^6.8.0",
61 | "babel-plugin-transform-es2015-template-literals": "^6.8.0",
62 | "babel-plugin-transform-es2015-unicode-regex": "^6.11.0",
63 | "babel-plugin-transform-es3-member-expression-literals": "^6.8.0",
64 | "babel-plugin-transform-es3-property-literals": "^6.8.0",
65 | "babel-plugin-transform-object-rest-spread": "^6.8.0",
66 | "babel-preset-react": "^6.11.1",
67 | "babel-runtime": "^6.11.6",
68 | "browser-sync": "^2.14.0",
69 | "browser-sync-webpack-plugin": "^1.1.2",
70 | "clean-css-loader": "0.0.1",
71 | "cross-env": "^2.0.0",
72 | "css-loader": "^0.23.1",
73 | "eslint": "^3.3.1",
74 | "eslint-config-airbnb-base": "^5.0.2",
75 | "eslint-plugin-import": "^1.13.0",
76 | "eslint-plugin-react": "^6.1.2",
77 | "expect": "^1.20.2",
78 | "extract-text-webpack-plugin": "^1.0.1",
79 | "json-loader": "^0.5.4",
80 | "karma": "^1.2.0",
81 | "karma-chrome-launcher": "^2.0.0",
82 | "karma-mocha": "^1.1.1",
83 | "karma-mocha-reporter": "^2.1.0",
84 | "karma-phantomjs-launcher": "^1.0.1",
85 | "karma-phantomjs-shim": "^1.4.0",
86 | "karma-webpack": "^1.8.0",
87 | "less": "^2.7.1",
88 | "less-loader": "^2.2.3",
89 | "mkdirp": "^0.5.1",
90 | "mocha": "^3.0.2",
91 | "ngzip": "^1.0.0",
92 | "npm-run-all": "^3.0.0",
93 | "ntee": "^1.1.5",
94 | "phantomjs-prebuilt": "^2.1.12",
95 | "postcss-loader": "^0.10.1",
96 | "react-addons-test-utils": "^15.3.0",
97 | "rimraf": "^2.5.4",
98 | "style-loader": "^0.13.1",
99 | "uglify-js": "^2.7.3",
100 | "webpack": "^1.13.2",
101 | "webpack-shell-plugin": "^0.4.3"
102 | },
103 | "dependencies": {
104 | "axios": "^0.13.1",
105 | "core-js": "^2.4.1",
106 | "react": "^15.3.0",
107 | "react-dom": "^15.3.0"
108 | },
109 | "keywords": []
110 | }
111 |
--------------------------------------------------------------------------------