尝试为SSR构建Angular 9 Universal项目时出现此错误:
/Users/my-project/dist/server.js:28676
Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__metadata"])("design:type", HTMLVideoElement)
ReferenceError: HTMLVideoElement is not defined
我在项目中使用了mat-video播放器,我怀疑这是导致错误的原因,但是我不确定如何解决此问题。有什么想法吗?
我的 tsconfig.json :
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"baseUrl": "src",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es2015",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2017",
"dom"
],
"module": "esnext",
"resolveJsonModule": true,
}
}
答案 0 :(得分:0)
我终于成功了! 1 周后!
我遇到了同样的问题:
<块引用>HTMLVideoElement 未定义
虽然环境与 OP 提供的环境不同,但解决方案是相同的,以避免执行 HTMLVideoElement 代码。
我使用 pixi.js 和 Angular Universal 进行服务器端渲染 (SSR)。
我按照 https://angular.io/guide/universal 处的文档运行 ng add @nguniversal/express-engine
在我的 Angular 应用程序中设置了 SSR
我通过避免导致问题的 pixi.js 代码解决了这个问题。即:
PIXI.Texture.from('assets/image.png');
此调用在此处的函数签名中引用了 HTMLVideoElement ... https://pixijs.download/dev/docs/PIXI.Texture.html#from
我改用 PIXI.Loader() 来加载纹理:
this.loader = new PIXI.Loader()
this.texturesArray.forEach((texture: string) => this.loader.add(texture))
this.loader.onComplete.add(this.onTexturesLoaded)
this.loader.load()
问题消失了,现在我的服务器启动正常。
我还必须通过添加属性来更改 tsconfig.server.json 中的“compilerOptions”:
"module": "commonjs"
这是我为感兴趣的人提供的最终工作 server.ts 代码:
import 'zone.js/dist/zone-node'
import { ngExpressEngine } from '@nguniversal/express-engine'
import express from 'express'
import { join } from 'path'
import { APP_BASE_HREF } from '@angular/common'
import { existsSync } from 'fs'
import { cloneDeep } from 'lodash-es'
import { mockCanvas } from './mock-canvas'
const fs = require('fs')
const path = require('path')
const filename = path.join(__dirname, '../browser', 'index.html')
const template = fs.readFileSync(filename).toString()
const domino = require('domino')
const win = domino.createWindow(template)
win.HTMLCanvasElement.prototype = cloneDeep(win.HTMLCanvasElement.prototype)
mockCanvas(win)
global['window'] = win
global['document'] = win.document
import { AppServerModule } from './src/main.server'
// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
const server = express()
const distFolder = join(process.cwd(), 'dist/gematriangle/browser')
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index'
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule
}))
server.set('view engine', 'html')
server.set('views', distFolder)
// Example Express Rest API endpoints
// server.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}))
// All regular routes use the Universal engine
server.get('*', (req: any, res: any) => {
res.render(indexHtml, {req, providers: [{provide: APP_BASE_HREF, useValue: req.baseUrl}]})
})
return server
}
function run(): void {
const port = process.env.PORT || 4000
// Start up the Node server
const server = app()
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`)
})
}
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire
const mainModule = __non_webpack_require__.main
const moduleFilename = mainModule && mainModule.filename || ''
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run()
}
export * from './src/main.server'
和 PIXI 也需要的 mockCanvas 看起来像这样:
export function mockCanvas(window: any) {
window.HTMLCanvasElement.prototype.getContext = function() {
return {
fillRect: function() {},
clearRect: function() {},
getImageData: function(x: any, y: any, w: any, h: any) {
return {
data: new Array(w * h * 4)
}
},
putImageData: function() {},
createImageData: function(): any { return []},
setTransform: function() {},
drawImage: function() {},
save: function() {},
fillText: function() {},
restore: function() {},
beginPath: function() {},
moveTo: function() {},
lineTo: function() {},
closePath: function() {},
stroke: function() {},
translate: function() {},
scale: function() {},
rotate: function() {},
arc: function() {},
fill: function() {},
measureText: function() {
return {width: 0}
},
transform: function() {},
rect: function() {},
clip: function() {}
}
}
window.HTMLCanvasElement.prototype.toDataURL = function() {
return ''
}
}