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构建目标分别设置模块别名:
- 打开
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" } } } } } } } }
- 确保存根模块的导出结构与原模块一致,组件中无需额外修改(但仍建议在组件中通过平台判断避免SSR时执行依赖Document的逻辑)。
内容的提问来源于stack exchange,提问作者Sergej
相关产品推荐
相关产品推荐

