You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 17.2 SSR如何配置独立tsconfig实现模块替换

在Angular 17.2中为SSR替换依赖Document的ng2-dragula模块

因为Angular 17+不再单独提供tsconfig.server.json,没法通过路径映射直接区分浏览器和SSR环境的模块,你可以通过以下两种方案实现真实模块和存根模块的切换:

方案一:代码层面条件导入(推荐)

1. 创建ng2-dragula的存根模块

在项目中新建存根文件(比如src/app/dragula.stub.ts),模拟原模块的核心导出结构,确保SSR时不会引入依赖Document的代码:

import { NgModule, Injectable } from '@angular/core';

// 模拟DragulaModule的forRoot静态方法
@NgModule({
  exports: [],
  providers: []
})
export class DragulaModule {
  static forRoot() {
    return {
      ngModule: DragulaModule,
      providers: []
    };
  }
}

// 模拟DragulaService的核心方法(根据你项目中用到的方法补充)
@Injectable()
export class DragulaService {
  create() {}
  destroy() {}
  drop() { return { subscribe: () => ({ unsubscribe: () => {} }) }; }
}

2. 在AppModule中条件加载模块

利用Angular的isPlatformBrowser和动态导入,区分浏览器和SSR环境加载对应的模块:

import { NgModule, importProvidersFrom, inject } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { isPlatformBrowser, PLATFORM_ID } from '@angular/common';

@NgModule({
  imports: [
    BrowserModule.withServerTransition({ appId: 'serverApp' }),
  ],
  providers: [
    // 根据平台环境导入对应模块
    ...(isPlatformBrowser(inject(PLATFORM_ID)) 
      ? [importProvidersFrom(import('ng2-dragula').then(m => m.DragulaModule.forRoot()))]
      : [importProvidersFrom(import('./dragula.stub').then(m => m.DragulaModule.forRoot()))]
    )
  ]
})
export class AppModule { }

3. 组件中条件使用服务

在用到DragulaService的组件里,同样通过平台判断避免SSR时调用依赖Document的逻辑:

import { Component, OnInit, inject, PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { DragulaService } from 'ng2-dragula';

@Component({
  selector: 'app-drag-container',
  templateUrl: './drag-container.component.html'
})
export class DragContainerComponent implements OnInit {
  private platformId = inject(PLATFORM_ID);
  private dragulaService: DragulaService | null = null;

  ngOnInit() {
    if (isPlatformBrowser(this.platformId)) {
      this.dragulaService = inject(DragulaService);
      // 这里编写你的dragula业务逻辑,比如初始化拖拽容器
      this.dragulaService.create('bag-name');
    }
  }

  ngOnDestroy() {
    if (this.dragulaService) {
      this.dragulaService.destroy('bag-name');
    }
  }
}

方案二:通过Angular构建配置设置别名

Angular 17使用esbuild作为构建工具,可以在angular.json中为浏览器和SSR构建目标分别设置模块别名:

  1. 打开angular.json,找到项目的architect配置,分别修改build(浏览器构建)和server(SSR构建)的options:
{
  "projects": {
    "your-project-name": {
      "architect": {
        "build": {
          "options": {
            "resolve": {
              "alias": {
                "ng2-dragula": "./node_modules/ng2-dragula"
              }
            }
          }
        },
        "server": {
          "options": {
            "resolve": {
              "alias": {
                "ng2-dragula": "./src/app/dragula.stub.ts"
              }
            }
          }
        }
      }
    }
  }
}
  1. 确保存根模块的导出结构与原模块一致,组件中无需额外修改(但仍建议在组件中通过平台判断避免SSR时执行依赖Document的逻辑)。

内容的提问来源于stack exchange,提问作者Sergej

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 17:17:42