cjmyles / instant-react

React boilerplate including all the essential vitamins and nutrients.

Home Page:https://cjmyles.github.io/instant-react/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Instant React

React boilerplate bundled with React Router, Material-UI, layouts, and Redux (Redux Thunk implementing Ducks with optional localstorage persistence). Integrates seemlessly with the Firebase platform to enable services such as Firebase Authentication, Cloud Firestore, Cloud Storage and Firebase Hosting. Part of the instant suite of rapid application development tools and can be used in conjunction with instant-express if an API/server solution is also required.

Initially created using an ejected version of create-react-app, the framework has been extended to include the following features out the box:

Table of Contents

Creating an App

Similar to create-react-app, you can create an application using instant-tools.

Please note: This will clone the instant-react boilerplate into the specified my-app directory, and the optional -i parameter will install all dependencies.

npx

$ npx instant-tools create react my-app -i

npm

$ npm i instant-tools -g
$ instant create react my-app -i

Please note: This will install the instant-tools CLI globally, which will come in useful later on for generating new project files such as components and Redux modules.

It will create a directory called my-app inside the current folder. Inside that directory, it will generate the initial project structure and install the transitive dependencies:

my-app
├── LICENCE
├── README.md
├── node_modules
├── package.json
├── database.json
├── firebase.json
├── firestore.indexes.json
├── firestore.rules
├── .env
├── .eslintrc
├── .gitignore
├── .prettierrc
├── config
│   ├── default.json
│   ├── development.json
│   ├── env.js
│   ├── paths.js
│   ├── polyfills.js
│   ├── production.json
│   ├── webpack.config.dev.js
│   ├── webpack.config.prod.js
│   └── webpackDevServer.config.js
├── public
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
├── scripts
│   ├── build.js
│   ├── firebase.js
│   └── start.js
│   └── test.js
└── src
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── registerServiceWorker.js
    ├── Routes.js
    ├── Theme.js
    ├── config
        └── theme.js
    ├── containers
        ├── About.js
        ├── Home.js
        ├── PageNotFound.js
        ├── Profile.js
        ├── Settings.js
        └── SignIn.js
    ├── layouts
        └── Default.js
    └── redux
        └── modules
            ├── auth.js
            ├── client.js
            └── reducer.js

Just like create-react-app, instant-react assumes the following.

For the project to build, these files must exist with exact filenames:

  • public/index.html is the page template;
  • src/index.js is the JavaScript entry point.

You can delete or rename the other files.

You may create subdirectories inside src. For faster rebuilds, only files inside src are processed by Webpack.
You need to put any JS and CSS files inside src, otherwise Webpack won’t see them.

Only files inside public can be used from public/index.html.
Read instructions below for using assets from JavaScript and HTML.

You can, however, create more top-level directories.
They will not be included in the production build so you can use them for things like documentation.

Once the installation is done, you can open your project folder:

cd my-app

Inside the newly created project, you can run some built-in commands:

firebase use --add

Associates the project with a Firebase project. You will be provided with a list of Firebase projects to choose from.

Please note: This assumes you have created a Firebase project for this purpose and you've logged into Firebase using the firebase-tools CLI.

Please note: This is currently a pre-requisite and the application won't load without an associated Firebase project. However, this dependency may be removed in the future.

npm start

Runs the app in development mode. Open http://localhost:3000 to view it in the browser.

The page will automatically reload if you make changes to the code. You will see the build errors and lint warnings in the console.

Build errors

npm test

Runs the test watcher in an interactive mode. By default, runs tests related to files changed since the last commit.

Read more about testing.

npm run build

Builds the app for production to the build folder. It correctly bundles React in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.

Your app is ready to be deployed.

firebase deploy

Deploys the build folder to the associated Firebase project, via Firebase Hosting. Once deployed you'll see the deployed URL in the console.

npm run deploy

Builds the app for production and deploys the build folder to the associated Firebase project. A combination of the npm run build and firebase deploy commands.

Core Concepts

Config

instant-react (and in fact most of the instant suite) relies heavily on node-config. Although the default ejected application generated by create-react-app utilizes .env files (you can see how to implement them in this helpful article), instant-react utilizes node-config as it can be used for both client and server-side applications with only slightly varying usage. This ensures consistent behaviour across all the instant tools.

