部署 angular- 通用应用程序到 heroku
Deploying angular-universal app to heroku
我一直在尝试将我的 angular-universal start 应用程序部署到 heroku。我已经像通常使用 angular 节点应用程序一样设置了一些东西,但为此我可能做错了什么。
这是我遇到的错误
2017-12-18T07:16:23.453463+00:00 heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
但是我是动态设置PORT的
这是我的文件夹结构
我想这可能是我的设置有问题。
Package.json
{
"name": "ng-universal-demo",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"build:client-and-server-bundles": "ng build --prod && ng build --prod --app 1 --output-hashing=false",
"build:prerender": "npm run build:client-and-server-bundles && npm run webpack:server && npm run generate:prerender",
"build:ssr": "npm run build:client-and-server-bundles && npm run webpack:server",
"generate:prerender": "cd dist && node prerender",
"webpack:server": "webpack --config webpack.server.config.js --progress --colors",
"serve:prerender": "cd dist/browser && http-server",
"serve:prerender:prod": "cd dist/browser && node ./bin/www",
"serve:ssr": "node dist/server",
"postinstall": "npm run build:ssr",
"deploy": "git push origin master && git push heroku master"
},
"private": true,
"dependencies": {
"@angular/animations": "^5.0.0",
"@angular/cli": "^1.5.0",
"@angular/common": "^5.0.0",
"@angular/compiler": "^5.0.0",
"@angular/compiler-cli": "^5.0.0",
"@angular/core": "^5.0.0",
"@angular/forms": "^5.0.0",
"@angular/http": "^5.0.0",
"@angular/language-service": "^5.0.0",
"@angular/platform-browser": "^5.0.0",
"@angular/platform-browser-dynamic": "^5.0.0",
"@angular/platform-server": "^5.0.0",
"@angular/router": "^5.0.0",
"@nguniversal/express-engine": "^5.0.0-beta.5",
"@nguniversal/module-map-ngfactory-loader": "^5.0.0-beta.5",
"@types/node": "^8.0.30",
"body-parser": "^1.18.2",
"cookie-parser": "^1.4.3",
"core-js": "^2.4.1",
"cpy-cli": "^1.0.1",
"express": "^4.15.2",
"http-server": "^0.10.0",
"morgan": "^1.9.0",
"reflect-metadata": "^0.1.10",
"rxjs": "^5.5.2",
"ts-loader": "^2.3.7",
"typescript": "~2.4.2",
"zone.js": "^0.8.14"
},
"devDependencies": {}
}
垃圾箱
var app = require('../server');
var debug = require('debug')('test:server');
var http = require('http');
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
var server = http.createServer(app);
//models.sequelize.sync({alter: true}).then(function() {
server.listen(port, function() {
console.log('Express server listening on port ' + server.address().port);
});
server.on('error', onError);
server.on('listening', onListening);
//});
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
和server.ts
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { renderModuleFactory } from '@angular/platform-server';
import { enableProdMode } from '@angular/core';
import * as express from 'express';
import { join } from 'path';
import { readFileSync } from 'fs';
import * as cookieParser from 'cookie-parser';
import * as bodyParser from "body-parser";
import * as logger from 'morgan';
// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();
// Express server
const app = express();
const DIST_FOLDER = join(process.cwd(), 'dist');
// Our index.html we'll use as our template
const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main.bundle');
// Express Engine
import { ngExpressEngine } from '@nguniversal/express-engine';
// Import module map for lazy loading
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP)
]
}));
app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));
app.use(logger('dev'));
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({extended: true}, {limit: '50mb'}));
app.use(cookieParser());
/* - Example Express Rest API endpoints -
app.get('/api/**', (req, res) => { });
*/
// Server static files from /browser
app.get('*.*', express.static(join(DIST_FOLDER, 'browser'), {
maxAge: '1y'
}));
// ALl regular routes use the Universal engine
app.get('*', (req, res) => {
res.render('index', { req });
});
module.exports = app;
除了 bin 设置之外,我还使用了 repo 开头的所有内容。不确定我必须做什么才能将其部署到 heroku
我看到你在使用 Universal Starter 存储库。我采用了相同的 repo 并对其进行了一些调整以使其与 Heroku 一起正常工作。
我记录了这些变化 on Medium and published the edited repo on GitHub
我希望其中任何一个对您有所帮助 - 我已经 运行 我的通用应用程序没有任何问题,现在
"ng": "ng",
"start": "npm run serve:ssr",
"build": "npm run build:ssr",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"dev:ssr": "ng run universal:serve-ssr",
"serve:ssr": "node dist/universal/server/main.js",
"build:ssr": "ng build --prod && ng run universal:server:production",
"prerender": "ng run universal:prerender"
使用此更改启动并构建脚本
我一直在尝试将我的 angular-universal start 应用程序部署到 heroku。我已经像通常使用 angular 节点应用程序一样设置了一些东西,但为此我可能做错了什么。
这是我遇到的错误
2017-12-18T07:16:23.453463+00:00 heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
但是我是动态设置PORT的
这是我的文件夹结构
我想这可能是我的设置有问题。 Package.json
{
"name": "ng-universal-demo",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"build:client-and-server-bundles": "ng build --prod && ng build --prod --app 1 --output-hashing=false",
"build:prerender": "npm run build:client-and-server-bundles && npm run webpack:server && npm run generate:prerender",
"build:ssr": "npm run build:client-and-server-bundles && npm run webpack:server",
"generate:prerender": "cd dist && node prerender",
"webpack:server": "webpack --config webpack.server.config.js --progress --colors",
"serve:prerender": "cd dist/browser && http-server",
"serve:prerender:prod": "cd dist/browser && node ./bin/www",
"serve:ssr": "node dist/server",
"postinstall": "npm run build:ssr",
"deploy": "git push origin master && git push heroku master"
},
"private": true,
"dependencies": {
"@angular/animations": "^5.0.0",
"@angular/cli": "^1.5.0",
"@angular/common": "^5.0.0",
"@angular/compiler": "^5.0.0",
"@angular/compiler-cli": "^5.0.0",
"@angular/core": "^5.0.0",
"@angular/forms": "^5.0.0",
"@angular/http": "^5.0.0",
"@angular/language-service": "^5.0.0",
"@angular/platform-browser": "^5.0.0",
"@angular/platform-browser-dynamic": "^5.0.0",
"@angular/platform-server": "^5.0.0",
"@angular/router": "^5.0.0",
"@nguniversal/express-engine": "^5.0.0-beta.5",
"@nguniversal/module-map-ngfactory-loader": "^5.0.0-beta.5",
"@types/node": "^8.0.30",
"body-parser": "^1.18.2",
"cookie-parser": "^1.4.3",
"core-js": "^2.4.1",
"cpy-cli": "^1.0.1",
"express": "^4.15.2",
"http-server": "^0.10.0",
"morgan": "^1.9.0",
"reflect-metadata": "^0.1.10",
"rxjs": "^5.5.2",
"ts-loader": "^2.3.7",
"typescript": "~2.4.2",
"zone.js": "^0.8.14"
},
"devDependencies": {}
}
垃圾箱
var app = require('../server');
var debug = require('debug')('test:server');
var http = require('http');
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
var server = http.createServer(app);
//models.sequelize.sync({alter: true}).then(function() {
server.listen(port, function() {
console.log('Express server listening on port ' + server.address().port);
});
server.on('error', onError);
server.on('listening', onListening);
//});
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
和server.ts
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { renderModuleFactory } from '@angular/platform-server';
import { enableProdMode } from '@angular/core';
import * as express from 'express';
import { join } from 'path';
import { readFileSync } from 'fs';
import * as cookieParser from 'cookie-parser';
import * as bodyParser from "body-parser";
import * as logger from 'morgan';
// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();
// Express server
const app = express();
const DIST_FOLDER = join(process.cwd(), 'dist');
// Our index.html we'll use as our template
const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main.bundle');
// Express Engine
import { ngExpressEngine } from '@nguniversal/express-engine';
// Import module map for lazy loading
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP)
]
}));
app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));
app.use(logger('dev'));
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({extended: true}, {limit: '50mb'}));
app.use(cookieParser());
/* - Example Express Rest API endpoints -
app.get('/api/**', (req, res) => { });
*/
// Server static files from /browser
app.get('*.*', express.static(join(DIST_FOLDER, 'browser'), {
maxAge: '1y'
}));
// ALl regular routes use the Universal engine
app.get('*', (req, res) => {
res.render('index', { req });
});
module.exports = app;
除了 bin 设置之外,我还使用了 repo 开头的所有内容。不确定我必须做什么才能将其部署到 heroku
我看到你在使用 Universal Starter 存储库。我采用了相同的 repo 并对其进行了一些调整以使其与 Heroku 一起正常工作。
我记录了这些变化 on Medium and published the edited repo on GitHub
我希望其中任何一个对您有所帮助 - 我已经 运行 我的通用应用程序没有任何问题,现在
"ng": "ng",
"start": "npm run serve:ssr",
"build": "npm run build:ssr",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"dev:ssr": "ng run universal:serve-ssr",
"serve:ssr": "node dist/universal/server/main.js",
"build:ssr": "ng build --prod && ng run universal:server:production",
"prerender": "ng run universal:prerender"
使用此更改启动并构建脚本