1

所以我开发了一个简单的 gulp 脚本来创建一个很好的 node.js 应用程序来在 Azure 上运行 Angular Universal,但它并不完全有效。

我正在使用这个: github angular universal

当我正常运行 Angular 通用时,它可以完美运行,但我需要让它在 Azure 上运行。所以 gulp 文件是将所有内容组合在一个构建文件夹中,如果有更好的方法让它在 azure 上运行,请告诉我。

我用 gulp 创建了一个构建文件夹,如下所示:

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       31.01.2017     15.21                assets
d-----       31.01.2017     15.01                node_modules
-a----       31.01.2017     15.24        1661564 app.js
-a----       31.01.2017     15.24        6460064 app.js.map
-a----       31.01.2017     15.21            656 index.html
-a----       31.01.2017     15.21         616568 main.bundle.js
-a----       31.01.2017     15.21        4688762 main.bundle.js.map
-a----       31.01.2017     15.27             60 morgan.log
-a----       31.01.2017     15.21           4188 package.json

它运行得很好,但是当我连接到页面时,我得到一个

错误:无法在视图目录“src”中查找视图“索引”

更多细节在文章末尾。

这是我的 gulp 文件:

"use strict";
var gulp = require("gulp");
var del = require("del");
var sourcemaps = require('gulp-sourcemaps');
var rename = require('gulp-rename');
var clean = require('gulp-clean');

/**
 * Remove build directory.
 */
gulp.task('clean', function (cb) {
    return del(["build"], cb);
});

/**
 * Copy all resources that are not TypeScript files into build directory.
 */
gulp.task("resources", ["server", "app", "assets", "client", "rename1", "rename2", "move", "removetemp"], function () {
    console.log("Building resources...");
});
/* copy the app core files to the build folder */
gulp.task("app", ['index'], function(){
    return gulp.src(["app/**", "!app/**/*.ts"])
        .pipe(gulp.dest("build/app"));
});
/* get the index file to the root of the build */
// TODO: Add web.config
gulp.task("index", function(){
    return gulp.src(["src/index.html", "package.json"])
        .pipe(gulp.dest("build"));
});
/* copy node server to build folder */
gulp.task("server", function () {
    return gulp.src(["index.js", "package.json"], { cwd: "server/**" })
        .pipe(gulp.dest("build"));
});

/* styles and other assets */
gulp.task("assets", function(){
    return gulp.src(["src/assets/**"])
        .pipe(gulp.dest("build/assets"));
});

/* client folder */
gulp.task("client", function(){
    return gulp.src(["dist/client/main.bundle.js", "dist/client/main.bundle.js.map"])
        .pipe(gulp.dest("build"));
});

/* rename /server/index.js to app.js and move to build */
gulp.task('rename1', function() {
    return gulp.src(["dist/server/index.js"])
        .pipe(rename('app.js'))
        .pipe(gulp.dest("build/temp"));
});

gulp.task('rename2', function() {
    return gulp.src(["dist/server/index.js.map"])
        .pipe(rename('app.js.map'))
        .pipe(gulp.dest("build/temp"));
});


gulp.task('move', function() {
    return gulp.src(["build/temp/**"])
        .pipe(gulp.dest("build"));
});

gulp.task('removetemp', function () {
    return del(["build/temp"]);
});

/*
gulp.task('temp', function() {
    return gulp.src(["build/temp"])
        .pipe(clean({force: true}))
});
*/

/**
 * Copy all required libraries into build directory.
 *
gulp.task("libs", function () {
    return gulp.src([
        'core-js/client/shim.min.js',
        'zone.js/dist/zone.js',
        'systemjs/dist/system.src.js',
        'systemjs.config.js',
        // 'es6-shim/es6-shim.min.js',
        'systemjs/dist/system-polyfills.js',
        'angular2/bundles/angular2-polyfills.js',
        'angular2/es6/dev/src/testing/shims_for_IE.js',
        'systemjs/dist/system.src.js',
        'rxjs/bundles/Rx.js',
        'angular2/bundles/angular2.dev.js',
        'angular2/bundles/router.dev.js'
    ], { cwd: "node_modules/**" }) /* Glob required here.
        .pipe(gulp.dest("build/node_modules"));
});
/**
 * Build the project.
 */
gulp.task("default", ['resources'], function () {
    console.log("Building the project ...");
});

