Merge branch 'passion-for-coding-heroku-deployment'

This commit is contained in:
Cassie Tarakajian 2019-01-24 17:33:56 -05:00
commit 601ef4d012
17 changed files with 8197 additions and 21337 deletions

View file

@ -1,22 +1,22 @@
API_URL=/api API_URL=/api
MONGO_URL=mongodb://localhost:27017/p5js-web-editor
PORT=8000
SESSION_SECRET=whatever_you_want_this_to_be_it_only_matters_for_production
AWS_ACCESS_KEY=<your-aws-access-key> AWS_ACCESS_KEY=<your-aws-access-key>
AWS_SECRET_KEY=<your-aws-secret-key>
AWS_REGION=<your-aws-region> AWS_REGION=<your-aws-region>
S3_BUCKET=<your-s3-bucket> AWS_SECRET_KEY=<your-aws-secret-key>
EMAIL_SENDER=<transactional-email-sender>
EMAIL_VERIFY_SECRET_TOKEN=whatever_you_want_this_to_be_it_only_matters_for_production
EXAMPLE_USER_EMAIL=examples@p5js.org
EXAMPLE_USER_PASSWORD=hellop5js
GG_EXAMPLES_EMAIL=benedikt.gross@generative-gestaltung.de
GG_EXAMPLES_PASS=generativedesign
GG_EXAMPLES_USERNAME=generative-design
GITHUB_ID=<your-github-client-id> GITHUB_ID=<your-github-client-id>
GITHUB_SECRET=<your-github-client-secret> GITHUB_SECRET=<your-github-client-secret>
GOOGLE_ID=<your-google-client-id> (use google+ api) GOOGLE_ID=<your-google-client-id> (use google+ api)
GOOGLE_SECRET=<your-google-client-secret> (use google+ api) GOOGLE_SECRET=<your-google-client-secret> (use google+ api)
MAILGUN_DOMAIN=<your-mailgun-domain> MAILGUN_DOMAIN=<your-mailgun-domain>
MAILGUN_KEY=<your-mailgun-api-key> MAILGUN_KEY=<your-mailgun-api-key>
EMAIL_SENDER=<transactional-email-sender> MONGO_URL=mongodb://localhost:27017/p5js-web-editor
EMAIL_VERIFY_SECRET_TOKEN=whatever_you_want_this_to_be_it_only_matters_for_production PORT=8000
S3_BUCKET=<your-s3-bucket>
S3_BUCKET_URL_BASE=<alt-for-s3-url> S3_BUCKET_URL_BASE=<alt-for-s3-url>
EXAMPLE_USER_EMAIL=examples@p5js.org SESSION_SECRET=whatever_you_want_this_to_be_it_only_matters_for_production
EXAMPLE_USER_PASSWORD=hellop5js
GG_EXAMPLES_USERNAME=generative-design
GG_EXAMPLES_PASS=generativedesign
GG_EXAMPLES_EMAIL=benedikt.gross@generative-gestaltung.de

View file

@ -1,7 +1,7 @@
sudo: required sudo: required
language: node_js language: node_js
node_js: node_js:
- "8.11.1" - "10.15.0"
cache: cache:
directories: directories:

View file

@ -1,4 +1,4 @@
FROM node:8.11.1 as base FROM node:10.15.0 as base
ENV APP_HOME=/usr/src/app \ ENV APP_HOME=/usr/src/app \
TERM=xterm TERM=xterm
RUN mkdir -p $APP_HOME RUN mkdir -p $APP_HOME

1
Procfile Normal file
View file

@ -0,0 +1 @@
web: MONGO_URL=$MONGO_URI MAILGUN_KEY=$MAILGUN_API_KEY npm run start:prod

93
app.json Normal file
View file

