2016-11-12 83 views
2

我试图使用prerender-node和一个私有预渲染服务器来预渲染一个Angular2/Express应用程序。如果我尝试目标ES5在我tsconfig.json,预渲染服务器将引发此错误:使用Angular 2/Typescript/Webpack预渲染es6错误

ReferenceError: Can't find variable: Map 

undefined:1521 in KeyRegistry 
:1540 
:7 

如果我尝试目标ES6(包括files阵列中node_modules/typescript/lib/lib.es6.d.ts),预渲染服务器将引发此错误:

SyntaxError: Unexpected token 'const' 

http://localhost:3000/app.js:50 in eval 
http://localhost:3000/app.js:50 
http://localhost:3000/app.js:20 in __webpack_require__ 
http://localhost:3000/app.js:40 

我猜我需要包括某种填充工具,以便为这个工作,但我没有第一想法是什么,包括或者包含它。

这里是万一我的WebPack的配置,可以帮助:

var webpack = require('webpack'); 
var path = require('path'); 
var rootDir = path.resolve(); 

module.exports = 
{ 
    target: 'node', 
    entry: rootDir + "/dist/client/app/bootstrap.js", 
    output: { 
     path: rootDir + "/dist/client", publicPath: '/', filename: "app.js", 
     pathinfo: true 
    }, 
    devtool: 'eval', 
    resolve: { 
     root: rootDir + "/dist/client/app", 
     extensions: ['', '.js'] 
    }, 
    module: { 
     loaders: [ 
      { 
       test: /\.ts/, loaders: ['ts-loader'], exclude: /node_modules/ 
      } 
     ] 
    } 
}; 

而如果我的客户tsconfig帮助:

{ 
    "compilerOptions": { 
     "target": "es6", 
     "module": "commonjs", 
     "moduleResolution": "node", 
     "sourceMap": false, 
     "outDir": "../../dist/client", 
     "emitDecoratorMetadata": true, 
     "experimentalDecorators": true, 
     "removeComments": false, 
     "noImplicitAny": true 
    }, 
    "files": ["app/bootstrap.ts", "app/vendor.ts", "app/Window.ts", "tests/index.ts", "../../node_modules/typescript/lib/lib.es6.d.ts"] 
} 

更新

如果我改变我的WebPack配置目标web而不是node,并在预渲染服务器中注释掉server.use(prerender.removeScriptTags());,该请求每次都会触发预渲染服务器,并且n错误被抛出,但没有任何东西被放弃。但似乎比以前更接近,所以我想我会更新。

更新

Prerender似乎没有执行任何Angular代码。如果我在我的index.html头部的脚本标签设置window.prerenderReady = false,然后尝试将其设置为true时再我的根组件实例化时,预渲染服务器超时:

import { Component, OnInit } from '@angular/core' 

@Component({ 
    selector: 'my-app', 
    template: ` 
     <div id="main"> all the things </div> 
    ` 
}) 
export class AppComponent implements OnInit 
{ 
    constructor(){} 

    ngOnInit() 
    { 
     // Prerender never executes this code before it times out 
     window.prerenderReady = true; 
     console.info('Prerender Ready'); 
    } 
} 
+0

看起来像那些JavaScript错误是防止PhantomJS(底层渲染引擎)失败并停止渲染页面。你有没有为Map添​​加一个polyfill? 'removeScriptTags'仅在页面完成渲染后删除脚本标记,因此不应影响任何与渲染有关的操作。 –

+0

在我的webpack配置中将'web'而不是'node'定向到预渲染es6错误。 prerender服务器返回200,但不执行Angular代码。 – MyCompassSpins

+0

是否有任何其他细节我可以提供,可能有助于得到一个答案呢? – MyCompassSpins

回答

0

我设法得到这与以下更改一起工作:

在Webpack配置中使用target: 'web'

使用target: 'es5'并将node_modules/typescript/lib/lib.es6.d.ts添加到tsconfig.json中的文件数组中。这可以防止es6上的编译时错误。

显然,尽管针对web和es5,但Webpack依然留下了PhantomJs无法处理的es6 styntax。我不喜欢在一个Typescript项目中包含babel的想法,但这是我发现的唯一工作:require('babel-polyfill');在任何可能使用任何es6语法的应用程序代码或供应商代码之前。

文档的head设置window.prerenderReady = false;,然后将其设置为true当实例根应用组件:

export class ApplicationComponent implements OnInit 
{ 
    ngOnInit() 
    { 
     window.prerenderReady = true; 
    } 
} 

注:以上以打字稿工作,你需要确保在窗口上存在属性prerenderReady。例如:

interface Window 
{ 
    prerenderReady:boolean; 
} 

在服务器端,请确保在配置prerender-node之前配置了任何路由。例如。:

export function routeConfig(app:express.Application):void 
{ 
    // Prerender 
    app.use(require('prerender-node').set('prerenderServiceUrl', CONFIG.prerenderServiceUrl)); 

    // Angular routes should return index.html 
    app.route(CONFIG.angularRoutes) 
     .get((req:Request, res:Response, next:NextFunction) => 
     { 
      return res.sendFile(`${app.get('appPath')}/client/index.html`); 
     }); 
} 

希望这可以帮助别人:)