角度通用:从捆绑中排除仅节点依赖项



我有一个用角度通用"@nguniversal/express-engine": "^9.1.1"构建的应用程序。我正在尝试添加服务器端节点画布("canvas": "^2.6.1"(以在服务器上渲染某些图像。我不需要这个库在客户端可用,因此想从捆绑包中排除它。

尝试使用npm run dev:ssr运行应用程序时 - 我收到与该库相关的错误:

ERROR in ./node_modules/canvas/build/Release/canvas.node 1:0
Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are 
configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
this.debug is not a function

经过一些研究,我发现externalDependencies选项被添加到angular.json服务器构建选项中。我试图将canvas库路径添加到externalDependencies数组中,但这没有给出任何结果。错误仍然存在。构建正在失败。

目前,如果平台server,我正在使用动态import()将画布库加载到角度服务之一中。出于某种原因,我认为默认情况下它不会尝试捆绑动态导入的脚本。 也许还有其他一些解决方法。

因此,总而言之,理想情况下,我希望拥有仅在服务器端可用的特定服务,并且将使用其中的canvas库。并且不会破坏棱角分明的构建。

仅包含在服务器捆绑包中

目前,如果平台是服务器,我正在使用动态import((将画布库加载到角度服务之一中

这包括将此依赖项包含在使用您的服务的任何捆绑包中(带有 canvas 的块可能仍然延迟加载 - 但 webpack 无论如何都必须处理它(。

在 Angular 中执行此操作的一种惯用方法是通过依赖注入:

// no side effect here - safe to import in browser or server files
// canvas-polyfill.token.ts
export type PolyfillLoader = () => Promise<any>;
export const CANVAS_POLYFILL_LOADER = new InjectionToken<PolyfillLoader>();
// app.server.module.ts
const canvasLoader = () => import('canvas');
@NgModule({
...
providers: [{provide: CANVAS_POLYFILL_LOADER, useValue: canvasLoader}]
})
export class AppServerModule {}
// your service
@Injectable()
class MyService {
constructor(@Optional() @Inject(CANVAS_POLYFILL_LOADER) private polyfillLoader: PolyfillLoader) {}
doYourStuff() {
const whenReady = this.polyfillLoader ? this.polyfillLoader() : Promise.resolve();
return whenReady.then(() => {
// do something useful
})
}
}

网络包问题

综上所述 - 在构建服务器捆绑包时,仍然不能保证 Angular 的 webpack 能够处理这种依赖关系。 如果要避免将其包含在捆绑包中并保持外部,则可以在angular.json中为服务器构建器设置bundleDependencies: false选项。 不过,它有一个副作用,即不会从角度库中删除任何调试代码 - 因此您需要执行额外的步骤来准备您的应用程序以进行生产(有关一些提示,请参阅 https://angular.io/guide/ivy-compatibility#payload-size-debugging(

最新更新