The Wayback Machine - https://web.archive.org/web/20230306004628/https://github.com/neonexus/sails-react-bootstrap-webpack
Skip to content

neonexus/sails-react-bootstrap-webpack

release
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

Updated GitHub CodeQL config. Fixed npm audit issues. Updated dependencies.
a5e6541

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
June 6, 2020 16:35
June 6, 2020 16:35
June 6, 2020 16:35
June 6, 2020 16:35

sails-react-bootstrap-webpack

Travis CI status

This is an opinionated base Sails v1 application, using Webpack to handle Bootstrap (using SASS) and React builds. It is designed such that, one can build multiple React frontends (an admin panel, and a customer site maybe), that use the same API backend. This allows developers to easily share React components across different frontends / applications. Also, because the backend and frontend are in the same repo (and the frontend is compiled before it is handed to the end user), they can share NPM libraries, like Moment.js

Need help? Want to hire me to build your next app or prototype? You can contact me any time via Gitter: Join the chat at https://gitter.im/sails-react-bootstrap-webpack/community

Main Features

  • Automatic (incoming) request logging (manual outgoing), via Sails models / hooks.
  • Setup for Webpack auto-reload dev server.
  • Setup so Sails will serve Webpack-built bundles as separate apps (so, a marketing site, and an admin site can live side-by-side).
  • Custom functions to make pagination simple.
  • Includes react-bootstrap to make using Bootstrap styles / features with React easier.
  • Schema validation and enforcement for PRODUCTION. This repo is set up for MySQL. If you plan to use a different datastore, you will likely want to disable the schema validation and enforcement feature inside config/bootstrap.js. See schema validation and enforcement for more info.
  • New passwords can be checked against the PwnedPasswords API. If there is a single hit for the password, an error will be given, and the user will be forced to choose another. See PwnedPasswords integration for more info.

Branch Warning

The master branch is experimental, and the release branch (or the releases section) is where one should base their use of this template.

master is volatile, likely to change at any time, for any reason; this includes git push --force updates.

FINAL WARNING: DO NOT RELY ON THE MASTER BRANCH!

v3.0.0 Warning

Moving from v5 -> v6 of the React Router can be a serious undertaking (see the v5 -> v6 migration guide).

If you would like to use v5 of React Router, make sure you are cloning v2 of this repo.

Current Dependencies

See the package.json for more details.

How to Use

This repo is not installable via npm. Instead, GitHub provides a handy "Use this template" (green) button at the top of this page. That will create a special fork of this repo (so there is a single, init commit, instead of the commit history from this repo).

Configuration

In the config folder, there is the local.js.sample file, which is meant to be copied to local.js. This file (local.js, not the sample) is ignored by Git, and intended for use in local development, NOT remote servers. Generally one would use environment variables for remote server configuration (and this repo is already setup to handle environment variable configuration for both DEV and PROD). See: config/env/development.js and config/env/production.js.

Want to configure the "X-Powered-By" header?

Sails, by default, has middleware (akin to Express.js Middleware, Sails is built on Express.js after all...). Inside of config/http.js we create our own X-Powered-By header, using Express.js Middleware.

Scripts built into package.json:

Command Description
npm run start Will run both npm run lift and npm run open:client in parallel.
npm run open:client Will run the Webpack Dev Server and open a browser tab / window.
npm run lift The same thing as sails lift or node app.js; will "lift our Sails" instance (aka starting the API).
npm run lift:prod The same thing as sails lift --prod or NODE_ENV=production node app.js.
npm run debug Alias for node --inspect app.js.
npm run build Will run npm run clean, then will build production-ready files with Webpack in the .tmp/public folder.
npm run build:dev Same thing as npm run build, except that it will not optimize the files, retaining newlines and empty spaces.
npm run clean Will delete everything in the .tmp folder.
npm run lines Will count the lines of code in the project, minus .gitignore'd files, for funzies. There are currently about 8k custom lines in this repo (views, controllers, helpers, hooks, etc).
npm run test Run Mocha tests. Everything starts in the test/startTests.js file.
npm run coverage Runs NYC coverage reporting of the Mocha tests, which generates HTML in test/coverage.

Environment Variables

There are a few environment variables that the remote configuration files are set up for. There are currently 3 variables that change names between DEV and PROD; this is intentional, and has proven very useful in my experience. DEV has shorter names like DB_HOST, where PROD has fuller names like DB_HOSTNAME. This helps with ensuring you are configuring the correct remote server, and has prevented accidental DEV deployments to PROD.

If you DO NOT like this behavior, and would prefer the variables stay the same across your environments, feel free to change them in config/env/development.js and config/env/production.js

Variable Default Description
ASSETS_URL "" (empty string) Webpack is configured to modify static asset URLs to point to a CDN, like CloudFront. MUST end with a slash " / ", or be empty.
BASE_URL https://myapi.app The address of the Sails instance.
   DEV: DB_HOST
PROD: DB_HOSTNAME
localhost The hostname of the datastore.
   DEV: DB_USER
PROD: DB_USERNAME
   DEV: root
