Angular SSR构建运行报错:document is not defined(plyr.io导致)
Angular SSR 运行报错:ReferenceError: document is not defined
执行Angular SSR构建并运行时,出现以下错误:
ReferenceError: document is not defined .../dist/app/server/vendor.js:319308:13 at Module.56601 (.../dist/app/server/vendor.js:319317)
此前已在所有页面手动注入document,但错误转移到了vendor.js。经排查,问题源于引入的plyr.io库在服务端渲染阶段直接调用了document对象,导致SSR运行失败。完整CLI错误日志如下:
myapp@0.0.1 serve:ssr ... > node dist/app/server/main.js .../dist/app/server/vendor.js:319308 const e = document.createElement("span"), ^ ReferenceError: document is not defined at .../dist/app/server/vendor.js:319308:13 at Module.56601 (.../dist/app/server/vendor.js:319317:3) at __webpack_require__ (.../dist/app/server/main.js:24408:42) at Module.80518 (.../dist/app/server/main.js:7629:62) at __webpack_require__ (.../dist/app/server/main.js:24408:42) at Module.70771 (.../dist/app/server/main.js:20312:94) at __webpack_require__ (.../dist/app/server/main.js:24408:42) at Module.59229 (.../dist/app/server/main.js:99:111) at __webpack_require__ (.../dist/app/server/main.js:24408:42) at Module.63370 (.../dist/app/server/main.js:819:72) npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! myapp@0.0.1 serve:ssr: `node dist/app/server/main.js` npm ERR! Exit status 1 npm ERR! Failed at the myapp@0.0.1 serve:ssr script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: npm ERR! .../.npm/_logs/2023-07-27T05_02_50_176Z-debug.log abhay@Abhays-MacBook-Pro myapp % code . abhay@Abhays-MacBook-Pro myapp % npm run serve:ssr > myapp@0.0.1 serve:ssr ... > node dist/app/server/main.js .../dist/app/server/vendor.js:319308 const e = document.createElement("span"), ^ ReferenceError: document is not defined at .../dist/app/server/vendor.js:319308:13 at Module.56601 (.../dist/app/server/vendor.js:319317:3) at __webpack_require__ (.../dist/app/server/main.js:24408:42) at Module.80518 (.../dist/app/server/main.js:7629:62) at __webpack_require__ (.../dist/app/server/main.js:24408:42) at Module.70771 (.../dist/app/server/main.js:20312:94) at __webpack_require__ (.../dist/app/server/main.js:24408:42) at Module.59229 (.../dist/app/server/main.js:99:111) at __webpack_require__ (.../dist/app/server/main.js:24408:42) at Module.63370 (.../dist/app/server/main.js:819:72) npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! myapp@0.0.1 serve:ssr: `node dist/app/server/main.js` npm ERR! Exit status 1 npm ERR! Failed at the myapp@0.0.1 serve:ssr script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: npm ERR! .../.npm/_logs/2023-07-27T05_03_11_215Z-debug.log
解决方案
1. 动态导入plyr.io,仅在浏览器环境初始化
利用Angular的isPlatformBrowser判断当前环境,仅在浏览器中加载并初始化plyr:
import { Component, OnInit, Inject, PLATFORM_ID } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; @Component({ selector: 'app-your-component', templateUrl: './your-component.component.html', styleUrls: ['./your-component.component.css'] }) export class YourComponent implements OnInit { constructor(@Inject(PLATFORM_ID) private platformId: Object) {} ngOnInit(): void { if (isPlatformBrowser(this.platformId)) { // 动态导入plyr import('plyr').then((Plyr) => { // 初始化播放器 const player = new Plyr.default('#your-player-element'); // 添加自定义配置 player.on('play', () => { console.log('播放开始'); }); }); } } }
2. 配置Angular构建脚本,仅浏览器端加载plyr
如果是全局引入plyr,修改angular.json,将plyr脚本仅添加到浏览器构建配置中,排除服务端构建:
{ "projects": { "your-app-name": { "architect": { "build": { "options": { "scripts": [ "node_modules/plyr/dist/plyr.js" ] } }, "server": { "options": { // 移除此处的plyr脚本引用 } } } } } }
3. 封装Angular指令,延迟初始化(推荐)
创建一个自定义指令,确保在DOM渲染完成且浏览器环境下初始化plyr,避免服务端执行:
import { Directive, ElementRef, OnInit, Inject, PLATFORM_ID } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; @Directive({ selector: '[appPlyr]' }) export class PlyrDirective implements OnInit { constructor( private el: ElementRef, @Inject(PLATFORM_ID) private platformId: Object ) {} ngOnInit(): void { if (isPlatformBrowser(this.platformId)) { import('plyr').then((Plyr) => { new Plyr.default(this.el.nativeElement); }); } } }
在模板中使用:
<video appPlyr controls> <source src="your-video.mp4" type="video/mp4"> </video>
4. 临时方案:服务端模拟DOM环境(不推荐)
使用domino库在服务端模拟浏览器的document对象,但可能引发其他兼容性问题,仅作为临时应急方案:
- 安装依赖:
npm install domino --save-dev - 修改
server.ts,在导入Angular模块前添加:
import * as domino from 'domino'; const win = domino.createWindow(''); global['document'] = win.document; global['window'] = win;
内容的提问来源于stack exchange,提问作者abhay jani
相关产品推荐
相关产品推荐