With node-config we can define a standard set of variables or settings that apply across all environments, and then define a specific set of environment variables that can be used to override the defaults.

In our case the settings that apply across all environments are stored in config/default.json; local development settings are stored in config/development.json; and all production settings are stored in config/production.json.

Please note: Sensitive config values should only be committed to the repository after being encrypted. As a consequence, the development.json and production.json files are excluded by git via the .gitignore file by default. Please see Securing Production Config Files for more information.

In addition to the settings you define in these files, the Firebase project settings are automatically pulled down via firebase-tools when the npm start and npm build commands are executed, and added to the application's config object.

Please see the Modfiying Config section for information on how to add custom settings to your application.

Components & Containers

Although not enforced, instant-react adheres to the concept that all reusable React components are stored in src/components. This could include atomic elements such as buttons, alerts or progress bars. Components which map to URL routes are stored in src/containers and should only be referenced once by your application, in the src/Routes.js file (please see Routing for more information). This could include the Homepage, the About page, the Sign-in page and so on. Although similar to components in technical design, containers allow us to separate application pages from the atomic components they utilize.

See the Adding Components & Containers section for information on how to add new components and containers to your applicaton.

Routing

The src/Routes.js file contains the URL routing configuration and implements React Router and Code Splitting.

Routes are split into three different types:

  • Authenticated: Access is only granted if the user is authenticated, e.g Profile page.
  • Unathenticated: Access is only granted if the user is unauthenticated, e.g About page.
  • Applied: Access is granted whether the user is authenticated or unauthenticated, e.g. Homepage.

Attempted access to an Authenticated route by a user that isn't authenticated will result in the user being redirected to /signin and the attempted page URL will be appended as a redirect URL parameter (once successfully signed in, the user will be redirected to that page), e.g http://localhost:3000/signin?redirect=profile.

You'll notice another, special, type of route too:

  • Core: If authentication has been enabled then this will act as an Authenticated route. If authentication has been disabled then this will act as an Unauthenticated route. This can be useful if you want hide or show all routes in one go without having to alter the Routes.js file. Authentication can be enabled or disabled by toggling the app.useAuth setting in config.

Your application can implement any of these routes.

Containers are imported asyncronously so that they are only loaded into memory when the revelant URL route is triggered. This prevents all of our containers being loaded at once unecessarily.

A default 'catch all' route is also specified which displays the PageNotFound container.

See the Routes section for information on how to add new routes to your applicaton.

Material UI is enabled by default and is utilized by the core instant-react components and containers. In addition, instant-react provides template theming, styling properties and layouts.

Material UI utilises the Google Roboto font and Material Font Icons which are referenced in public/index.html.

See the Themeing, Styling and Layouts sections for information on how to customize the look and feel of your application.

Redux

instant-react has been configured to utilise Redux, Redux Thunk and Redux Localstorage. We've opted to use the Ducks Modular Redux pattern for the core Redux modules, but you don't have to.

Redux is useful for large applications and can be integrated into your application with very little effort. Please see the Using Redux section for information on how to use Redux in your application.

Firebase

instant-react has been designed to integrate seemlessly with Firebase. This means it's incredibly easy to utilise Firebase services such as Firebase Authentication, Cloud Firestore, Cloud Storage and Firebase Hosting.

Authentication

To enable authentication, please ensure the app.useAuth setting in config is set to true.

Next, head to the Firebase console and ensure one of the Sign-in providers has been enabled in the "Sign-in method" section of "Authentication".

Please note: instant-react currently only supports the Email/Password provider. As a consequence, you'll need to manually add users to the "Users" section of "Authentication".

