Skip to content

Commit

Permalink
Update GA tracking, DB scripts, and README.md (#470)
Browse files Browse the repository at this point in the history
  • Loading branch information
koistya authored Nov 26, 2019
1 parent f6c97b2 commit 983854f
Show file tree
Hide file tree
Showing 15 changed files with 221 additions and 51 deletions.
6 changes: 3 additions & 3 deletions .env.production
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ JWT_NAME=__session
# https://www.postgresql.org/docs/current/static/libpq-envars.html

PGHOST=/cloudsql/<project-id>:<region>:<db-instance>
PGUSER=<user>
PGDATABASE=<database>
PGPASSWORD=<password>
# PGUSER=<user>
# PGDATABASE=<database>
# PGPASSWORD=<password>
PGAPPNAME=rsk
PGSSLMODE=
PGDEBUG=false
Expand Down
44 changes: 32 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<img src="https://api.dependabot.com/badges/status?host=github&repo=kriasoft/react-firebase-starter" alt="Dependabot" height="20" />
<a href="https://opencollective.com/react-firebase-starter"><img src="https://opencollective.com/react-firebase-starter/backers/badge.svg?maxAge=3600" height="20"></a>
<a href="https://twitter.com/ReactStarter"><img src="https://img.shields.io/twitter/follow/ReactStarter.svg?style=social&amp;label=Follow&amp;maxAge=3600" alt="Twitter" height="20"></a>
<a href="https://t.me/ReactStarter"><img src="https://img.shields.io/badge/chat-Telegram-green.svg?style=social&amp;maxAge=3600" height="20"></a>
<a href="https://discord.gg/2nKEnKq"><img src="https://img.shields.io/badge/chat-Discord-green.svg?style=social&amp;maxAge=3600" height="20"></a>
</h1>

**React Starter Kit** _for Firebase_ is a popular project template (aka, boilerplate) for building
Expand All @@ -13,11 +13,11 @@ provided by <a href="https://cloud.google.com/">Google Cloud</a> (Cloud SQL, Clo
hosting, and file storage). It allows you to save time and build upon a solid foundation and
design patterns.

<p align="center"><strong>View</strong> <a href="https://firebase.reactstarter.com">online demo</a> (<a href="https://firebase.reactstarter.com/graphql">API</a>, <a href="https://firebase.reactstarter.com/graphql/model">data model</a>) &nbsp;|&nbsp; <strong>Follow us</strong> on <a href="https://twitter.com/ReactStarter">Twitter</a> &nbsp;|&nbsp; <strong>Get FREE support</strong> on <a href="https://t.me/ReactStarter">Telegram</a> &nbsp;|&nbsp; <a href="https://angel.co/company/kriasoft/jobs/"><strong>We're hiring!</strong></a></p>
<p align="center"><strong>View</strong> <a href="https://firebase.reactstarter.com">online demo</a> (<a href="https://firebase.reactstarter.com/graphql">API</a>, <a href="https://firebase.reactstarter.com/graphql/model">data model</a>) &nbsp;|&nbsp; <strong>Follow us</strong> on <a href="https://twitter.com/ReactStarter">Twitter</a> &nbsp;|&nbsp; <strong>Get FREE support</strong> on <a href="https://discord.gg/2nKEnKq">Discord</a> &nbsp;|&nbsp; <a href="https://angel.co/company/kriasoft/jobs/"><strong>We're hiring!</strong></a></p>

---

This project was bootstraped with [React Starter Kit for Firebase][rfs] by [Kriasoft][kriasoft].
This project was bootstrapped with [React Starter Kit for Firebase][rfs] by [Kriasoft][kriasoft].

### Tech Stack

Expand Down Expand Up @@ -107,18 +107,38 @@ In order to re-compile GraphQL fragments, run `yarn relay` or `yarn relay --watc

### How to Migrate Database Schema

While the app is in development, you can use a simplified migration workflow by
creating a backup of your existing database, making changes to the existing
migration file (see `migrations/20180101000000_initial.js`), re-apply the
migration and restore data from the backup file (`backup.sql`):

```bash
$ yarn db-change # Create a new database migration file
$ yarn db-migrate # Migrate database to the latest version
$ yarn db-rollback # Rollback the latest migration
$ yarn db-backup --env=prod # Write database backup to backup.sql
$ yarn db-restore --env=dev # Restore database from backup.sql
$ yarn db # Open PostgreSQL shell (for testing/debugging)
$ yarn db-backup --env=dev # Or, yarn db-backup --env=test
$ yarn db-reset-dev # Or, yarn db-reset-test
```

Upon deployment to production, switch to normal migration workflow:

```bash
$ yarn db-change <name> # Create a new database migration file
$ yarn db-migrate --env=dev # Migrate database to the latest version
```

**Note**: Appending `--env=prod` or `--env=test` flags to any of the commands above will load the
corresponding database settings for the selected deployment environment from
[Firebase Config API](https://firebase.google.com/docs/functions/config-env)
**HINT**: Test your migration thoroughly with a local instance of the DB first
(by using `--env=local` or `--env=dev` (default) flag) then apply it to your
`test` or `prod` database instance using `--env=test` or `--env=prod` command
argument.

Other helpful database scripts:

```bash
$ yarn db-version --env=dev # Print the version number of the last migration
$ yarn db-rollback --env=dev # Rollback the latest migration
$ yarn db-restore --env=dev # Restore database from backup.sql
$ yarn db-seed --env=dev # Seed database with test data
$ yarn db --env=dev # Open Knex.js REPL shell (type ".exit" for exit)
$ yarn psql --env=dev # Open PostgreSQL shell (type "\q" for exit)
```

### How to Test

Expand Down
31 changes: 23 additions & 8 deletions knexfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,50 @@
const fs = require('fs');
const cp = require('child_process');
const dotenv = require('dotenv');
const { env } = require('minimist')(process.argv.slice(2));
const { env = 'dev' } = require('minimist')(process.argv.slice(2));

function getProjectID(env) {
return `example-${env}`;
}

// Load API keys, secrets etc. from Firebase environment
// https://firebase.google.com/docs/functions/config-env
if (env && env !== 'dev') {
if (env === 'prod' || env === 'test') {
const { status, stdout } = cp.spawnSync(
'firebase',
[`--project=example-${env}`, 'functions:config:get'],
[`--project=${getProjectID(env)}`, 'functions:config:get'],
{ stdio: ['pipe', 'pipe', 'inherit'] },
);

if (status !== 0) process.exit(status);

const config = JSON.parse(stdout.toString()).app;

Object.keys(config).forEach(key => {
process.env[key.toUpperCase()] =
typeof key === 'object' ? JSON.stringify(config[key]) : config[key];
});

dotenv.config({ path: `.env.${process.env.NODE_ENV}` });
// delete process.env.PGHOST;
// delete process.env.PGSSLMODE;
} else {
process.env.PGHOST = 'X.X.X.X';
process.env.PGPOST = '5432';
process.env.PGSSLMODE = 'require';
process.env.PGSSLCERT = `./ssl/${env}.client-cert.pem`;
process.env.PGSSLKEY = `./ssl/${env}.client-key.pem`;
process.env.PGSSLROOTCERT = `./ssl/${env}.server-ca.pem`;
} else if (env === 'local') {
dotenv.config({ path: '.env.local' });
process.env.PGPORT = process.env.PGPORT || '5432';
process.env.PGHOST = process.env.PGHOST || 'localhost';
process.env.PGUSER = process.env.PGUSER || 'postgres';
process.env.PGPASSWORD = process.env.PGPASSWORD || '';
process.env.PGDATABASE = process.env.PGDATABASE || 'rsk_local';
process.env.PGSSLMODE = process.env.PGSSLMODE || 'disable';
}

console.log('Environment:', env);
dotenv.config({ path: '.env' });

// Knex configuration
// Knex configuration that is used with DB migration scripts etc.
// http://knexjs.org/#knexfile
module.exports = {
client: 'pg',
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@
"test": "react-app test",
"lint": "eslint --ignore-path .gitignore --ignore-pattern \"!**/.*\" .",
"lint-fix": "eslint --ignore-path .gitignore --ignore-pattern \"!**/.*\" --fix . && yarn run prettier --write \"**/*.{js,json}\"",
"db": "node ./scripts/db",
"db-backup": "node ./scripts/db-backup",
"db-restore": "node ./scripts/db-restore",
"db-change": "knex migrate:make",
Expand All @@ -114,6 +113,8 @@
"db-reset-dev": "yarn db-rollback --env=dev && yarn db-migrate --env=dev && yarn db-restore --env=dev",
"db-reset-test": "yarn db-rollback --env=test && yarn db-migrate --env=test && yarn db-restore --env=test",
"db-reset-prod": "yarn db-rollback --env=prod && yarn db-migrate --env=prod && yarn db-restore --env=prod",
"db": "node --experimental-repl-await ./scripts/db",
"psql": "node ./scripts/psql",
"deploy": "yarn run deploy-test",
"deploy-test": "node ./scripts/pre-deploy --env=test && firebase --project=example-test deploy && node ./scripts/post-deploy --env=test",
"deploy-prod": "node ./scripts/pre-deploy --env=prod && firebase --project=example-prod deploy && node ./scripts/post-deploy --env=prod"
Expand Down
25 changes: 15 additions & 10 deletions scripts/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@
* Copyright (c) 2015-present Kriasoft | MIT License
*/

const cp = require('child_process');
const repl = require('repl');
const knex = require('knex');
const config = require('../knexfile');

// Load environment variables (PGHOST, PGUSER, etc.)
require('../knexfile');
global.db = knex(config);

// Ensure that the SSL key file has correct permissions
if (process.env.PGSSLKEY) {
cp.spawnSync('chmod', ['0600', process.env.PGSSLKEY], { stdio: 'inherit' });
}

// Launch interactive terminal for working with Postgres
cp.spawn('psql', { stdio: 'inherit' });
global.db
.raw('select current_database(), version()')
.then(({ rows: [x] }) => {
console.log('Connected to', x.current_database);
console.log(x.version);
repl.start('#> ').on('exit', process.exit);
})
.catch(err => {
console.error(err);
process.exit(1);
});
18 changes: 18 additions & 0 deletions scripts/psql.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* React Starter Kit for Firebase
* https://github.com/kriasoft/react-firebase-starter
* Copyright (c) 2015-present Kriasoft | MIT License
*/

const cp = require('child_process');

// Load environment variables (PGHOST, PGUSER, etc.)
require('../knexfile');

// Ensure that the SSL key file has correct permissions
if (process.env.PGSSLKEY) {
cp.spawnSync('chmod', ['0600', process.env.PGSSLKEY], { stdio: 'inherit' });
}

// Launch interactive terminal for working with Postgres
cp.spawn('psql', { stdio: 'inherit' });
24 changes: 18 additions & 6 deletions src/common/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import React from 'react';
import CssBaseline from '@material-ui/core/CssBaseline';
import { QueryRenderer } from 'react-relay';
import { ROOT_ID, REF_KEY } from 'relay-runtime';
import { MuiThemeProvider } from '@material-ui/core/styles';

import theme from '../theme';
Expand Down Expand Up @@ -36,14 +37,25 @@ class App extends React.PureComponent {
state = { error: null };

componentDidRender = () => {
const { history, title, config } = this.props;
const { history, location, startTime, title, config, relay } = this.props;
window.document.title = title;

// Track page views
gtag('config', config.gaTrackingId, { transport_type: 'beacon' });
// fb(FB => FB.AppEvents.logPageView());

const scrollY = getScrollPosition(history.location.key);
// Get the current user's ID
const root = relay.getStore().getSource().get(ROOT_ID); // prettier-ignore
const userId = root && root.me ? atob(root.me[REF_KEY]).substr(5) : '';

// Track page views, render time, etc.
gtag('config', config.gaTrackingId, {
transport_type: 'beacon',
user_id: userId,
});
gtag('event', 'timing_complete', {
name: 'load',
value: Math.round(performance.now() - startTime),
event_category: 'Render Complete',
});

const scrollY = getScrollPosition(location.key);

if (scrollY && history.action === 'POP') {
window.scrollTo(0, scrollY);
Expand Down
18 changes: 7 additions & 11 deletions src/icons/Facebook.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,18 @@ const Facebook = React.forwardRef(function Facebook(props, ref) {
return (
<SvgIcon
ref={ref}
role="img"
width={size}
height={size}
viewBox="0 0 256 256"
titleAccess="Facebook icon"
htmlColor="#4172B8"
{...other}
>
<g>
<path
d="M241.871,256.001 C249.673,256.001 256,249.675 256,241.872 L256,14.129 C256,6.325 249.673,0 241.871,0 L14.129,0 C6.324,0 0,6.325 0,14.129 L0,241.872 C0,249.675 6.324,256.001 14.129,256.001 L241.871,256.001"
fill="#395185"
></path>
<path
d="M176.635,256.001 L176.635,156.864 L209.912,156.864 L214.894,118.229 L176.635,118.229 L176.635,93.561 C176.635,82.375 179.742,74.752 195.783,74.752 L216.242,74.743 L216.242,40.188 C212.702,39.717 200.558,38.665 186.43,38.665 C156.932,38.665 136.738,56.67 136.738,89.736 L136.738,118.229 L103.376,118.229 L103.376,156.864 L136.738,156.864 L136.738,256.001 L176.635,256.001"
fill="#FFFFFF"
></path>
</g>
<path d="M241.871,256.001 C249.673,256.001 256,249.675 256,241.872 L256,14.129 C256,6.325 249.673,0 241.871,0 L14.129,0 C6.324,0 0,6.325 0,14.129 L0,241.872 C0,249.675 6.324,256.001 14.129,256.001 L241.871,256.001"></path>
<path
d="M176.635,256.001 L176.635,156.864 L209.912,156.864 L214.894,118.229 L176.635,118.229 L176.635,93.561 C176.635,82.375 179.742,74.752 195.783,74.752 L216.242,74.743 L216.242,40.188 C212.702,39.717 200.558,38.665 186.43,38.665 C156.932,38.665 136.738,56.67 136.738,89.736 L136.738,118.229 L103.376,118.229 L103.376,156.864 L136.738,156.864 L136.738,256.001 L176.635,256.001"
fill="#FFFFFF"
></path>
</SvgIcon>
);
});
Expand Down
24 changes: 24 additions & 0 deletions src/icons/GitHub.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* React Starter Kit for Firebase
* https://github.com/kriasoft/react-firebase-starter
* Copyright (c) 2015-present Kriasoft | MIT License
*/

import React from 'react';
import SvgIcon from '@material-ui/core/SvgIcon';

const GitHub = React.forwardRef(function GitHub(props, ref) {
return (
<SvgIcon
ref={ref}
viewBox="0 0 24 24"
titleAccess="GitHub icon"
htmlColor="#181717"
{...props}
>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
</SvgIcon>
);
});

export default GitHub;
27 changes: 27 additions & 0 deletions src/icons/Instagram.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* React Starter Kit for Firebase
* https://github.com/kriasoft/react-firebase-starter
* Copyright (c) 2015-present Kriasoft | MIT License
*/

import React from 'react';
import SvgIcon from '@material-ui/core/SvgIcon';

const Instagram = React.forwardRef(function Instagram(props, ref) {
const { size = 24, ...other } = props;
return (
<SvgIcon
ref={ref}
width={size}
height={size}
viewBox="0 0 24 24"
titleAccess="Instagram icon"
htmlColor="#E4405F"
{...other}
>
<path d="M12 0C8.74 0 8.333.015 7.053.072 5.775.132 4.905.333 4.14.63c-.789.306-1.459.717-2.126 1.384S.935 3.35.63 4.14C.333 4.905.131 5.775.072 7.053.012 8.333 0 8.74 0 12s.015 3.667.072 4.947c.06 1.277.261 2.148.558 2.913.306.788.717 1.459 1.384 2.126.667.666 1.336 1.079 2.126 1.384.766.296 1.636.499 2.913.558C8.333 23.988 8.74 24 12 24s3.667-.015 4.947-.072c1.277-.06 2.148-.262 2.913-.558.788-.306 1.459-.718 2.126-1.384.666-.667 1.079-1.335 1.384-2.126.296-.765.499-1.636.558-2.913.06-1.28.072-1.687.072-4.947s-.015-3.667-.072-4.947c-.06-1.277-.262-2.149-.558-2.913-.306-.789-.718-1.459-1.384-2.126C21.319 1.347 20.651.935 19.86.63c-.765-.297-1.636-.499-2.913-.558C15.667.012 15.26 0 12 0zm0 2.16c3.203 0 3.585.016 4.85.071 1.17.055 1.805.249 2.227.415.562.217.96.477 1.382.896.419.42.679.819.896 1.381.164.422.36 1.057.413 2.227.057 1.266.07 1.646.07 4.85s-.015 3.585-.074 4.85c-.061 1.17-.256 1.805-.421 2.227-.224.562-.479.96-.899 1.382-.419.419-.824.679-1.38.896-.42.164-1.065.36-2.235.413-1.274.057-1.649.07-4.859.07-3.211 0-3.586-.015-4.859-.074-1.171-.061-1.816-.256-2.236-.421-.569-.224-.96-.479-1.379-.899-.421-.419-.69-.824-.9-1.38-.165-.42-.359-1.065-.42-2.235-.045-1.26-.061-1.649-.061-4.844 0-3.196.016-3.586.061-4.861.061-1.17.255-1.814.42-2.234.21-.57.479-.96.9-1.381.419-.419.81-.689 1.379-.898.42-.166 1.051-.361 2.221-.421 1.275-.045 1.65-.06 4.859-.06l.045.03zm0 3.678c-3.405 0-6.162 2.76-6.162 6.162 0 3.405 2.76 6.162 6.162 6.162 3.405 0 6.162-2.76 6.162-6.162 0-3.405-2.76-6.162-6.162-6.162zM12 16c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4zm7.846-10.405c0 .795-.646 1.44-1.44 1.44-.795 0-1.44-.646-1.44-1.44 0-.794.646-1.439 1.44-1.439.793-.001 1.44.645 1.44 1.439z" />
</SvgIcon>
);
});

export default Instagram;
28 changes: 28 additions & 0 deletions src/icons/Twitter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* React Starter Kit for Firebase
* https://github.com/kriasoft/react-firebase-starter
* Copyright (c) 2015-present Kriasoft | MIT License
*/

import React from 'react';
import SvgIcon from '@material-ui/core/SvgIcon';

const Twitter = React.forwardRef(function Twitter(props, ref) {
const { size = 24, ...other } = props;
return (
<SvgIcon
ref={ref}
width={size}
height={size}
viewBox="0 0 24 24"
titleAccess="Twitter icon"
htmlColor="#1DA1F2"
{...other}
>
<title>Twitter icon</title>
<path d="M23.954 4.569c-.885.389-1.83.654-2.825.775 1.014-.611 1.794-1.574 2.163-2.723-.951.555-2.005.959-3.127 1.184-.896-.959-2.173-1.559-3.591-1.559-2.717 0-4.92 2.203-4.92 4.917 0 .39.045.765.127 1.124C7.691 8.094 4.066 6.13 1.64 3.161c-.427.722-.666 1.561-.666 2.475 0 1.71.87 3.213 2.188 4.096-.807-.026-1.566-.248-2.228-.616v.061c0 2.385 1.693 4.374 3.946 4.827-.413.111-.849.171-1.296.171-.314 0-.615-.03-.916-.086.631 1.953 2.445 3.377 4.604 3.417-1.68 1.319-3.809 2.105-6.102 2.105-.39 0-.779-.023-1.17-.067 2.189 1.394 4.768 2.209 7.557 2.209 9.054 0 13.999-7.496 13.999-13.986 0-.209 0-.42-.015-.63.961-.689 1.8-1.56 2.46-2.548l-.047-.02z" />
</SvgIcon>
);
});

export default Twitter;
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function reset() {
}

function render(location) {
const startTime = performance.now();
router
.resolve({
pathname: location.pathname,
Expand All @@ -44,8 +45,10 @@ function render(location) {
{...route}
config={window.config}
history={history}
location={location}
relay={relay}
reset={reset}
startTime={startTime}
/>,
container,
);
Expand Down
1 change: 1 addition & 0 deletions src/server/ssr.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ router.get('*', async (req, res, next) => {
url: `${process.env.APP_ORIGIN}${req.path}`,
title: route.title,
description: route.description,
preload: route.preload || [],
assets: (route.chunks || []).reduce(
(acc, name) => [...acc, ...[].concat(stats.assetsByChunkName[name])],
stats.entrypoints.main.assets,
Expand Down
3 changes: 3 additions & 0 deletions src/server/templates/ok.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
<meta name="theme-color" content="#000000">
<link rel="manifest" href="/manifest.json">
<link rel="shortcut icon" href="/favicon.ico">
<% preload.forEach(x => { -%>
<link rel="preload" href="<%= x.href %>" as="<%= x.as %>">
<% }); -%>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500|Roboto+Mono:300">
<meta property="og:url" content="<%= url %>">
<meta property="og:type" content="website">
Expand Down
Loading

0 comments on commit 983854f

Please sign in to comment.