@ -0,0 +1,93 @@
{
"name": "p5.js Web Editor",
"description": "The p5.js Web Editor is an in-browser editor for creative coding, specifically for writing p5.js sketches.",
"repository": "https://github.com/processing/p5.js-web-editor",
"logo": "https://p5js.org/assets/img/p5js.svg",
"keywords": ["processing", "p5js", "p5.js"],
"addons": [
{
"plan": "mongolab:sandbox",
"as": "MONGO"
},
{
"plan": "mailgun:starter",
"as": "MAILGUN"
}
],
"env": {
"API_URL": {
"value": "/api"
},
"AWS_ACCESS_KEY": {
"description": "AWS Access Key",
"value": "placeholder"
},
"AWS_SECRET_KEY": {
"description": "AWS Secret Key",
"value": "placeholder"
},
"AWS_REGION": {
"description": "AWS Region for the S3_BUCKET",
"value": "placeholder"
},
"EMAIL_SENDER": {
"description": "The sending email address for transactional emails.",
"value": "no-reply@mydomain.com"
},
"EMAIL_VERIFY_SECRET_TOKEN": {
"description": "A secret key for...? Not sure where used.",
"generator": "secret"
},
"EXAMPLE_USER_EMAIL": {
"description": "The email address for the account holding the default Example sketches",
"value": "examples@p5js.org"
},
"EXAMPLE_USER_PASSWORD": {
"value": "hellop5js"
},
"GG_EXAMPLES_EMAIL": {
"description": "The email address for the account holding the Generative Design Example sketches",
"value": "benedikt.gross@generative-gestaltung.de"
},
"GG_EXAMPLES_PASS": {
"value": "generativedesign"
},
"GG_EXAMPLES_USERNAME": {
"value": "generative-design"
},
"GITHUB_ID": {
"description": "The GitHub Client Id for sign in with GitHub support",
"value": "placeholder"
},
"GITHUB_SECRET": {
"description": "The GitHub Client Secret",
"value": "placeholder"
},
"GOOGLE_ID": {
"description": "The Google Client Id for sign in with Google support",
"value": "placeholder"
},
"GOOGLE_SECRET": {
"description": "The Google Client Secret",
"value": "placeholder"
},
"NODE_ENV": {
"value": "production"
},
"S3_BUCKET": {
"desription": "Name of the S3 bucket for asset storage",
"value": "placeholder"
},
"S3_BUCKET_URL_BASE": {
"description": "S3 bucket URL base",
"required": false
},
"SESSION_SECRET": {
"description": "A secret key for verifying the integrity of signed cookies.",
"generator": "secret"
}
},
"scripts": {
"postdeploy": "MONGO_URL=$MONGO_URI MAILGUN_KEY=$MAILGUN_API_KEY npm run fetch-examples:prod"
}
}

View file

@ -8,9 +8,7 @@ import InlineSVG from 'react-inlinesvg';
import classNames from 'classnames'; import classNames from 'classnames';
import * as IDEActions from '../modules/IDE/actions/ide'; import * as IDEActions from '../modules/IDE/actions/ide';
import { import { metaKeyName, } from '../utils/metaKey';
metaKeyName,
} from '../utils/metaKey';
const triangleUrl = require('../images/down-filled-triangle.svg'); const triangleUrl = require('../images/down-filled-triangle.svg');
const logoUrl = require('../images/p5js-logo-small.svg'); const logoUrl = require('../images/p5js-logo-small.svg');

View file

@ -5,10 +5,12 @@ import each from 'async/each';
import { isEqual, pick } from 'lodash'; import { isEqual, pick } from 'lodash';
import * as ActionTypes from '../../../constants'; import * as ActionTypes from '../../../constants';
import { showToast, setToastText } from './toast'; import { showToast, setToastText } from './toast';
import { setUnsavedChanges, import {
setUnsavedChanges,
justOpenedProject, justOpenedProject,
resetJustOpenedProject, resetJustOpenedProject,
showErrorModal } from './ide'; showErrorModal
} from './ide';
import { clearState, saveState } from '../../../persistState'; import { clearState, saveState } from '../../../persistState';
const __process = (typeof global !== 'undefined' ? global : window).process; const __process = (typeof global !== 'undefined' ? global : window).process;

View file

