3.0.0-alpha • Published 7 years ago

generator-react-firebase v3.0.0-alpha

Weekly downloads
30
License
MIT
Repository
github
Last release
7 years ago

generator-react-firebase

Yeoman generator for starting projects using React and Firebase (Redux optional)

NPM version NPM downloads Quality Build Status Dependency Status Code Coverage License Code Style

Installation

Install Yeoman and generator-react-firebase using npm (we assume you have pre-installed node.js):

npm install -g yo generator-react-firebase

Before Starting

  1. Do the following in the Firebase Console:
    1. Create both a Firestore Database and Real Time Database within your project
    2. Enable Google and/or Email Sign In Methods in the Authentication tab (required to enable login/signup within your application)

Getting Started

  1. Create a project folder and enter it: mkdir myProject && cd myProject
  2. Generate project: yo react-firebase (project will be named after current folder)
  3. Confirm dependencies are installed: npm i && npm i --prefix functions
  4. Start application: npm start

    Project will default to being named with the name of the folder that it is generated within (in this case myProject)

Whats Next

  1. Deploy your application either manually through firebase-tools or by setting up CI Deployment
  2. Enable APIs for features which were opted into:
  3. Checkout and understand src/config.js. This was generated for you for your local development environment, but is is ignored from git tracking (within .gitignore). You can have different settings within this file based on environment or if multiple developers are running the same code.
  4. Tryout the Sub Generators to add new features to your project quickly
  5. Tryout Firestore (you can generate a new project with yes as the answer to Do you want to use Firestore). Things work mostly the same, but it runs through redux-firestore.

Features

  • React v16.6
  • Material-UI application styling including Navbar
  • Full Authentication with validation (through Email, Google or Github)
  • Async route loading (using react-loadable)
  • Route protection (only view certain pages when logged in)
  • Firebase Functions Setup with function splitting for faster cold-starts (including support within function sub-generator)
  • Account Management Page
  • Automatic Build/Deploy config for multiple CI Providers including:
    • Gitlab (uses pipelines)
    • Travis
  • Component Testing With Jest
  • UI Testing with Cypress

Uses

When opting into redux

Sub generators

Sub generators are included to help speed up the application building process. You can run a sub-generator by calling yo react-firebase:<name of sub-generator> <param1>.

Example: To call the component sub-generator with "SomeThing" as the first parameter write: yo react-firebase:component SomeThing

Path Argument

Another argument can be passed to sub generators (unless otherwise noted) to provide the base path in which you would like to run the generator (starts from src). For example: yo react-firebase:component Car routes/Project runs the component generator within the Project route folder meaning that the component will be added to routes/Project/components instead of the top level src/components folder.

Function

Generates a Cloud Function allowing the user to specify trigger type (from HTTPS, Firestore, RTDB, Auth, or Storage)

A component is best for things that will be reused in multiple places. Our example

command

yo react-firebase:function uppercaser

result

/functions
--/uppercaser
----index.js

For firebase-functions >v1.0.0:

/functions/uppercaser/index.js:

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import { to } from 'utils/async';

const eventName = 'uppercaser';

/**
 * @param  {functions.Event} event - Function event
 * @return {Promise}
 */
async function uppercaserEvent(event) {
  const { params: { pushId }, data } = event;

  console.log('uppercaser onUpdate event:', data.val());

  // Create RTDB for response
  const ref = admin.database().ref(`responses/${eventName}/${pushId}`);

  // Write data to RTDB
  const [writeErr] = await to(ref.set({ hello: 'world' }));

  // Handle errors writing data to RTDB
  if (writeErr) {
    console.error(
      `Error writing response: ${writeErr.message || ''}`,
      writeErr
    );
    throw writeErr;
  }

  // End function execution by returning
  return null;
}

/**
 * Event handler that fires every time data is updated in Firebase Realtime Database.
 *
 * Trigger: `RTDB - onUpdate - '/uppercaser/{pushId}'`
 * @name uppercaser
 * @type {functions.CloudFunction}
 * @public
 */
export default functions.database
  .ref(`/${eventName}/{pushId}`)
  .onUpdate(uppercaserEvent);

For firebase-functions >=v1.0.0:

/functions/uppercaser/index.js:

import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'
import { to } from 'utils/async'

const eventName = 'uppercaser'

/**
 * 
 * @param  {functions.database.DataSnapshot} snap - Data snapshot of the event
 * @param {Function} snap.val - Value after event
 * @param {functions.EventContext} context - Function event context
 * @param {Object} context.auth - Authentication information for the user that triggered the function
 * @return {Promise}
 */
async function uppercaserEvent(snap, context) {
  const { params: { pushId } } = context

  console.log('uppercaser onCreate event:', snap.val())

  // Create RTDB for response
  const ref = admin.database().ref(`responses/${eventName}/${pushId}`)

  // Write data to RTDB
  const [writeErr] = await to(ref.set({ hello: 'world' }))

  // Handle errors writing data to RTDB
  if (writeErr) {
    console.error(`Error writing response: ${writeErr.message || ''}`, writeErr)
    throw writeErr
  }

  // End function execution by returning
  return null
}