PROD: produser
Username of the datastore.
   DEV: DB_PASS
PROD: DB_PASSWORD
   DEV: mypass
PROD: prodpass
Password of the datastore.
DB_NAME    DEV: myapp
PROD: prod
The name of the database inside the datastore.
DB_PORT 3306 The port number for the datastore.
DB_SSL true If the datastore requires SSL, set this to "true".
SESSION_SECRET "" (empty string) Used to sign cookies, and SHOULD be set, especially on PRODUCTION environments.

Request Logging

Automatic incoming request logging, is a 2 part process. First, the request-logger hook gathers info from the request, and creates a new RequestLog record, making sure to mask anything that may be sensitive, such as passwords. Then, a custom response gathers information from the response, again, scrubbing sensitive data (using the customToJSON feature of Sails models) to prevent leaking of password hashes, or anything else that should never be publicly accessible. The keepModelsSafe helper and the custom responses (such as ok or serverError) are responsible for the final leg of request logs.

Using Webpack

Local Dev

The script npm run open:client will start the auto-reloading Webpack development server, and open a browser window. When you save changes to assets (React files mainly), it will auto-compile the update, then refresh the browser automatically.

Remote Builds

The script npm run build will make Webpack build all the proper assets into the .tmp/public folder. Sails will serve assets from this folder.

If you want to build assets, but retain spaces / tabs for debugging, you can use npm run build:dev.

Configuration

The webpack configuration can be found in the webpack folder. The majority of the configuration can be found in common.config.js. Then, the other 3 files, such as dev.config.js extend the common.config.js file.

Building with React

React source files live in the assets/src folder. It is structured in such a way, where the index.jsx is really only used for local development (to help Webpack serve up the correct "app"). Then, there are the individual "apps", main and admin. These files are used as Webpack "entry points", to create 2 separate application bundles.

In a remote environment, Sails will look at the first subdirectory requested, and use that to determine which index.html file it needs to actually return. So, in this case, the "main" application will get built in .tmp/public/main, where the CSS is .tmp/public/main/bundle.css, the JavaScript is .tmp/public/main/bundle.js, and the HTML is .tmp/public/main/index.html. To view the main application, one would just go to http://mydomain/ which gets redirected to /main (because we need to know what application we are using, we need a subdirectory), and now Sails will serve the main application. Whereas, if one were to go to http://mydomain/admin, Sails would now serve the admin application bundle (aka .tmp/public/admin/index.html, .tmp/public/admin/bundle.css, etc...).

Schema Validation and Enforcement

Inside config/bootstrap.js is a bit of logic (HEAVILY ROOTED IN NATIVE MySQL QUERIES), which validates column types in the PRODUCTION database (aka sails.config.models.migrate === 'safe'), then will validate foreign key indexes. If there are too many columns, or there is a missing index, or incorrect column type, the logic will console.error any issues, then process.exit(1) (kill) the Sails server. The idea here, is that if anything is out of alignment, Sails will fail to lift, which will mean failure to deploy on PRODUCTION, preventing accidental, invalid live deployments; a final safety net if you will.

If you DO NOT want schema validation

... then you have 2 options:

  • Set sails.config.models.validateOnBootstrap = false at the bottom of config/models.js.
  • OR replace the contents of config/bootstrap.js with the following:
module.exports.bootstrap = function(next) {
    // You must call the callback function, or Sails will fail to lift!
    next();
};

PwnedPasswords.com Integration

When a new password is being created, it is checked with the PwnedPasswords.com API. This API uses a k-anonymity model, so the password that is searched for is never exposed to the API. Basically, the password is hashed, then the first 5 characters are sent to the API, and the API returns any hashes that start with those 5 characters, including the amount of times that hash (aka password) has been found in known security breaches.

This functionality is turned on by default, and can be shutoff per-use, or globally throughout the app. sails.helpers.isPasswordValid can be used with skipPwned option set to true, to disable the check per use (see api/controllers/common/login.js for example). Inside of config/security.js, the variable checkPwnedPasswords can be set to false to disable it globally.

What about SEO?

I recommend looking at prerender.io. They offer a service (free up to 250 pages) that caches the end result of a JavaScript-rendered view (React, Vue, Angular), allowing search engines to crawl otherwise un-crawlable web views. You can use the service in a number of ways. One way, is to use the prerender-node package. To use it with Sails, you'll have to add it to the HTTP Middleware. Here's a quick example:

middleware: {

    order: [
        'cookieParser',
        'session',
        'bodyParser',
        'prerender', // reference our custom middleware found below;
                     // we run this before compression and routing,
                     // because it is a proxy, saving time and resources
        'compress',
        'router',
        'assetLog',
        'www',
        'favicon'
    ],

    prerender: require('prerender-node').set('prerenderToken', 'YOUR_TOKEN')

}

Useful Links

Version info

This app was originally generated on Fri Mar 20 2020 17:39:04 GMT-0500 (Central Daylight Time) using Sails v1.2.3.

Code Coverage

The current code coverage can be viewed here.