Skip to content

Commit bda4ed5

Browse files
authored
Update Complete Material Example (#269)
Complete Material Example updates including: * Webpack 3 🎆 * Heavily simplified/improved build setup (all config lives in `project.config.js` at base level) * `.eslintrc` no using yaml format instead of JSON * `firebase-ci` is used for deployment instead of logic within application * `NewProjectTile` component includes delete button (if you are owner) and handles long names * Basic database and storage rules included
1 parent 49b5deb commit bda4ed5

File tree

67 files changed

+3885
-2309
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+3885
-2309
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
coverage/**
2+
**/node_modules/**
3+
dist/**
4+
src/index.html
5+
blueprints/**
6+
src/config.js

examples/complete/material/.eslintrc

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,35 @@
1-
{
2-
"parser" : "babel-eslint",
3-
"extends" : [
4-
"standard",
5-
"standard-react",
6-
"prettier/react"
7-
],
8-
"plugins": [
9-
"babel",
10-
"prettier"
11-
],
12-
"env" : {
13-
"browser" : true
14-
},
15-
"globals" : {
16-
"__DEV__" : false,
17-
"__PROD__" : false,
18-
"__DEBUG__" : false,
19-
"__COVERAGE__" : false,
20-
"__BASENAME__" : false
21-
},
22-
"rules": {
23-
"semi" : [2, "never"],
24-
"max-len": [2, 120, 2],
25-
"generator-star-spacing": 0,
26-
"babel/generator-star-spacing": 1,
27-
"jsx-quotes": ["error", "prefer-single"],
28-
"prettier/prettier": ["error", {
29-
"singleQuote": true,
30-
"trailingComma": "es6",
31-
"semi": false
32-
}]
33-
}
34-
}
1+
root: true
2+
3+
parser: babel-eslint
4+
5+
extends: [standard, standard-react, prettier, prettier/react]
6+
plugins: [babel, react, prettier]
7+
8+
env:
9+
browser: true
10+
es6: true
11+
node: true
12+
13+
ecmaFeatures:
14+
jsx: true
15+
modules: true
16+
17+
globals:
18+
__DEV__: false
19+
__COVERAGE__: false
20+
__TEST__: false
21+
22+
rules:
23+
semi: [2, 'never']
24+
no-console: 'error'
25+
jsx-quotes: ['error', 'prefer-double']
26+
prettier/prettier: ['error', {
27+
singleQuote: true,
28+
trailingComma: 'es6',
29+
semi: false,
30+
bracketSpacing: true,
31+
jsxBracketSameLine: true,
32+
printWidth: 80,
33+
tabWidth: 2,
34+
useTabs: false
35+
}]

examples/complete/material/.firebaserc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,43 @@
22
"projects": {
33
"dev": "redux-firebasev3",
44
"stage": "redux-firebasev3",
5+
"master": "redux-firebasev3",
56
"prod": "redux-firebasev3"
7+
},
8+
"ci": {
9+
"createConfig": {
10+
"master": {
11+
"version": "${npm_package_version}",
12+
"env": "development",
13+
"firebase": {
14+
"apiKey": "AIzaSyCTUERDM-Pchn_UDTsfhVPiwM4TtNIxots",
15+
"authDomain": "redux-firebasev3.firebaseapp.com",
16+
"databaseURL": "https://redux-firebasev3.firebaseio.com",
17+
"projectId": "redux-firebasev3",
18+
"storageBucket": "redux-firebasev3.appspot.com"
19+
},
20+
"reduxFirebase": {
21+
"userProfile": "users",
22+
"enableLogging": false,
23+
"updateProfileOnLogin": false
24+
}
25+
},
26+
"prod": {
27+
"version": "${npm_package_version}",
28+
"env": "production",
29+
"firebase": {
30+
"apiKey": "AIzaSyCTUERDM-Pchn_UDTsfhVPiwM4TtNIxots",
31+
"authDomain": "redux-firebasev3.firebaseapp.com",
32+
"databaseURL": "https://redux-firebasev3.firebaseio.com",
33+
"projectId": "redux-firebasev3",
34+
"storageBucket": "redux-firebasev3.appspot.com"
35+
},
36+
"reduxFirebase": {
37+
"userProfile": "users",
38+
"enableLogging": false,
39+
"updateProfileOnLogin": false
40+
}
41+
}
42+
}
643
}
744
}

examples/complete/material/.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
**/*.log
33
.DS_Store
44
**/.DS_Store
5-
6-
node_modules
5+
**/dist
6+
**/node_modules
77
coverage
8+
src/config.js
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
dist: trusty
2+
3+
sudo: false
4+
5+
language: node_js
6+
7+
node_js:
8+
- 6.11.1 # runtime used within Firebase functions
9+
10+
notifications:
11+
email:
12+
on_failure: change
13+
on_success: change
14+
15+
branches:
16+
only:
17+
- master
18+
- stage
19+
- prod
20+
21+
cache:
22+
bundler: true
23+
directories:
24+
- node_modules # NPM packages
25+
26+
install:
27+
- npm set progress=false
28+
- npm i
29+
- npm i -g firebase-ci
30+
31+
script:
32+
- firebase-ci createConfig
33+
- npm run lint
34+
- npm run test
35+
- npm run build
36+
37+
after_success:
38+
- firebase-ci deploy -s # deploy without CI actions since createConfig is called earlier

examples/complete/material/README.md

Lines changed: 67 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
[![License][license-image]][license-url]
44
[![Code Style][code-style-image]][code-style-url]
55

6-
This is a "real-world" example and is deployed to [demo.react-redux-firebase.com](https://demo.react-redux-firebase.com). Project was based on the output of [`generator-react-firebase`](https://github.com/prescottprue/generator-react-firebase), which generates a full project starter with `react-redux-firebase` included.
6+
## What is Shown
7+
* Route protection using `redux-auth-wrapper`
8+
* Data input/validation using `redux-form`
9+
* Async & Sync route loading
10+
* Real CI and Deployment settings (including `prod` and `stage` environments)
11+
* Using different instances of Firebase based on environment
712

813
## Getting Started
914

@@ -13,37 +18,38 @@ This is a "real-world" example and is deployed to [demo.react-redux-firebase.com
1318

1419
While developing, you will probably rely mostly on `npm start`; however, there are additional scripts at your disposal:
1520

16-
|`npm run <script>`|Description|
17-
|------------------|-----------|
18-
|`start`|Serves your app at `localhost:3000`. HMR will be enabled in development.|
19-
|`build:dev`|Same as `build` but overrides `NODE_ENV` to "development".|
20-
|`build:prod`|Same as `build` but overrides `NODE_ENV` to "production".|
21-
|`lint`|Lint all `.js` files.|
22-
|`lint:fix`|Lint and fix all `.js` files. [Read more on this](http://eslint.org/docs/user-guide/command-line-interface.html#fix).|
21+
|`npm run <script>` |Description|
22+
|-------------------|-----------|
23+
|`start` |Serves your app at `localhost:3000` and displays [Webpack Dashboard](https://github.com/FormidableLabs/webpack-dashboard)|
24+
|`start:simple` |Serves your app at `localhost:3000` without [Webpack Dashboard](https://github.com/FormidableLabs/webpack-dashboard)|
25+
|`build` |Builds the application to ./dist|
26+
|`test` |Runs unit tests with Karma. See [testing](#testing)|
27+
|`test:watch` |Runs `test` in watch mode to re-run tests when changed|
28+
|`lint` |[Lints](http://stackoverflow.com/questions/8503559/what-is-linting) the project for potential errors|
29+
|`lint:fix` |Lints the project and [fixes all correctable errors](http://eslint.org/docs/user-guide/command-line-interface.html#fix)|
2330

24-
## What is Shown
25-
* Route protection using `redux-auth-wrapper`
26-
* Data input/validation using `redux-form`
27-
* Async & Sync route loading
28-
* Real CI and Deployment settings (including `prod` and `stage` environments)
29-
* Using different instances of Firebase based on environment
31+
[Husky](https://github.com/typicode/husky) is used to enable `prepush` hook capability. The `prepush` script currently runs `eslint`, which will keep you from pushing if there is any lint within your code. If you would like to disable this, remove the `prepush` script from the `package.json`.
3032

3133
## Application Structure
3234

3335
The application structure presented in this boilerplate is **fractal**, where functionality is grouped primarily by feature rather than file type. Please note, however, that this structure is only meant to serve as a guide, it is by no means prescriptive. That said, it aims to represent generally accepted guidelines and patterns for building scalable applications. If you wish to read more about this pattern, please check out this [awesome writeup](https://github.com/davezuko/react-redux-starter-kit/wiki/Fractal-Project-Structure) by [Justin Greenberg](https://github.com/justingreenberg).
3436

3537
```
3638
.
37-
├── bin # Build/Start scripts
38-
├── config # Project and build configurations
39-
├── server # Express application that provides Webpack middleware
39+
├── build # All build-related configuration
40+
│ └── create-config # Script for building config.js in ci environments
41+
│ └── karma.config.js # Test configuration for Karma
42+
│ └── webpack.config.js # Environment-specific configuration files for webpack
43+
├── server # Express application that provides webpack middleware
4044
│ └── main.js # Server application entry point
4145
├── src # Application source code
4246
│ ├── index.html # Main HTML page container for app
4347
│ ├── main.js # Application bootstrap and rendering
48+
│ ├── normalize.js # Browser normalization and polyfills
4449
│ ├── components # Global Reusable Presentational Components
4550
│ ├── containers # Global Reusable Container Components
4651
│ ├── layouts # Components that dictate major page structure
52+
│ │ └── CoreLayout # Global application layout in which to render routes
4753
│ ├── routes # Main route definitions and async split points
4854
│ │ ├── index.js # Bootstrap main application routes with store
4955
│ │ └── Home # Fractal route
@@ -53,35 +59,66 @@ The application structure presented in this boilerplate is **fractal**, where fu
5359
│ │ ├── container # Connect components to actions and store
5460
│ │ ├── modules # Collections of reducers/constants/actions
5561
│ │ └── routes ** # Fractal sub-routes (** optional)
56-
│ ├── static # Static assets (not imported anywhere in source code)
62+
│ ├── static # Static assets
5763
│ ├── store # Redux-specific pieces
5864
│ │ ├── createStore.js # Create and instrument redux store
5965
│ │ └── reducers.js # Reducer registry and injection
6066
│ └── styles # Application-wide styles (generally settings)
67+
├── project.config.js # Project configuration settings (includes ci settings)
68+
└── tests # Unit tests
6169
```
6270

63-
## Learning Resources
71+
### Routing
72+
We use `react-router` [route definitions](https://github.com/ReactTraining/react-router/blob/v3/docs/API.md#plainroute) (`<route>/index.js`) to define units of logic within our application. See the [application structure](#application-structure) section for more information.
6473

65-
* [Starting out with react-redux-starter-kit](https://suspicious.website/2016/04/29/starting-out-with-react-redux-starter-kit/) is an introduction to the components used in this starter kit with a small example in the end.
74+
## Testing
75+
To add a unit test, create a `.spec.js` file anywhere inside of `./tests`. Karma and webpack will automatically find these files, and Mocha and Chai will be available within your test without the need to import them.
6676

67-
### Production
77+
## Production
6878

69-
Build code before deployment by running `npm run build:prod`.
79+
Build code before deployment by running `npm run build`. There are multiple options below for types of deployment, if you are unsure, checkout the Firebase section.
7080

7181
### Deployment
82+
7283
1. Login to [Firebase](firebase.google.com) (or Signup if you don't have an account) and create a new project
7384
2. Install cli: `npm i -g firebase-tools`
74-
3. Login: `firebase login`
7585

76-
#### CI
77-
**Note:** The next steps automatically through config set in the `.travis.yml`. Use `firebase login:ci` to generate a token and set it to `FIREBASE_TOKEN` within your travis config.
86+
#### CI Deploy (recommended)
87+
**Note**: Config for this is located within `travis.yml`
88+
`firebase-ci` has been added to simplify the CI deployment process. All that is required is providing authentication with Firebase:
7889

79-
#### Local
80-
1. Build Project: `npm run build`
81-
2. Confirm Firebase config by running locally: `firebase serve`
82-
3. Deploy to firebase: `firebase deploy`
90+
1. Login: `firebase login:ci` to generate an authentication token (will be used to give Travis-CI rights to deploy on your behalf)
91+
1. Set `FIREBASE_TOKEN` environment variable within Travis-CI environment
92+
1. Run a build on Travis-CI
8393

94+
If you would like to deploy to different Firebase instances for different branches (i.e. `prod`), change `ci` settings within `.firebaserc`.
95+
96+
For more options on CI settings checkout the [firebase-ci docs](https://github.com/prescottprue/firebase-ci)
97+
98+
#### Manual deploy
99+
100+
1. Run `firebase:login`
101+
1. Initialize project with `firebase init` then answer:
102+
* What file should be used for Database Rules? -> `database.rules.json`
103+
* What do you want to use as your public directory? -> `build`
104+
* Configure as a single-page app (rewrite all urls to /index.html)? -> `Yes`
105+
* What Firebase project do you want to associate as default? -> **your Firebase project name**
106+
1. Build Project: `npm run build`
107+
1. Confirm Firebase config by running locally: `firebase serve`
108+
1. Deploy to firebase: `firebase deploy`
109+
**NOTE:** You can use `firebase serve` to test how your application will work when deployed to Firebase, but make sure you run `npm run build` first.
110+
111+
[npm-image]: https://img.shields.io/npm/v/material.svg?style=flat-square
112+
[npm-url]: https://npmjs.org/package/material
113+
[travis-image]: https://img.shields.io/travis/testuser/material/master.svg?style=flat-square
114+
[travis-url]: https://travis-ci.org/testuser/material
115+
[daviddm-image]: https://img.shields.io/david/testuser/material.svg?style=flat-square
116+
[daviddm-url]: https://david-dm.org/testuser/material
117+
[climate-image]: https://img.shields.io/codeclimate/github/testuser/material.svg?style=flat-square
118+
[climate-url]: https://codeclimate.com/github/testuser/material
119+
[coverage-image]: https://img.shields.io/codeclimate/coverage/github/testuser/material.svg?style=flat-square
120+
[coverage-url]: https://codeclimate.com/github/testuser/material
84121
[license-image]: https://img.shields.io/npm/l/material.svg?style=flat-square
85-
[license-url]: https://github.com/prescottprue/material/blob/master/LICENSE
122+
[license-url]: https://github.com/testuser/material/blob/master/LICENSE
86123
[code-style-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square
87124
[code-style-url]: http://standardjs.com/

examples/complete/material/bin/compile.js

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const webpackConfig = require('../config/webpack.config')
44
const project = require('../config/project.config')
55

66
// Wrapper around webpack to promisify its compiler and supply friendly logging
7-
const webpackCompiler = (webpackConfig) =>
7+
const webpackCompiler = webpackConfig =>
88
new Promise((resolve, reject) => {
99
const compiler = webpack(webpackConfig)
1010

@@ -34,22 +34,24 @@ const webpackCompiler = (webpackConfig) =>
3434

3535
const compile = () => {
3636
debug('Starting compiler.')
37-
return Promise.resolve()
38-
.then(() => webpackCompiler(webpackConfig))
39-
// .then(stats => {
40-
// if (stats.warnings.length && project.compiler_fail_on_warning) {
41-
// throw new Error('Config set to fail on warning, exiting with status code "1".')
42-
// }
43-
// debug('Copying static assets to dist folder.')
44-
// fs.copySync(project.paths.public(), project.paths.dist())
45-
// })
46-
.then(() => {
47-
debug('Compilation completed successfully.')
48-
})
49-
.catch((err) => {
50-
debug('Compiler encountered an error.', err)
51-
process.exit(1)
52-
})
37+
return (
38+
Promise.resolve()
39+
.then(() => webpackCompiler(webpackConfig))
40+
// .then(stats => {
41+
// if (stats.warnings.length && project.compiler_fail_on_warning) {
42+
// throw new Error('Config set to fail on warning, exiting with status code "1".')
43+
// }
44+
// debug('Copying static assets to dist folder.')
45+
// fs.copySync(project.paths.public(), project.paths.dist())
46+
// })
47+
.then(() => {
48+
debug('Compilation completed successfully.')
49+
})
50+
.catch(err => {
51+
debug('Compiler encountered an error.', err)
52+
process.exit(1)
53+
})
54+
)
5355
}
5456

5557
compile()

0 commit comments

Comments
 (0)