So I am trying to deploy my node.js app in heroku for the first time.
After deploying my code and getting to the 6th step in the heroku deployment guide: https://devcenter.heroku.com/articles/getting-started-with-nodejs#scale-the-app
It told me it had deployed fine so I opened up "Application error" - the browser console was 503
Next I added a Procfile to my project, re-deployed and then ran heroku ps top which it returns the following:
=== web (Free): yarn start:production (1) web.1: crashed 2018/01/30 13:17:05 +0000 (~ 5m ago) I'm not too sure where to go from here as the heroku guide carries on without explaining what to do if I hit this error.
here are the initial few pages for my node.js app:
package.json
{ "name": "", "version": "2.5.1", "description": "", "main": "index.js", "engines": { "node": ">=6.0", "npm": ">=3.0" }, "repository": { "type": "git", "url": "" } "author": "", "license": "", "bugs": { "url": "" }, "homepage": "", "scripts": { "start": "better-npm-run start", "start:production": "yarn build && yarn start:prod", "start:prod": "better-npm-run start:prod", "build": "yarn clean:build && better-npm-run build", "lint": "yarn lint:js && yarn lint:style", "lint:js": "better-npm-run lint:js", "lint:style": "better-npm-run lint:style", "flow": "better-npm-run flow", "test": "better-npm-run test", "test:watch": "yarn test --watch", "clean:all": "yarn clean:build && yarn clean:test", "clean:build": "better-npm-run clean:build", "clean:test": "better-npm-run clean:test", "coveralls": "better-npm-run coveralls && yarn clean:test" }, "betterScripts": { "start": { "command": "nodemon ./index.js", "env": { "NODE_PATH": "./src", "NODE_ENV": "development", "PORT": 3000 } }, "start:prod": { "command": "node ./index.js", "env": { "NODE_PATH": "./src", "NODE_ENV": "production", "PORT": 8080 } }, "build": { "command": "webpack --progress --hide-modules --config ./tools/webpack/config.babel.js", "env": { "NODE_ENV": "production" } }, "lint:js": { "command": "eslint ./src ./tools ./index.js" }, "lint:style": { "command": "stylelint \"./src/**/*.scss\" --syntax scss" }, "flow": { "command": "flow; test $? -eq 0 -o $? -eq 2" }, "test": { "command": "jest --coverage", "env": { "NODE_ENV": "test" } }, "clean:build": { "command": "rimraf ./public/assets" }, "clean:test": { "command": "rimraf ./coverage" }, "coveralls": { "command": "cat ./coverage/lcov.info | coveralls" } }, "babel": { "presets": [ "env", "react", "stage-0" ], "env": { "production": { "plugins": [ "transform-remove-console" ] } } }, "eslintConfig": { "parser": "babel-eslint", "extends": "airbnb", "plugins": [ "react", "jsx-a11y", "import" ], "env": { "browser": true, "node": true, "jest": true, "es6": true }, "rules": { "linebreak-style": 0, "global-require": 0, "no-underscore-dangle": 0, "no-console": 0, "react/jsx-filename-extension": [ 1, { "extensions": [ ".js", ".jsx" ] } ], "import/no-extraneous-dependencies": [ "error", { "devDependencies": true } ], "function-paren-newline": 0 }, "globals": { "__CLIENT__": true, "__SERVER__": true, "__DISABLE_SSR__": true, "__DEV__": true, "webpackIsomorphicTools": true } }, "stylelint": { "extends": "stylelint-config-standard", "rules": { "string-quotes": "single", "selector-pseudo-class-no-unknown": [ true, { "ignorePseudoClasses": [ "global", "local" ] } ] } }, "browserslist": [ "last 2 versions", "not ie <= 8" ], "jest": { "setupFiles": [ "raf/polyfill", "<rootDir>/tools/jest/setup.js" ], "collectCoverageFrom": [ "src/containers/**/*.js", "src/components/**/*.js", "!src/**/__tests__" ], "moduleNameMapper": { ".*\\.(css|scss|sass)$": "<rootDir>/tools/jest/styleMock.js", ".*\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/tools/jest/assetMock.js" } } } index.js
/* @flow */ // Use babel-register to precompile ES6 syntax require('babel-core/register'); const WebpackIsomorphicTools = require('webpack-isomorphic-tools'); // Setup global variables for server global.__CLIENT__ = false; global.__SERVER__ = true; global.__DISABLE_SSR__ = false; // Disable server side render here global.__DEV__ = process.env.NODE_ENV !== 'production'; // This should be the same with webpack context const dirRoot = require('path').join(process.cwd()); // Settings of webpack-isomorphic-tools global.webpackIsomorphicTools = new WebpackIsomorphicTools(require('./tools/webpack/WIT.config')).server(dirRoot, () => require('./src/server')); WIT.config.js
const WebpackIsomorphicToolsPlugin = require('webpack-isomorphic-tools/plugin'); module.exports = { // debug: true, // webpack_assets_file_path: 'webpack-assets.json', // webpack_stats_file_path: 'webpack-stats.json', assets: { images: { extensions: ['png', 'jpg', 'jpeg', 'gif'], parser: WebpackIsomorphicToolsPlugin.url_loader_parser, }, fonts: { extensions: ['eot', 'ttf', 'woff', 'woff2'], parser: WebpackIsomorphicToolsPlugin.url_loader_parser, }, svg: { extension: 'svg', parser: WebpackIsomorphicToolsPlugin.url_loader_parser, }, style_modules: { extensions: ['css', 'scss'], filter: (module, regex, options, log) => { if (options.development) { return WebpackIsomorphicToolsPlugin.style_loader_filter(module, regex, options, log); } return regex.test(module.name); }, path: (module, options, log) => { if (options.development) { return WebpackIsomorphicToolsPlugin.style_loader_path_extractor(module, options, log); } return module.name; }, parser: (module, options, log) => { if (options.development) { return WebpackIsomorphicToolsPlugin.css_modules_loader_parser(module, options, log); } return module.source; }, }, }, }; server.js
/* @flow */ import path from 'path'; import morgan from 'morgan'; import express from 'express'; import compression from 'compression'; import helmet from 'helmet'; import hpp from 'hpp'; import favicon from 'serve-favicon'; import React from 'react'; import { renderToString, renderToStaticMarkup } from 'react-dom/server'; import { StaticRouter, matchPath } from 'react-router-dom'; import { Provider } from 'react-redux'; import chalk from 'chalk'; import createHistory from 'history/createMemoryHistory'; import configureStore from './redux/store'; import Html from './utils/Html'; import App from './containers/App'; import routes from './routes'; import { port, host } from './config'; const app = express(); app.set('port', process.env.PORT || 3000); // Using helmet to secure Express with various HTTP headers app.use(helmet()); // Prevent HTTP parameter pollution. app.use(hpp()); // Compress all requests app.use(compression()); // Use morgan for http request debug (only show error) app.use(morgan('dev', { skip: (req, res) => res.statusCode < 400 })); app.use(favicon(path.join(process.cwd(), './public/favicon.ico'))); app.use(express.static(path.join(process.cwd(), './public'))); // Run express as webpack dev server if (__DEV__) { const webpack = require('webpack'); const webpackConfig = require('../tools/webpack/config.babel'); const compiler = webpack(webpackConfig); app.use(require('webpack-dev-middleware')(compiler, { publicPath: webpackConfig.output.publicPath, hot: true, noInfo: true, stats: { colors: true }, serverSideRender: true, })); app.use(require('webpack-hot-middleware')(compiler)); } //GET week app.get('/api/week', (req, res) => { console.log('week'); var articles = []; db.collection('articles') .find() .limit(2) .sort("date", -1) .toArray() .then(result => { articles = articles.concat(result); }).then(() => { // console.log(articles); res.send(articles); }).catch(e => { console.error(e); }); }); //GET articles app.get('/api/articles', (req, res) => { console.log('articles'); var articles = []; db.collection('articles') .find() .limit(12) .sort("date", -1) .toArray() .then(result => { articles = articles.concat(result); }).then(() => { // console.log(articles); res.send(articles); }).catch(e => { console.error(e); }); }); //GET authorArticles app.get('/api/authorArticles', (req, res) => { console.log('authorArticles'); var articles = []; var ObjectId = require('mongodb').ObjectID; var author = {}; var param = req.query.authorQuery; param = param.replace(/-/g, ' '); db.collection('articles') // .find() .find({"author" : {$regex : ".*" + param + ".*"}}) .limit(12) .sort("date", -1) .toArray() .then(result => { articles = articles.concat(result); }).then(() => { // console.log(articles); res.send(articles); }).catch(e => { console.error(e); }); }); //GET extra app.get('/api/extra', (req, res) => { console.log('extra'); var articles = []; db.collection('articles') .aggregate([{ $sample: { size: 4 } }]) .toArray() .then(result => { articles = articles.concat(result); }).then(() => { // console.log(articles); res.send(articles); }).catch(e => { console.error(e); }); }); //GET authors app.get('/api/authors', (req, res) => { console.log('authors'); var authors = []; db.collection('authors') .find() .limit(24) .toArray() .then(result => { // console.log(result); authors = authors.concat(result); }).then(() => { res.send(authors); }).catch(e => { console.error(e); }); }); //GET search app.get('/api/search', (req, res) => { console.log('/api/search'); var articles = []; db.collection('articles') .find({$or:[ {title: {$regex : ".*" + req.query.searchQuery + ".*"}}, {description: {$regex : ".*" + req.query.searchQuery + ".*"}}, {author: {$regex : ".*" + req.query.searchQuery + ".*"}}, {keywords: {$regex : ".*" + req.query.searchQuery + ".*"}} ]}) .limit(24) .sort("date", -1) .toArray() .then(result => { articles = articles.concat(result); }).then(() => { // console.log(articles); res.send(articles); }).catch(e => { console.error(e); }); }); //GET category app.get('/api/category', (req, res) => { console.log('category'); var articles = []; db.collection('articles') .find({$or:[ {category: {$regex : ".*" + req.query.categoryQuery + ".*"}} ]}) .limit(12) .sort("date", -1) .toArray() .then(result => { articles = articles.concat(result); }).then(() => { // console.log(articles); res.send(articles); }).catch(e => { console.error(e); }); }); //GET article app.get('/api/article', (req, res) => { console.log('article'); var ObjectId = require('mongodb').ObjectID; var article = {}; var param = req.query.title; param = param.replace(/-/g, ' '); db.collection('articles') .findOne({"title": param}) .then(result => { article = result; }).then(() => { res.send(article); }).catch(e => { console.error(e); }); }); //GET author app.get('/api/author', (req, res) => { console.log('author'); var ObjectId = require('mongodb').ObjectID; var article = {}; var param = req.query.title; param = param.replace(/-/g, ' '); db.collection('authors') .findOne({"name": param}) .then(result => { article = result; }).then(() => { res.send(article); }).catch(e => { console.error(e); }); }); // Register server-side rendering middleware app.get('*', (req, res) => { if (__DEV__) webpackIsomorphicTools.refresh(); const history = createHistory(); const store = configureStore(history); const renderHtml = (store, htmlContent) => { // eslint-disable-line no-shadow const html = renderToStaticMarkup(<Html store={store} htmlContent={htmlContent} />); return `<!doctype html>${html}`; }; // If __DISABLE_SSR__ = true, disable server side rendering if (__DISABLE_SSR__) { res.send(renderHtml(store)); return; } // Load data on server-side const loadBranchData = () => { const promises = []; routes.some((route) => { const match = matchPath(req.path, route); // $FlowFixMe: the params of pre-load actions are dynamic if (match && route.loadData) promises.push(route.loadData(store.dispatch, match.params)); return match; }); return Promise.all(promises); }; // Send response after all the action(s) are dispathed loadBranchData() .then(() => { // Setup React-Router server-side rendering const routerContext = {}; const htmlContent = renderToString( <Provider store={store}> <StaticRouter location={req.url} context={routerContext}> <App /> </StaticRouter> </Provider>, ); // Check if the render result contains a redirect, if so we need to set // the specific status and redirect header and end the response if (routerContext.url) { res.status(301).setHeader('Location', routerContext.url); res.end(); return; } // Checking is page is 404 const status = routerContext.status === '404' ? 404 : 200; // Pass the route and initial state into html template res.status(status).send(renderHtml(store, htmlContent)); }) .catch((err) => { res.status(404).send('Not Found :('); console.error(`==> 😭 Rendering routes error: ${err}`); }); }); // connect to mongo db var db const MongoClient = require('mongodb').MongoClient MongoClient.connect('mongodb://dannyjones360:test@ds123930.mlab.com:23930/halftimefront', (err, database) => { if (err) return console.log(err); db = database console.log('db connected'); }) if (port) { app.listen(port, host, (err) => { const url = `http://${host}:${port}`; if (err) console.error(`==> 😭 OMG!!! ${err}`); console.info(chalk.green(`==> 🌎 Listening at ${url}`)); // Open Chrome require('../tools/openBrowser')(url); }); } else { console.error(chalk.red('==> 😭 OMG!!! No PORT environment variable has been specified')); } config
module.exports = { host: 3000 || 'localhost', // Define your host from 'package.json' port: 3000, app: { htmlAttributes: { lang: 'en' }, title: 'Rendah', titleTemplate: 'Rendah - %s', meta: [ { name: 'description', content: 'Beats culture magazine', }, { name: 'apple-mobile-web-app-title', content: 'Vernacare', }, { name: 'apple-mobile-web-app-capable', content: 'yes', }, { name: 'apple-mobile-web-app-status-bar-style', content: 'black', }, { name: 'theme-color', content: '#ffffff', }, { name: 'mobile-web-app-capable', content: 'yes', }, { name: 'theme-color', content: '#fff', }, ], }, }; Any help or advice would be appreciated - thank you in advance.
After making ammends to Yoni Rabinovitch's answer, I deploy the site and now get:
2018-02-05T11:37:12.562907+00:00 heroku[web.1]: Process exited with status 1 2018-02-05T11:37:12.580445+00:00 heroku[web.1]: State changed from starting to crashed 2018-02-05T11:37:15.775044+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=sleepy-scrubland-78530.herokuapp.com request_id=d7e4d005-d2f9-4c5f-89c8-14f2addc9ebf fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https 2018-02-05T11:37:16.157734+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=sleepy-scrubland-78530.herokuapp.com request_id=0f2a7123-f9bf-4ee0-bbc6-59894e21cc1b fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https 2018-02-05T11:37:19.664289+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=sleepy-scrubland-78530.herokuapp.com request_id=b3748306-5b3a-4dd6-be2c-58a171bafbd1 fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https 2018-02-05T11:37:19.898230+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=sleepy-scrubland-78530.herokuapp.com request_id=99b155b8-17e9-47da-a454-d3d4c6f45ef4 fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https 2018-02-05T11:37:21.262972+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=sleepy-scrubland-78530.herokuapp.com request_id=ca84a061-f834-476f-a269-7a9a8cd4adda fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https 2018-02-05T11:37:21.537896+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=sleepy-scrubland-78530.herokuapp.com request_id=9e6e9096-f6b4-4d73-b0c1-faf921ea8666 fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https 4 Answers
Answers 1
You seem to be setting the PORT env var in your package.json. You should not be doing that for Heroku. Heroku sets if for you automatically. Instead, add something like this in your server.js:
app.set('port', process.env.PORT || 3000); The you can subsequently call app.listen(app.get('port'),...)
Answers 2
I was getting the same error, so I tried this method. I added this code to my package.json :
"scripts": { "start": "node index.js" }, And in my Procfile:
web: npm start Answers 3
Try in your Procfile npm run start:production instead of using yarn. One time I got the same App crashed in Heroku because when calling the run scripts with yarn it didn't iniatilize the process global variable.
In the latest deploys I hadn't this problem, but it may be ocurring with you.
Answers 4
I am assuming that you are deploying a fresh/sample app. Can you please try above like for the same process :)
sb game hacker
ReplyDelete