当我在构建文件夹中运行“node app.js”时出现完整的错误消息:

Listening on: http://localhost:3000
Error: Failed to lookup view "index" in views directory "src"
    at EventEmitter.render (C:\front-end\universal\node_modules\express\lib\application.js:579:17)
    at ServerResponse.render (C:\front-end\universal\node_modules\express\lib\response.js:960:7)
    at C:\front-end\universal\build\app.js:52:12237
    at ZoneDelegate.invoke (C:\front-end\universal\node_modules\zone.js\dist\zone-node.js:232:26)
    at Zone.run (C:\front-end\universal\node_modules\zone.js\dist\zone-node.js:114:43)
    at ngApp (C:\front-end\universal\build\app.js:52:12218)
    at Layer.handle [as handle_request] (C:\front-end\universal\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\front-end\universal\node_modules\express\lib\router\route.js:131:13)
    at Route.dispatch (C:\front-end\universal\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\front-end\universal\node_modules\express\lib\router\layer.js:95:5)

服务器.ts

// the polyfills must be one of the first things imported in node.js.
// The only modules to be imported higher - node modules with es6-promise 3.x or other Promise polyfill dependency
// (rule of thumb: do it if you have zone.js exception that it has been overwritten)
// if you are including modules that modify Promise, such as NewRelic,, you must include them before polyfills
import 'angular2-universal-polyfills';
import 'ts-helpers';
import './__workaround.node'; // temporary until 2.1.1 things are patched in Core

import * as path from 'path';
import * as express from 'express';
import * as bodyParser from 'body-parser';
import * as cookieParser from 'cookie-parser';
import * as morgan from 'morgan';
import * as compression from 'compression';

// Angular 2
import { enableProdMode } from '@angular/core';
// Angular 2 Universal
import { createEngine } from 'angular2-express-engine';

// App
import { MainModule } from './node.module';

// Routes
import { routes } from './server.routes';

// enable prod for faster renders
enableProdMode();

const app = express();
const ROOT = path.join(path.resolve(__dirname, '..'));

// Express View
app.engine('.html', createEngine({
  ngModule: MainModule,
  providers: [
    // use only if you have shared state between users
    // { provide: 'LRU', useFactory: () => new LRU(10) }

    // stateless providers only since it's shared
  ]
}));
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname);
app.set('view engine', 'html');
app.set('json spaces', 2);

app.use(cookieParser('Angular 2 Universal'));
app.use(bodyParser.json());
app.use(compression());

app.use(morgan('dev'));

function cacheControl(req, res, next) {
  // instruct browser to revalidate in 60 seconds
  res.header('Cache-Control', 'max-age=60');
  next();
}
// Serve static files
app.use('/assets', cacheControl, express.static(path.join(__dirname, 'assets'), {maxAge: 30}));
app.use(cacheControl, express.static(path.join(ROOT, 'dist/client'), {index: false}));

//
/////////////////////////
// ** Example API
// Notice API should be in aseparate process
import { serverApi, createTodoApi } from './backend/api';
// Our API for demos only
app.get('/data.json', serverApi);
app.use('/api', createTodoApi());

process.on('uncaughtException', function (err) {
  console.error('Catching uncaught errors to avoid process crash', err);
});

function ngApp(req, res) {

  function onHandleError(parentZoneDelegate, currentZone, targetZone, error)  {
    console.warn('Error in SSR, serving for direct CSR');
    res.sendFile('index.html', {root: './src'});
    return false;
  }

  Zone.current.fork({ name: 'CSR fallback', onHandleError }).run(() => {
    res.render('index', {
      req,
      res,
      // time: true, // use this to determine what part of your app is slow only in development
      preboot: false,
      baseUrl: '/',
      requestUrl: req.originalUrl,
      originUrl: `http://localhost:${ app.get('port') }`
    });
  });

}

/**
 * use universal for specific routes
 */
app.get('/', ngApp);
routes.forEach(route => {
  app.get(`/${route}`, ngApp);
  app.get(`/${route}/*`, ngApp);
});

app.get('*', function(req, res) {
  res.setHeader('Content-Type', 'application/json');
  var pojo = { status: 404, message: 'No Content' };
  var json = JSON.stringify(pojo, null, 2);
  res.status(404).send(json);
});

// Server
let server = app.listen(app.get('port'), () => {
  console.log(`Listening on: http://localhost:${server.address().port}`);
});
4

0 回答 0