Angular预渲染:条件使用JS导致 ‘document is not defined’。

huangapple go评论64阅读模式
英文:

Angular Prerendering: Using JS conditionally causes 'document is not defined'

问题

I understand your question. It seems that Bootstrap is causing issues with pre-rendering due to its access to the document object even before Bootstrap.Modal is instantiated. To address this, you can try the following:

  1. Lazy Loading: You can try lazy loading Bootstrap or delaying its initialization until the component has fully loaded. This might prevent it from accessing document too early.

  2. Server-Side Rendering (SSR) Compatibility: Some libraries are not designed to work with SSR. Check if Bootstrap provides any SSR compatibility or if there are alternative libraries that work better in a server-side rendering environment.

  3. Debugging: To find the exact file where document is called, you can use source maps and debugging tools in your development environment. Look for any parts of the Bootstrap code that might be causing this issue.

  4. Alternative Libraries: If Bootstrap continues to be problematic, consider using alternative libraries that are designed with server-side rendering in mind or have fewer dependencies on the DOM.

Remember to consult Bootstrap's documentation and community forums for any updates or solutions related to server-side rendering compatibility.

英文:

I'm using Angular 15 and I'm trying to pre-render a website for SEO purposes. I understand that facilities such as document and window aren't available when pre-rendering because the code isn't running on a browser.

I'm using a few JS libraries that manipulate the DOM directly and in order to support pre-rendering I'm doing this:

import Typed from 'typed.js';

export class ExampleComponent implements OnInit {
  
  typed?: Typed;

  constructor(
    @Inject(PLATFORM_ID) private platformId: any
  ) { }

  ngOnInit(): void {
     if (isPlatformBrowser(this.platformId)) {
      this.typed = new Typed('#searchdomain', {
	      strings: ["example", "anoter" ""],
	      typeSpeed: 80,
	      contentType: "text"
	    });
    }	
  }

As you can see Typed is only instantiated if the application is running on a browser.

Now I tried to do the same with Bootstrap 5 however it fails.

import * as Bootstrap from 'bootstrap/dist/js/bootstrap.esm.min.js';

export class ExampleComponent implements OnInit {
  
  private bsModalInstance?: Bootstrap.Modal;
  @ViewChild('bsmodal', {read: ElementRef, static: false}) modalRef?: ElementRef;

  constructor(
    @Inject(PLATFORM_ID) private platformId: any
  ) { }

  ngOnInit(): void {
     if (isPlatformBrowser(this.platformId)) {
       this.bsModalInstance = new Bootstrap.Modal(this.modalRef?.nativeElement);
     }	
  }

Output of npm run prerender:

⠴ Prerendering 2 route(s) to -path-\-proj-\dist\-proj-\browser...
Unhandled Promise rejection: document is not defined ; Zone: <root> ; Task: Promise.then ; Value: ReferenceError: document is not defined
    at enableDismissTrigger (-path-\-proj-\dist\-proj-\server\main.js:1:3878580)
    at -path-\-proj-\dist\-proj-\server\main.js:1:3879522
    at -path-\-proj-\dist\-proj-\server\main.js:1:3977330
    at Object.<anonymous> (-path-\-proj-\dist\-proj-\server\main.js:1:3977562)
    at Module._compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:12)
    at Module.require (internal/modules/cjs/loader.js:974:19)
    at require (internal/modules/cjs/helpers.js:101:18) ReferenceError: document is not defined
    at enableDismissTrigger (-path-\-proj-\dist\-proj-\server\main.js:1:3878580)
    at -path-\-proj-\dist\-proj-\server\main.js:1:3879522
    at -path-\-proj-\dist\-proj-\server\main.js:1:3977330
    at Object.<anonymous> (-path-\-proj-\dist\-proj-\server\main.js:1:3977562)
    at Module._compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:12)
    at Module.require (internal/modules/cjs/loader.js:974:19)
    at require (internal/modules/cjs/helpers.js:101:18)
✖ Prerendering routes to -path-\-proj-\dist\-proj-\browser failed.
document is not defined

Why does it fail when Bootstraps's Bootstrap.Modal isn't even instantiated?

Is there any way to have more debug so I can find the exact file where document. is called?

Update: I decided to add a console.log() on the component's constructor and it never shows up. I believe bootstrap, when imported, is accessing the document right away, even before the Bootstrap.Modal call.

Thank you.

答案1

得分: 1

这确实是由Bootstrap在导入时访问windowsdocument和一些其他对象引起的问题。这个问题已经在https://github.com/twbs/bootstrap/pull/34989上进行讨论,并有一个修复了一些问题但不是全部的PR。

我决定分支该存储库并将进一步的修复添加到jo-ssr-friendly分支。同时,我也将它重新基于了最新的稳定版本。

如果将来有人遇到这个问题,可以直接从我的分支安装所有这些修复:

npm install "https://github.com/TCB13/bootstrap.git#jo-ssr-friendly" --save
英文:

This was indeed a problem caused by Bootstrap accessing the windows, document and some other objects when imported. This was already under discussion at https://github.com/twbs/bootstrap/pull/34989 with a PR that fixed some of the issues but not all.

I decided to fork the repository and add further fixes to the jo-ssr-friendly branch. Also rebased it to the latest stable release.

If anyone comes across this in the future all those fixes can be installed directly from my fork:

npm install "https://github.com/TCB13/bootstrap.git#jo-ssr-friendly" --save

huangapple
  • 本文由 发表于 2023年4月13日 20:32:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/76005487.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定