@ -67,6 +67,7 @@ class CopyableInput extends React.Component {
{hasPreviewLink && {hasPreviewLink &&
<a <a
target="_blank" target="_blank"
rel="noopener noreferrer"
href={value} href={value}
className="copyable-input__preview" className="copyable-input__preview"
title={`open ${label.toLowerCase()} view in new tab`} title={`open ${label.toLowerCase()} view in new tab`}

View file

@ -32,9 +32,7 @@ import '../../../utils/p5-javascript';
import '../../../utils/webGL-clike'; import '../../../utils/webGL-clike';
import Timer from '../components/Timer'; import Timer from '../components/Timer';
import EditorAccessibility from '../components/EditorAccessibility'; import EditorAccessibility from '../components/EditorAccessibility';
import { import { metaKey, } from '../../../utils/metaKey';
metaKey,
} from '../../../utils/metaKey';
import search from '../../../utils/codemirror-search'; import search from '../../../utils/codemirror-search';

View file

@ -1,7 +1,5 @@
import React from 'react'; import React from 'react';
import { import { metaKeyName, } from '../../../utils/metaKey';
metaKeyName,
} from '../../../utils/metaKey';
function KeyboardShortcutModal() { function KeyboardShortcutModal() {
return ( return (

View file

@ -1,6 +1,4 @@
import { import { EXTERNAL_LINK_REGEX } from '../../server/utils/fileUtils';
EXTERNAL_LINK_REGEX
} from '../../server/utils/fileUtils';
export const hijackConsoleErrorsScript = (offs) => { export const hijackConsoleErrorsScript = (offs) => {
const s = ` const s = `

View file

@ -38,3 +38,14 @@ You'll only need to do this if you're testing the production environment locally
7. `$ npm run build` 7. `$ npm run build`
8. Since production assumes your environment variables are in the shell environment, and not in a `.env` file, you will have to run `export $(grep -v '^#' .env | xargs)` or a similar command, see this [Stack Overflow answer](https://stackoverflow.com/a/20909045/4086967). 8. Since production assumes your environment variables are in the shell environment, and not in a `.env` file, you will have to run `export $(grep -v '^#' .env | xargs)` or a similar command, see this [Stack Overflow answer](https://stackoverflow.com/a/20909045/4086967).
9. `$ npm run start:prod` 9. `$ npm run start:prod`
## Self Hosting - Heroku Deployment
If you are interested in hosting and deploying your own p5.js Web Editor instance, you can! It would be the same as the official editor instance at editor.p5js.org, except with a different domain, and you would be in charge of the maintenance. We recommend using Heroku as you can host it for free.
1. Sign up for a free account at: [Heroku](https://www.heroku.com/)
2. Click here: [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/processing/p5.js-web-editor/tree/master)
3. Enter a unique *App name*, this will become part of the url (i.e. https://app-name.herokuapp.com/)
4. Update any configuration variables, or accept the defaults for a quick evaluation (they can be changed later to enable full functionality)
5. Click on the "Deploy app" button
6. When complete, click on the "View app" button

27969
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,8 @@
"fetch-examples": "cross-env NODE_ENV=development node ./server/scripts/fetch-examples.js", "fetch-examples": "cross-env NODE_ENV=development node ./server/scripts/fetch-examples.js",
"fetch-examples-gg": "cross-env NODE_ENV=development node ./server/scripts/fetch-examples-gg.js", "fetch-examples-gg": "cross-env NODE_ENV=development node ./server/scripts/fetch-examples-gg.js",
"fetch-examples:prod": "cross-env NODE_ENV=production node ./dist/fetch-examples.bundle.js", "fetch-examples:prod": "cross-env NODE_ENV=production node ./dist/fetch-examples.bundle.js",
"fetch-examples-gg:prod": "cross-env NODE_ENV=production node ./dist/fetch-examples-gg.bundle.js" "fetch-examples-gg:prod": "cross-env NODE_ENV=production node ./dist/fetch-examples-gg.bundle.js",
"heroku-postbuild": "touch .env; npm run build"
}, },
"main": "index.js", "main": "index.js",
"author": "Cassie Tarakajian", "author": "Cassie Tarakajian",
@ -27,59 +28,60 @@
}, },
"devDependencies": { "devDependencies": {
"babel-eslint": "^7.1.1", "babel-eslint": "^7.1.1",
"babel-loader": "^7.1.4", "babel-loader": "^7.1.5",
"babel-plugin-transform-react-constant-elements": "^6.8.0", "babel-plugin-transform-react-constant-elements": "^6.23.0",
"babel-plugin-transform-react-inline-elements": "^6.8.0", "babel-plugin-transform-react-inline-elements": "^6.22.0",
"babel-plugin-transform-react-remove-prop-types": "^0.2.6", "babel-plugin-transform-react-remove-prop-types": "^0.2.12",
"babel-plugin-webpack-loaders": "^0.9.0", "babel-plugin-webpack-loaders": "^0.9.0",
"babel-preset-env": "^1.7.0", "babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.5.0", "babel-preset-react": "^6.24.1",
"babel-preset-react-optimize": "^1.0.1", "babel-preset-react-optimize": "^1.0.1",
"babel-preset-stage-0": "^6.5.0", "babel-preset-stage-0": "^6.24.1",
"chunk-manifest-webpack-plugin": "^1.1.2", "chunk-manifest-webpack-plugin": "github:catarak/chunk-manifest-webpack-plugin",
"css-loader": "^0.23.1", "css-loader": "^0.23.1",
"cssnano": "^3.7.1", "cssnano": "^3.10.0",
"eslint": "^4.9.0", "eslint": "^4.19.1",
"eslint-config-airbnb": "^16.1.0", "eslint-config-airbnb": "^16.1.0",
"eslint-plugin-import": "^2.2.0", "eslint-plugin-import": "^2.14.0",
"eslint-plugin-jsx-a11y": "^6.0.3", "eslint-plugin-jsx-a11y": "^6.1.2",
"eslint-plugin-react": "^7.7.0", "eslint-plugin-react": "^7.12.3",
"extract-text-webpack-plugin": "^3.0.2", "extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^2.0.0", "file-loader": "^2.0.0",
"node-sass": "^4.11.0", "node-sass": "^4.11.0",
"nodemon": "^1.18.9", "nodemon": "^1.18.9",
"postcss-cssnext": "^2.7.0", "postcss-cssnext": "^2.11.0",
"postcss-focus": "^1.0.0", "postcss-focus": "^1.0.0",
"postcss-loader": "^0.9.1", "postcss-loader": "^0.9.1",
"postcss-reporter": "^1.3.3", "postcss-reporter": "^1.4.1",
"rimraf": "^2.6.2", "rimraf": "^2.6.3",
"sass-loader": "^6.0.6", "sass-loader": "^6.0.7",
"style-loader": "^0.13.1", "style-loader": "^0.13.2",
"webpack-manifest-plugin": "^2.0.0", "webpack-manifest-plugin": "^2.0.4",
"webpack-node-externals": "^1.7.2" "webpack-node-externals": "^1.7.2"
}, },
"engines": { "engines": {
"node": ">=8.9.0" "node": "10.15.0",
"npm": "6.4.1"
}, },
"dependencies": { "dependencies": {
"archiver": "^1.1.0", "archiver": "^1.1.0",
"async": "^2.0.0", "async": "^2.6.1",
"axios": "^0.12.0", "axios": "^0.12.0",
"babel-core": "^6.26.3", "babel-core": "^6.26.3",
"babel-polyfill": "^6.8.0", "babel-polyfill": "^6.26.0",
"babel-register": "^6.26.0", "babel-register": "^6.26.0",
"bcrypt-nodejs": "0.0.3", "bcrypt-nodejs": "0.0.3",
"blob-util": "^1.2.1", "blob-util": "^1.2.1",
"body-parser": "^1.18.3", "body-parser": "^1.18.3",
"bson-objectid": "^1.1.4", "bson-objectid": "^1.2.4",
"classnames": "^2.2.5", "classnames": "^2.2.6",
"clipboard": "^1.7.1", "clipboard": "^1.7.1",
"codemirror": "^5.38.0", "codemirror": "^5.42.2",
"connect-mongo": "^1.2.0", "connect-mongo": "^1.3.2",
"console-feed": "^2.8.5", "console-feed": "^2.8.5",
"cookie-parser": "^1.4.1", "cookie-parser": "^1.4.3",
"cors": "^2.8.1", "cors": "^2.8.5",
"cross-env": "^5.1.3", "cross-env": "^5.2.0",
"csslint": "^0.10.0", "csslint": "^0.10.0",
"decomment": "^0.8.7", "decomment": "^0.8.7",
"dotenv": "^2.0.0", "dotenv": "^2.0.0",
@ -87,17 +89,17 @@
"escape-string-regexp": "^1.0.5", "escape-string-regexp": "^1.0.5",
"eslint-loader": "^1.3.0", "eslint-loader": "^1.3.0",
"express": "^4.16.4", "express": "^4.16.4",
"express-basic-auth": "^1.1.5", "express-basic-auth": "^1.1.6",
"express-session": "^1.15.6", "express-session": "^1.15.6",
"htmlhint": "^0.10.1", "htmlhint": "^0.10.1",
"is-url": "^1.2.2", "is-url": "^1.2.4",
"js-beautify": "^1.6.4", "js-beautify": "^1.8.9",
"jsdom": "^9.8.3", "jsdom": "^9.8.3",
"jshint": "^2.9.7", "jshint": "^2.9.7",
"lodash": "^4.17.11", "lodash": "^4.17.11",
"loop-protect": "github:catarak/loop-protect", "loop-protect": "github:catarak/loop-protect",
"mjml": "^3.3.2", "mjml": "^3.3.2",
"moment": "^2.14.1", "moment": "^2.23.0",
"mongoose": "^4.6.8", "mongoose": "^4.6.8",
"node-uuid": "^1.4.7", "node-uuid": "^1.4.7",
"nodemailer": "^2.6.4", "nodemailer": "^2.6.4",
@ -107,25 +109,25 @@
"passport-google-oauth20": "^1.0.0", "passport-google-oauth20": "^1.0.0",
"passport-local": "^1.0.0", "passport-local": "^1.0.0",
"pretty-bytes": "^3.0.1", "pretty-bytes": "^3.0.1",
"primer-tooltips": "^1.4.1", "primer-tooltips": "^1.5.11",
"project-name-generator": "^2.1.3", "project-name-generator": "^2.1.5",
"prop-types": "^15.6.0", "prop-types": "^15.6.2",
"q": "^1.4.1", "q": "^1.4.1",
"react": "^16.4.0", "react": "^16.7.0",
"react-dom": "^16.4.0", "react-dom": "^16.7.0",
"react-helmet": "^5.1.3", "react-helmet": "^5.1.3",
"react-hot-loader": "^4.1.2", "react-hot-loader": "^4.6.3",
"react-inlinesvg": "^0.7.5", "react-inlinesvg": "^0.7.5",
"react-redux": "^5.0.6", "react-redux": "^5.1.1",
"react-router": "^3.2.0", "react-router": "^3.2.1",
"react-split-pane": "^0.1.44", "react-split-pane": "^0.1.76",
"react-tabs": "^2.2.1", "react-tabs": "^2.3.0",
"redux": "^3.5.2", "redux": "^3.7.2",
"redux-devtools": "^3.4.2", "redux-devtools": "^3.4.2",
"redux-devtools-dock-monitor": "^1.1.3", "redux-devtools-dock-monitor": "^1.1.3",
"redux-devtools-log-monitor": "^1.4.0", "redux-devtools-log-monitor": "^1.4.0",
"redux-form": "^5.3.3", "redux-form": "^5.3.3",
"redux-thunk": "^2.1.0", "redux-thunk": "^2.3.0",
"request": "^2.88.0", "request": "^2.88.0",
"request-promise": "^4.1.1", "request-promise": "^4.1.1",
"s3": "^4.4.0", "s3": "^4.4.0",
@ -133,13 +135,13 @@
"sass-extract": "^2.1.0", "sass-extract": "^2.1.0",
"sass-extract-js": "^0.4.0", "sass-extract-js": "^0.4.0",
"sass-extract-loader": "^1.1.0", "sass-extract-loader": "^1.1.0",
"shortid": "^2.2.6", "shortid": "^2.2.14",
"slugify": "^1.2.9", "slugify": "^1.3.4",
"srcdoc-polyfill": "^0.2.0", "srcdoc-polyfill": "^0.2.0",
"url": "^0.11.0", "url": "^0.11.0",
"webpack": "^3.1.0", "webpack": "^3.12.0",
"webpack-dev-middleware": "^2.0.6", "webpack-dev-middleware": "^2.0.6",
"webpack-hot-middleware": "^2.10.0", "webpack-hot-middleware": "^2.24.3",
"xhr": "^2.2.1" "xhr": "^2.5.0"
} }
} }

View file

@ -4,7 +4,8 @@ import {
injectMediaUrls, injectMediaUrls,
resolvePathsForElementsWithAttribute, resolvePathsForElementsWithAttribute,
resolveScripts, resolveScripts,
resolveStyles } from '../utils/previewGeneration'; resolveStyles
} from '../utils/previewGeneration';
import { get404Sketch } from '../views/404Page'; import { get404Sketch } from '../views/404Page';
export function serveProject(req, res) { export function serveProject(req, res) {

View file

@ -1,7 +1,6 @@
export function renderIndex() { export function renderIndex() {
const assetsManifest = process.env.webpackAssets && JSON.parse(process.env.webpackAssets); const assetsManifest = process.env.webpackAssets && JSON.parse(process.env.webpackAssets);
const chunkManifest = process.env.webpackChunkAssets && JSON.parse(process.env.webpackChunkAssets); const chunkManifest = process.env.webpackChunkAssets && JSON.parse(process.env.webpackChunkAssets);
return ` return `
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>

View file

@ -116,6 +116,7 @@ module.exports = [{
new ChunkManifestPlugin({ new ChunkManifestPlugin({
filename: 'chunk-manifest.json', filename: 'chunk-manifest.json',
manifestVariable: 'webpackManifest', manifestVariable: 'webpackManifest',
inlineManifest: false
}), }),
new webpack.optimize.UglifyJsPlugin({ new webpack.optimize.UglifyJsPlugin({
sourceMap: true, sourceMap: true,