Automattic / node-canvas

Node canvas is a Cairo backed Canvas implementation for NodeJS.
10.07k stars 1.16k forks source link

bindings.CanvasPatternInit is not a function (canvas > 2.8.0) #1934

Open flohall opened 2 years ago

flohall commented 2 years ago

Issue or Feature

We are developing a konva + node-canvas AWS Lambda serverless implementation. I am the only member in the team that switched some days ago to a new MacBook with Apple M1 Pro. Our application renders a video using konva + node-canvas and streams raw images to ffmpeg. The whole thing worked nicely inside the AWS Lambda docker container and locally on an Intel MacBook. On my new laptop I couldn't execute the code locally with canvas 2.8.0 - thats why I switched to github:Automattic/node-canvas#198080580a0e3938c48daae357b88a1638a9ddcd and now the code works on my new MacBook with Apple Silicon (M1 Pro) as well. See my answer on stack overflow here: https://stackoverflow.com/questions/67031187/error-node-canvas-was-built-without-jpeg-support/70064802#70064802 But with this version I cannot execute the code inside the docker anymore. So something between canvas 2.8.0 release and the current master breaks execution in Amazon Linux docker. The following issue occurs at runtime (no issues while building / installing canvas):

at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10))  function aborted due to:  TypeError: bindings.CanvasPatternInit is not a function
2021-11-22T13:01:23.594Z        b68a7de0-7cae-47b5-a259-751150dba856    ERROR   Unhandled Promise Rejection     {"errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"TypeError: bindings.CanvasPatternInit is not a function","reason":{"errorType":"TypeError","errorMessage":"bindings.CanvasPatternInit is not a function","stack":["TypeError: bindings.CanvasPatternInit is not a function","    at Object.<anonymous> (/var/task/node_modules/canvas/lib/pattern.js:12:10)","    at Module._compile (internal/modules/cjs/loader.js:1072:14)","    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10)","    at Module.load (internal/modules/cjs/loader.js:937:32)","    at Function.Module._load (internal/modules/cjs/loader.js:778:12)","    at Module.require (internal/modules/cjs/loader.js:961:19)","    at require (internal/modules/cjs/helpers.js:92:18)","    at Object.<anonymous> (/var/task/node_modules/canvas/index.js:4:23)","    at Module._compile (internal/modules/cjs/loader.js:1072:14)","    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10)"]},"promise":{},"stack":["Runtime.UnhandledPromiseRejection: TypeError: bindings.CanvasPatternInit is not a function","    at process.<anonymous> (/var/runtime/index.js:35:15)","    at process.emit (events.js:400:28)","    at processPromiseRejections (internal/process/promises.js:245:33)","    at processTicksAndRejections (internal/process/task_queues.js:96:32)"]}
time="2021-11-22T13:01:23.6" level=warning msg="State transition is not allowed"

Steps to Reproduce

not sure exactly what causes the issue, but here some canvas functions we use:


const stage = new Konva.Stage({
            width: stageWidth,
            height: stageHeight,
            container: canvas
        });
const layer = this.createLayer();
layer.listening(false);
stage.add(layer);

const image = new canvas.Image();
image.onload = () => {
                const konvaImage = new Konva.Image(imageProperties);
                konvaImage.cache();
                layer.add(konvaImage);
                resolve(konvaImage);
            };
            image.onerror = (err) => {
                reject(err);
            };
            image.src = imageUrl; 
});

stage.toCanvas().toBuffer('raw');

dockerfile:

### BUILDER CONTAINER IMAGE only used for building
FROM public.ecr.aws/lambda/nodejs:14 as builder

# update (and installing of software without fixed version) means that without code changes behaviour could be slightly different if a new image is created
# therefore every image version should be tested on staging system and deployed as is to production later
# this way we get most important OS security fixes
RUN yum -y update

# lambda insights extension to log lambda insights logs for better monitoring
RUN curl -O https://lambda-insights-extension.s3-ap-northeast-1.amazonaws.com/amazon_linux/lambda-insights-extension.rpm && \
    rpm -U lambda-insights-extension.rpm && \
    rm -f lambda-insights-extension.rpm

# only needed for setup (execution of subsequent command "tar")
RUN yum -y install tar xz

