Node.js 在服务器和客户端的共享代码中显示画布接口

Node.js 在服务器和客户端的共享代码中显示画布接口,node.js,canvas,webpack,node-canvas,Node.js,Canvas,Webpack,Node Canvas,我正在尝试编写使用HTML画布的共享代码(在服务器和客户端上运行) 在客户机上,这应该工作得很好。在服务器上,Node没有画布(或DOM),因此我想使用Node canvas插件: 然而,我无法找到一种方法来访问它,而不让webpack尝试将节点画布捆绑到我的客户端代码中(这会使webpack崩溃)。是否有任何方法可以加载节点画布,这样我就可以使用浏览器中使用的相同代码引用它,而不会使网页包崩溃 我目前的努力没有奏效: canvas.server.js import Canvas from '

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

在客户机上,这应该工作得很好。在服务器上,Node没有画布(或DOM),因此我想使用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仍然捆绑在节点画布中。

您是否尝试仅要求
节点画布

如果您实际上没有在前端代码中调用require,webpack将不会捆绑它。这意味着在上述条件语句中调用实际的
require
,而不是在文件的顶部。这很重要。另外,请确认您没有将
节点画布
作为入口点放在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
操作后编辑提供的代码示例:

我在中复制了确切的结构,以证明它应该按照上面的解释工作。毕竟,这是common.js(和其他模块加载器)的一项功能,因此在webpack中受支持

我对代码的更改:

  • canvas.client.js
    canvas.server.js
    中的代码替换为该行将调用的
    console.log
  • 修复了将
    require
    导出默认值一起错误使用的问题(应该是
    require(…)。默认值
    )。不相关,但必须这样做才能使代码正常工作
  • 删除了
    canvasElement.getContex
    调用。在示例代码中不起作用,并且无论如何都是无关的,因此没有必要对其进行模拟

  • 您是否仅尝试要求
    节点画布

    如果您实际上没有在前端代码中调用require,webpack将不会捆绑它。这意味着在上述条件语句中调用实际的
    require
    ,而不是在文件的顶部。这很重要。另外,请确认您没有将
    节点画布
    作为入口点放在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
    
    操作后编辑提供的代码示例:

    我在中复制了确切的结构,以证明它应该按照上面的解释工作。毕竟,这是common.js(和其他模块加载器)的一项功能,因此在webpack中受支持

    我对代码的更改:

  • canvas.client.js
    canvas.server.js
    中的代码替换为该行将调用的
    console.log
  • 修复了将
    require
    导出默认值一起错误使用的问题(应该是
    require(…)。默认值
    )。不相关,但必须这样做才能使代码正常工作
  • 删除了
    canvasElement.getContex
    调用。在示例代码中不起作用,并且无论如何都是无关的,因此没有必要对其进行模拟

  • 如果有人想知道:在服务器和客户机上,画布都会将其内容转储到一个数据URL中,该URL在页面上呈现为SVG内部的。这一切都是非常黑客和怪异的,可能无论如何都不会起作用,但我想尝试一下,这是我坚持的一步。我不明白为什么你需要相同画布的两个相同副本。最好在服务器上保留画布的抽象副本,然后在需要图像时(其他客户端),发送抽象并让每个客户端渲染图像。所有node.js画布API都是软件渲染,速度很慢!你会让你的服务器很快陷入困境,客户端通过GPU轻松处理像素。我没有服务器进程。画布仅在构建时呈现一次,整个应用程序被简化为平面文件,然后在用户离开初始视图时在客户端上重新创建。如果有人想知道:在服务器和客户端上,画布将其内容转储到数据URL中,该URL在页面上呈现为SVG内部。这一切都是非常黑客和怪异的,可能无论如何都不会起作用,但我想尝试一下,这是我坚持的一步。我不明白为什么你需要相同画布的两个相同副本。最好在服务器上保留画布的抽象副本,然后在需要图像时(其他客户端),发送抽象并让每个客户端渲染图像。所有node.js画布API都是软件渲染,速度很慢!你会让你的服务器很快陷入困境,客户端通过GPU轻松处理像素。我没有服务器进程。画布仅在生成时渲染一次,此时整个应用程序将简化为平面文件,然后在用户离开初始视图时在客户端上重新创建。@futuraprime我刚刚更新了答案并添加了一个示例。你是这样做的吗?另外,请注意验证
    节点画布
    不是webpack中的入口点的部分,例如与供应商文件捆绑。我敢肯定,如果你这样做,webpack不应该捆绑它。如果是这样的话,你就没有按照我的建议去做。我已经在这个问题上添加了我目前的尝试。我认为这是做同样事情的一种更迂回的方式(这是基于我在这里看到的一些其他答案,尽管大多数人说它们也不起作用)。我的网页包配置只有两个入口点,My index.js和react hot loader。@futuraprime您肯定在其他地方有问题。我很快就拼凑起来了。它随机选取文件a.js或b.js,对其进行测试,打开控制台并点击保存按钮(左上角或ctrl/cmd+s),然后观察记录的内容。它正按照我说的那样工作。如果您使用的是
    e,则代码的旁注