/**
 * Cloud Function that is called every time new data is created in Firebase Realtime Database.
 *
 * Trigger: `RTDB - onCreate - '/requests/uppercaser/{pushId}'`
 * @name uppercaser
 * @type {functions.CloudFunction}
 * @public
 */
export default functions.database
  .ref(`/requests/${eventName}/{pushId}`)
  .onCreate(uppercaserEvent)

Note: This sub-generator does not support the Path Argument (functions are already placed within a folder matching their name).

Component

Generates a React component along with an option matching style file (either Javascript or SCSS) and places it within /components.

A component is best for things that will be reused in multiple places. Our example

command

yo react-firebase:component Car

result

/app
--/components
----/Car
------index.js
------Car.enhancer.js // optional
------Car.styles.js // optional (Localized MUI Styling)
------Car.js
------Car.scss // option (SCSS File)

/app/components/Car.js:

import React from 'react'
import PropTypes from 'prop-types'
import classes from './Car.scss'

export const Car = ({ car }) => (
  <div className={classes.container}>
    <span>Car Component</span>
    <pre>{JSON.stringify(car, null, 2)}</pre>
  </div>
)

export default Car

NOTE: Option to use Javascript file for styles is only offered if @material-ui/core is included in package.json

Form

Generates a Redux Form wrapped React component along with a matching scss file and places it within /components.

command

yo react-firebase:form Car

or

yo react-firebase:form CarForm

result

/app
--/components
----/CarForm
------index.js
------CarForm.enhancer.js
------CarForm.js
------CarForm.scss

/app/components/CarForm.js:

import React from 'react'
import PropTypes from 'prop-types'
import classes from './Car.scss'

export const CarForm = ({ car }) => (
  <div className={classes.container}>
    <span>CarForm Component</span>
    <pre>{JSON.stringify(car, null, 2)}</pre>
  </div>
)

export default CarForm

Enhancer

Generates an enhancer for a react component. Also includes an index file that wraps the component in the enhancer.

command

yo react-firebase:enhancer Project

result

/app
--/components
----/Project
------index.js
------Project.enhancer.js

Route

Generates a React component along with a matching component (which has an scss file, an enhancer, and its own index file).

command

yo react-firebase:route Project

result

/app
--/routes
----/Project
------index.js
------components
--------ProjectPage
----------index.js
----------Project.enhancer.js // optional
----------Project.js
----------Project.scss

Module

Generates a React component along with a matching component (which has an scss file, an enhancer, and its own index file).

command

yo react-firebase:module notification

result

/app
--/modules
----/notification
------components
------actions.js
------actionTypes.js
------index.js
------reducer.js

Note: This sub-generator does not support the Path Argument (functions are already placed within a folder matching their name).

Generated Project

Project outputted from generator has a README explaining the full structure and details specific to settings you choose. This includes everything from running your code to deploying it.

Examples

Complete examples of generator output available in Examples

For full projects built out using this as a starting place, check the next section.

Projects Started Using This

open an issue or reach out over gitter if you would like your project to be included

FAQ

  1. Why node 8 instead of a newer version? Cloud Functions runtime was still on 8, which is why that is what is used for the suggested build version as well as the version used when building within CI.

  2. How do I deploy my application? The README of your generated project specifies deployment instructions based on your choices while generating. For an example, checkout any of the README.md files at the root of projects in the examples folder including this one.

  3. How do I add a route?

    1. Use the route sub-generator to add the route: yo react-firebase:route MyRoute
    2. Add a path of the new route to constants/paths (i.e. MYROUTE_PATH)
    3. Add the route to the list of routes in src/routes/index.js
  4. Why enhancers over containers? - For many reasons, here are just a few:

    • separates concerns to have action/business logic move to enhancers (easier for future modularization + optimization)
    • components remain "dumb" by only receiving props which makes them more portable
    • smaller files which are easier to parse
    • functional components can be helpful (along with other tools) when attempting to optimize things
  5. Where are the settings for changing how my project deploys through Continious integration?

    Within .firebaserc under the ci section. These settings are loaded by firebase-ci

  6. How does one override react-redux-firebase and redux-firestore configuration based on the environment? Like adding logging only to staging?

    Add the following to .firebaserc under the branch associated with the environment you wish to change:

    "reduxFirebase": {
      "userProfile": "users",
      "enableLogging": false
    }

    Should look end up looking similar to the following:

    "ci": {
      "copyVersion": true,
      "createConfig": {
        "master": {
          "env": "staging",
          "firebase": {
            "apiKey": "${STAGE_FIREBASE_API_KEY}",
            "authDomain": "some-project.firebaseapp.com",
            "databaseURL": "https://some-project.firebaseio.com",
            "projectId": "some-project",
            "storageBucket": "some-project.appspot.com"
          },
          "reduxFirebase": {
            "userProfile": "users",
            "enableLogging": true
          }
        }
      }
    }

