Angular Universal SSR集成JSDOM遇canvas依赖及迭代器错误求解
Angular SSR中正确加载JSDOM window对象的问题
在Angular SSR项目中,尝试通过JSDOM创建window和document对象以初始化jQuery(需枚举其所有方法),但遇到canvas依赖解析失败问题。先后尝试忽略canvas打包、安装canvas并配置node-loader、externals等方案,均触发AsyncIteratorPrototype类型错误,现寻求在server.ts中正确加载JSDOM window对象的方法。
报错信息
- 初始报错
ERROR in ./node_modules/jsdom/lib/jsdom/utils.js Module not found: Error: Can't resolve 'canvas' in '/node_modules/jsdom/lib/jsdom'
- 使用IgnorePlugin后报错
Compiled successfully. /server/main.js:168664 const AsyncIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf( /*#__PURE__*/_wrapAsyncGenerator(function* () {})).prototype); ^ TypeError: Cannot convert undefined or null to object at Function.getPrototypeOf (<anonymous>)
- 安装canvas后报错
./node_modules/canvas/build/Release/canvas.node:1:0 - Error: 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
已尝试的配置
IgnorePlugin配置
plugins: [ new webpack.IgnorePlugin({ resourceRegExp: /canvas/, contextRegExp: /jsdom$/, }), ],
node-loader配置
module.exports = (config, context) => { return merge(config, { target: 'node', node: { __dirname: false, }, module: { rules: [ { test: /\.node$/, loader: 'node-loader', }, ], }, }); };
externals配置
const { merge } = require('webpack-merge'); module.exports = (config, context) => { return merge(config, { target: 'node', // Important (1) externals: { canvas: 'commonjs canvas', // Important (2) }, }); };
期望实现的server.ts代码
import { DOMWindow, JSDOM } from 'jsdom'; const window: DOMWindow = new JSDOM('<!DOCTYPE html><html><body></body></html>', { url: 'http://localhost' }).window;
可行解决方案
1. 调整JSDOM版本
JSDOM高版本对canvas依赖和Node环境要求严苛,建议降级至jsdom@16.7.0,该版本对canvas依赖更宽松,适配Angular SSR的Webpack配置。
2. 优化Webpack配置
在Angular SSR的Webpack配置文件中,同时排除JSDOM和canvas的原生依赖,直接禁用canvas模块解析:
const { merge } = require('webpack-merge'); module.exports = (config, context) => { return merge(config, { target: 'node', externals: { jsdom: 'commonjs jsdom', canvas: 'commonjs canvas' }, resolve: { alias: { 'canvas': false } } }); };
3. 修正server.ts初始化逻辑
将JSDOM的window对象挂载到全局,再完成jQuery初始化与方法枚举:
import { JSDOM } from 'jsdom'; import * as $ from 'jquery'; // 初始化JSDOM并挂载全局对象 const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>', { url: 'http://localhost' }); (global as any).window = dom.window; (global as any).document = dom.window.document; (global as any).navigator = dom.window.navigator; // 初始化jQuery并枚举所有方法 const jQueryInstance = $(dom.window); const jqueryMethods = Object.getOwnPropertyNames(jQueryInstance.fn) .filter(prop => typeof jQueryInstance.fn[prop] === 'function'); console.log('jQuery方法列表:', jqueryMethods);
4. 解决AsyncIteratorPrototype错误
该错误源于Webpack对异步生成器的处理问题,需确保:
- Node.js版本升级至14+(支持ES2018+语法)
- 在
tsconfig.server.json中添加配置:
{ "compilerOptions": { "target": "ES2018", "lib": ["ES2018", "DOM"] } }
内容的提问来源于stack exchange,提问作者Greg
相关产品推荐
相关产品推荐