Restart the React server (remember, config settings don't take effect without restarting the server) and navigate to http://localhost:3000/signin.

Helmet

React Helmet enables us to modify page headers at runtime, for example the title or meta data attributes.

See Using Helmet for more information on how to customize page headers at runtime.

ESLint & Prettier

ESLintESLint & Prettier have been configured to ensure consistent code formatting and style. ESLint highlights areas of the code that don't adhere to a coding standard, and Prettier automatically fixes code to match the standard. To enable these to work in VSCode, you'll need to install the ESLint and Prettier extensions, as well as modifying your settings so that files can be updated on save.

"editor.formatOnSave": true

Prettier is also configured to run as a precommit hook so that any staged files are automatically updated before commit.

For more information please see this useful article.

Customization

package.json

It's recommended that you modify the package.json file to customise the name and description fields for your project (and add a version field if necessary - Semantic Versioning is strongly recommended). This information is accessed by the application and displayed in the About page by default (via the /about URL route).

It's also recommended that you change the proxy value if you intend to make use of server requests in development mode.

Please see the Fetch Requests section for more information on using an external server for requests.

Modifying Config

Assuming your config/default.json file looks like this

{
  "testing": 123
}

It would be possible to access this value from within your React code as follows.

import config from 'config';
console.log(CONFIG.testing);

Please note: If you add new configuration values to these files and you're running Webpack Dev Server (by virtue of running npm start, then you'll need to restart the server in order to view these settings in your application).

Please note: The CONFIG object has been added to the globals option of .eslintrc to hide warnings regarding the non-declaration of this variable.

Please see the node-config documentation for more information.

Fetch Requests

As with any React application, you can make use of the Fetch API to fetch resources, such as requesting data from an API.

To serve data from an API using the same host as the React application, you can add the server URL to package.json, so that requests like fetch('/api/todos) will be proxied to the server.

package.json

"proxy": "http://localhost:5001/[node-project-id]/us-central1/app/"

Please see the create-react-app docs for more information.

To ease the process of making server requests, instant-react is bundled with a request helper that utilizes the instant-request package. For this to work you'll need to modify your config to include the URI prefix that all requests will use (by default this is just "/api").

default.json

"api": {
  "url": "/api"
}

Now you can import the request helper into your code from instant-react-core, and create a new instance of the class.

import Request from 'instant-react-core/lib/utils/request';
const request = new Request();

It's now possible to make POST, GET, PUT and DELETE requests by using your new request instance.

const createTodo = async () => {
  try {
    const todo = await request.post('/todos', {
      id: '1',
      description: 'Book holiday',
    });
    return todo;
  } catch (error) {
    throw error;
  }
};

const getTodos = async () => {
  try {
    const todos = await request.get('/todos');
    return todos;
  } catch (error) {
    throw error;
  }
};

const updateTodo = async () => {
  try {
    const todo = await request.put('/todos/1', { completed: true });
    return todo;
  } catch (error) {
    throw error;
  }
};

const deleteTodo = async () => {
  try {
    await request.delete('/todos/1');
  } catch (error) {
    throw error;
  }
};

This type of code can be utilized in your Redux modules. Please see the Using Redux section for information on how to use Redux in your application.

Addding Components & Containers

Adding Routes

@todo

Themeing

@todo

Styling

@todo

Layouts

@todo

Using Redux

@todo

Using Helmet

To use Helmet, simply import the library and wrap your page headers in a <Helmet> tag.

import React, { Fragment } from 'react';
import { Helmet } from 'react-helmet';

function() {
  return (
    <Fragment>
      <Helmet>
        <title>Home</title>
        <link rel="canonical" href="http://mysite.com/example" />
      </Helmet>
      <div>
        Your content
      </div>
    </Fragment>
  );
}

FAQ

How does node-config know which environment file to use?

The process.env.NODE_ENV variable is set to development in package.json when the npm start command is executed, and Firebase automatically sets the process.env.NODE_ENV variable to production in hosting. The

How does node-config work with Webpack?

node-config doesn't work with Webpack out of the box because it reads the config files at runtime, which can't be done when the code is running on a browser. Therefore, the Webpack config file has been amended to enable config values to be read at runtime (see https://github.com/lorenwest/node-config/wiki/Webpack-Usage#option-2 for more information).

Please note: We opted for Option 2 over Option 4 (even though 4 enabled the config get() method) as Option 4 causes warnings to be displayed. It may be worth reassessing this in future versions of node-config, Webpack and react-scripts.

Contributing

We'd greatly appreciate any contribution you make.

License

MIT

About

React boilerplate including all the essential vitamins and nutrients.

https://cjmyles.github.io/instant-react/

License:MIT License


Languages

Language:JavaScript 96.1%Language:HTML 2.6%Language:CSS 1.3%