In the future

  • Airbnb linting option (currently only standard)
  • Option to use simple file structure instead of fractal pattern
  • Open to ideas

License

MIT © Prescott Prue

9.0.0

4 years ago

8.3.1

5 years ago

8.3.0

5 years ago

8.2.0

5 years ago

8.1.0

5 years ago

7.6.6

5 years ago

7.6.5

5 years ago

7.6.4

5 years ago

7.6.3

5 years ago

7.6.7

5 years ago

8.0.1

5 years ago

8.0.0

5 years ago

7.6.2

5 years ago

7.6.1

5 years ago

7.6.0

5 years ago

7.5.1

5 years ago

7.5.0

5 years ago

7.4.0

5 years ago

7.3.0

6 years ago

7.2.0

6 years ago

7.1.1

6 years ago

7.1.0

6 years ago

7.0.0

6 years ago

6.3.0

6 years ago

6.2.0

6 years ago

6.1.1

6 years ago

6.1.0

6 years ago

6.0.0

6 years ago

5.7.3

6 years ago

5.7.2

6 years ago

5.7.1

6 years ago

5.7.0

6 years ago

5.6.2

6 years ago

5.6.1

6 years ago

5.6.0

6 years ago

5.5.0

6 years ago

5.3.2

6 years ago

5.4.0

6 years ago

5.3.1

6 years ago

5.3.0

6 years ago

5.2.2

6 years ago

5.2.1

6 years ago

5.2.0

6 years ago

5.1.1

6 years ago

5.1.0

6 years ago

5.0.0

6 years ago

4.1.1

6 years ago

4.1.0

6 years ago

4.0.1

6 years ago

4.0.0

6 years ago

3.5.0

7 years ago

3.4.0

7 years ago

3.3.0

7 years ago

3.2.8

7 years ago

3.2.7

7 years ago

3.2.6

7 years ago

3.2.5

7 years ago

3.2.4

7 years ago

3.2.3

7 years ago

3.2.2

7 years ago

3.2.1

7 years ago

3.2.0

7 years ago

3.1.2

7 years ago

3.1.1

7 years ago

3.1.0

7 years ago

3.0.3

7 years ago

3.0.2

7 years ago

3.0.1

7 years ago

3.0.0

7 years ago

3.0.0-beta.2

7 years ago

3.0.0-beta

7 years ago

3.0.0-alpha.2

7 years ago

3.0.0-alpha

7 years ago

2.3.4

7 years ago

2.3.3

7 years ago

2.3.2

7 years ago

2.3.1

8 years ago

2.3.0

8 years ago

2.2.0

8 years ago

2.1.1

8 years ago

2.1.0

8 years ago

2.1.0-alpha.2

8 years ago

2.1.0-alpha

8 years ago

2.0.7

8 years ago

2.0.6

8 years ago

2.0.5

8 years ago

2.0.4

8 years ago

2.0.3

8 years ago

2.0.2

8 years ago

2.0.1

8 years ago

2.0.0

8 years ago

2.0.0-rc.10

8 years ago

2.0.0-rc.9

8 years ago

2.0.0-rc.8

8 years ago

2.0.0-rc.7

8 years ago

2.0.0-rc.6

8 years ago

2.0.0-rc.5

8 years ago

2.0.0-rc.4

8 years ago

2.0.0-rc.3

8 years ago

2.0.0-rc.2

8 years ago

2.0.0-rc.1

8 years ago

2.0.0-beta.4

8 years ago

2.0.0-beta.3

8 years ago

2.0.0-beta.2

8 years ago

2.0.0-beta

8 years ago

1.4.6

8 years ago

1.4.5

8 years ago

1.4.4

9 years ago

1.4.3

9 years ago

1.4.2

9 years ago

1.4.1

9 years ago

1.4.0

9 years ago

1.3.1

9 years ago

1.3.0

9 years ago

1.2.5

9 years ago

1.2.4

9 years ago

1.2.3

9 years ago

1.2.2

9 years ago

1.2.1

9 years ago

1.2.0

9 years ago

1.1.0

9 years ago

1.0.5

9 years ago

1.0.4

9 years ago

1.0.3

9 years ago

1.0.2

9 years ago

1.0.1

9 years ago

1.0.0

10 years ago

0.1.8

10 years ago

0.1.7

10 years ago

0.1.6

10 years ago

0.1.5

10 years ago

0.1.4

10 years ago

0.1.3

10 years ago

0.1.2

10 years ago

0.1.1

10 years ago

0.1.0

10 years ago

0.0.1

10 years ago

0.0.0

10 years ago