我有一个用angular universal构建的app "@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
但这并没有给出任何结果。错误仍然存在。而且构建失败。
目前我使用的是动态 import()
来加载canvas库到其中的一个angular服务中,如果平台为 server
. 出于某种原因,我以为它不会尝试默认捆绑动态导入的脚本,也许有其他的变通办法。
所以,总结一下,理想的情况是,我希望有一个只在服务器端可用的服务,它将使用的是 canvas
库里面。而且不会破坏angular的构建。
只包含在服务器捆绑包中
目前,我使用动态导入()将canvas库加载到angular服务中,如果平台是服务器的话。
这将这个依赖关系包含到任何使用你的服务的捆绑包中(带有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
})
}
}
Webpack问题
如果你想避免将它包含在你的bundle中而保留外部,你可以设置一个 "外部依赖"。bundleDependencies: false
中的服务器构建器选项。angular.json
.它有一个副作用,那就是不能从angular库中删除任何调试代码--所以你需要采取额外的步骤来准备你的应用程序的生产(见 https:/angular.ioguideivy-compatibility#payload-siz-debugging。 以获得一些提示)