2016-11-12 85 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`); 
     }); 
} 

希望這可以幫助別人:)