【问题标题】:Present canvas interface in shared code on both server and client在服务器和客户端的共享代码中呈现画布界面
【发布时间】:2017-10-04 12:56:25
【问题描述】:

我正在尝试编写使用 HTML 画布的共享代码(在服务器和客户端上运行)。

在客户端上,这应该可以正常工作。在服务器上,Node 没有画布(或 DOM),所以我想使用 node-canvas 插件:https://github.com/Automattic/node-canvas。

但是,我无法找到一种不会使 webpack 尝试将 node-canvas 捆绑到我的客户端代码中的方法来访问它(这会使 webpack 崩溃)。有没有什么方法可以加载节点画布,这样我就可以使用在浏览器中使用的相同代码来引用它,并且不会让 webpack 严重崩溃?


我目前的努力,没有奏效:

canvas.server.js

import Canvas from 'canvas';

const createCanvas = (width, height) => new Canvas(width, height);

export default createCanvas;

canvas.client.js

const createCanvas = (width, height) => {
  const canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;

  return canvas;
};

export default createCanvas;

canvas.js

let createCanvas;

if (typeof document === 'undefined') {
  // SERVER/node
  createCanvas = require('./canvas.server.js');
} else {
  // BROWSER
  createCanvas = require('./canvas.client.js');
}

export default createCanvas;

使用中:

import createCanvas from './canvas';

const canvasElement = createCanvas(width, height);
const ctx = canvasElement.getContext('2d');

不幸的是,webpack 仍然捆绑在 node-canvas 中。

【问题讨论】:

  • 如果有人想知道:在服务器和客户端上,画布将其内容转储到数据 URL 中,该 URL 在页面上呈现为 SVG 内的 。这都是非常 hacky和奇怪的,可能无论如何都不会起作用,但我想尝试一下,这是我坚持的步骤。
  • 我不明白为什么您需要渲染同一画布的两个相同副本。您最好在服务器上保留画布的抽象副本,然后在需要图像时(其他客户端)发送摘要并让每个客户端渲染到图像。所有 node.js 画布 API 都是软件渲染和慢!您将很快使服务器陷入瘫痪,从而使客户端通过 GPU 轻松处理像素。
  • 我没有服务器进程。画布仅在构建时将整个应用程序缩减为平面文件时呈现一次,然后在用户离开初始视图时在客户端上重新创建。

标签: node.js canvas webpack node-canvas


【解决方案1】:

您是否尝试仅要求 node-canvas when the code is running in node?

如果你在前端代码中没有实际调用 require,webpack 不会捆绑它。这意味着在上述条件语句中调用实际的require,而不是在文件顶部。这个很重要。另外,请确认您没有将 node-canvas 作为 webpack 的入口点。

例子:

// let's assume there is `isNode` variable as described in linked answer
let canvas;
if (isNode) {
  const Canvas = require('canvas');
  canvas = new Canvas(x, y);
else {
  canvas = document.getElementById('canvas');
}
// get canvas context and draw on it

OP 提供代码示例后编辑:

我已经在this WebpackBin 中复制了确切的结构,以证明这应该按照上面的说明工作。毕竟,这是 common.js(和其他模块加载器)的特性,因此在 webpack 中得到支持。

我对代码的更改:

  1. 将 canvas.client.js 和 canvas.server.js 中的代码替换为 console.log 将在该行调用的代码
  2. 修复了require 与export default 的错误使用(应该是require(...).default)。无关紧要,但必须这样做才能使代码正常工作。
  3. 删除了canvasElement.getContex 调用。在示例代码中不起作用并且无论如何都无关紧要,因此没有必要模拟它。

【讨论】:

  • @futuraprime 我刚刚更新了我的答案并添加了一个示例。你是这样做的吗?另外,请注意验证 node-canvas 不是 webpack 中的入口点的部分,例如与供应商文件捆绑在一起。我敢肯定,如果你这样做,webpack 不应该捆绑它。如果是这样,你就没有按照我建议的方式做事。
  • 我已将我当前的尝试添加到问题中。我认为这是做同样事情的一种更迂回的方式(它基于我在这里看到的其他一些答案,尽管大多数人说他们也没有工作)。我的 webpack 配置只有两个入口点,我的 index.js 和 react-hot-loader。
  • @futuraprime 你肯定在其他地方有问题。我很快就破解了this example on WebpackBin。它随机选择文件 a.js 或 b.js 进行测试,打开控制台并点击保存按钮(左上角或 ctrl/cmd+s),然后观察记录的内容。它按我所说的那样工作。代码的旁注,如果您使用 export default,则必须使用 require(...).default 访问导出的值。
  • 一个建议:尝试我链接的确切代码以确定isNode。即使在您的节点代码中也可能设置了 document 值,而 typeof document === 'undefined' 不再正确。事实是这部分代码必须执行,否则您必须从代码中的其他位置访问node-canvas。此功能在所有 common.js 环境中都是默认的,不要解析从未需要的代码,webpack 从一开始就尊重这一点。在您的情况下,无论如何它都不应该这样做。
  • 为了证明这一点,我在另一个 WebpackBin 中复制了您的确切情况。请参阅更新的答案以获取链接和说明。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-02
  • 2012-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
相关资源
最近更新 更多