所以我第一次尝试在heroku中部署我的node.js应用程序。
部署我的代码并进入heroku部署指南中的第6步后:https://devcenter.heroku.com/articles/getting-started-with-nodejs#scale-the-app
它告诉我它已部署好了所以我打开了#34;应用程序错误" - 浏览器控制台为503
接下来,我在项目中添加了 Procfile ,重新部署,然后运行heroku ps
顶部,返回以下内容:
=== web (Free): yarn start:production (1)
web.1: crashed 2018/01/30 13:17:05 +0000 (~ 5m ago)
我不太确定从哪里开始,因为heroku指南不会解释如果我遇到此错误该怎么办。
这是我的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'));
}
配置
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',
},
],
},
};
任何帮助或建议将不胜感激 - 谢谢你提前。
在对Yoni Rabinovitch的答案做出弥补后,我部署了该网站,现在得到:
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
答案 0 :(得分:2)
您似乎在package.json中设置了PORT env var。你不应该为Heroku这样做。 Heroku会自动为您设置。 相反,在server.js中添加类似的东西:
app.set('port', process.env.PORT || 3000);
您随后可以调用app.listen(app.get(&#39; port&#39;),...)
答案 1 :(得分:0)
尝试使用 Procfile npm run start:production
而不是使用纱线。有一次我在Heroku中遇到了相同的 App崩溃,因为在使用yarn调用run脚本时,它没有使用process
全局变量。
在最新的部署中,我没有遇到这个问题,但它可能会与你发生争执。
答案 2 :(得分:0)
我假设你正在部署一个新的/示例应用程序。 你可以在上面尝试同样的过程:)