# old releases are used to have a fixed version of ffmpeg - update to most recent old-releases version if you like manually here
# TODO build ffmpeg from source or use yum installer for production ready code
RUN curl -o /tmp/ffmpeg.tar.xz https://www.johnvansickle.com/ffmpeg/old-releases/ffmpeg-4.2.2-amd64-static.tar.xz
RUN tar -xvf /tmp/ffmpeg.tar.xz -C /tmp/
RUN mkdir /opt/ffmpeglib/
RUN mv /tmp/ffmpeg-4.2.2-amd64-static/ffmpeg /opt/ffmpeglib/ffmpeg
RUN mv /tmp/ffmpeg-4.2.2-amd64-static/ffprobe /opt/ffmpeglib/ffprobe
RUN rm -r /tmp/*

# libraries needed for installation of npm package "canvas"
RUN yum -y install gcc-c++ cairo-devel pango-devel libjpeg-turbo-devel giflib-devel librsvg2-devel bzip2-devel

# needed for installing canvas diretly form github
RUN yum -y install git

# copy only files needed for npm install - so npm install will only be executed again if those files have changed
# .npmrc is needed for the vm-rendering-library to authenticate against nexus
COPY package.json .npmrc ./

# install all npm dependencies including dev dependencies
RUN npm install

# copy all remaining files not excluded in .dockerignore
COPY ./ ./

# fixing an issue in npm package canvas - must be executed after npm install, but before npm run build and again before execution
ENV LD_PRELOAD=/var/task/node_modules/canvas/build/Release/libz.so.1

# build typescript
RUN npm run build

# rename app.js to app.mjs to call ESM module from commonJS
RUN find ./dist -type f -name "*.js" -exec sed -i 's/\.js/\.mjs/g' {} \;
RUN find ./dist -type f -name "*.js" -exec sh -c 'mv "$0" "${0%.js}.mjs"' {} \;
RUN mv ./dist/video-merger/src/lambda/handler.mjs ./dist/video-merger/src/lambda/handler.js
RUN mv ./dist/video-renderer/src/lambda/handler.mjs ./dist/video-renderer/src/lambda/handler.js
RUN mv ./dist/video-splitter/src/lambda/handler.mjs ./dist/video-splitter/src/lambda/handler.js

# remove npm dev dependencies as they aren't needed anymore - make node_modules production ready
RUN npm prune --production

### END OF BUILDER CONTAINER IMAGE

### START OF RUNTIME CONTAINER IMAGE
FROM public.ecr.aws/lambda/nodejs:14

ARG SERVICE_NAME

# install again because some dependencies are needed at runtime
RUN yum -y install gcc-c++ cairo-devel pango-devel libjpeg-turbo-devel giflib-devel librsvg2-devel bzip2-devel
# copy over ffmepg from builder
COPY --from=builder /opt/ffmpeglib /opt/ffmpeglib
# copy over node_modules from builder
COPY --from=builder /var/task/node_modules ./node_modules
# copy shared files, which are shared between all different services
COPY --from=builder /var/task/dist/vm-rendering-backend-commons ./dist/vm-rendering-backend-commons
# copy over only the files from that specific service - rename the folder to service, as dynamic command names in docker are difficult
COPY --from=builder /var/task/dist/${SERVICE_NAME} ./dist/service

# fixing an issue in npm package canvas - must be executed after npm install, but before npm run build and again before execution
ENV LD_PRELOAD=/var/task/node_modules/canvas/build/Release/libz.so.1

ENV NODE_OPTIONS="--experimental-specifier-resolution=node"

# enable the lambda being executed - the correct handler function should be called
CMD ["dist/service/src/lambda/handler.handler"]

Your Environment

ENV 1 (on ARM MAC) (works)

ENV 1 (on ARM MAC) (doesn't work)

ENV 2 (on AMD64 docker) (doesn't work):

ENV 2 (on AMD64 docker) (works):

ppbl commented 2 years ago

+1

First of all, thank the team for their efforts. I sincerely hope to release a version that supports Apple M1🙏

ArthurClemens commented 2 years ago

I'm having the same issue with node-canvas 2.9.0 on a regular Macbook. Node v14.17.0.

dev-sandeep commented 2 years ago

Facing the same issue on Mac, Node 14

NimishVerma commented 1 year ago

having the same issue on a lambda layer