TryGhost / Ghost

Independent technology for modern publishing, memberships, subscriptions and newsletters.
https://ghost.org
MIT License
46.87k stars 10.2k forks source link

Lexical kg-cards missing on website after ghost update with zip #18948

Closed ASAMedia closed 4 months ago

ASAMedia commented 10 months ago

Issue Summary

I updated my custom Ghost to version 5.71.2. It runs fine in development via yarn dev, but upgrading the 5.70 docker with an .tgz file from yarn archive brings up some problems. When editing existing posts (mobiledoc) and saving them with the new editor (lexical) ALL images and other kg-cards will not show up anymore on the website of this post. There is not a single error in webconsole or docker-compose logs -f during/saving editing or while upgrading ghost. When running the original 5.71 docker image or yarn dev everything runs fine without this issue.

~Looking into the sqlite database, I'll found that the lexical code is complete with the image.~

So it seems like an update problem, that I cant narrow down without some help. Any idea how to fix this?

Steps to Reproduce

  1. create the following DOCKERFILE
    FROM ghost:5.71.0-alpine
    WORKDIR /var/lib/ghost
    COPY ./ghost-5.71.2.tgz /var/lib
    RUN apk add --no-cache git
    USER node
    RUN yarn --version
    RUN yarn cache clean
    RUN rm -rf node_modules
    RUN yarn
    RUN chmod -R 00775 /var/lib/ghost/content &&\
    ghost update --force --zip /var/lib/ghost-5.71.2.tgz
    RUN chmod -R 00775 /var/lib/ghost/content
  2. create the docker-compose.yml
    
    version: '3.1'

services:

lfg-ghost: build: . container_name: lfg-ghost restart: always ports:

Ghost Version

5.71.2

Node.js Version

18

How did you install Ghost?

docker-compose

Database type

SQLite3

Browser & OS version

Win 11/Ubuntu 20/Chrome/Firefox/Edge

Relevant log / error output

No response

Code of Conduct

ASAMedia commented 10 months ago

An example from the website I'm running (lyonel-feininger-gymnasium.de): It looks like this in the editor grafik

and like this on the website grafik

As you can see, the snow picture is nowhere to be seen.

ASAMedia commented 10 months ago

Ok, I've got some more information: I looked into the db and found that the images are against my previous claims in fact are NOT present in the lexical field of the post

Here is the code snippet from the working original docker version

 receive emails when new content is publishrfed!</p><figure class="kg-card kg-image-card kg-width-wide"><img src="__GHOST_URL__/content/images/2023/11/IMG_2658.jpeg" class="kg-image" alt="" loading="lazy" width="2000" height="1500" srcset="__GHOST_URL__/content/images/size/w600/2023/11/IMG_2658.jpeg 600w, __GHOST_URL__/content/images/size/w1000/2023/11/IMG_2658.jpeg 1000w, __GHOST_URL__/content/images/size/w1600/2023/11/IMG_2658.jpeg 1600w, __GHOST_URL__/content/images/2023/11/IMG_2658.jpeg 2000w" sizes="(min-width: 1200px) 1200px"></figure><figure class="kg-card kg-image-card"><img src="__GHOST_URL__/content/images/2023/11/Screenshot-2023-11-11-at-18-42-13-Studienfahrt-nach-Gillingham--Kent-GB--der-9.-Klassen.png" class="kg-image" alt="" loading="lazy" width="1920" height="673" srcset="__GHOST_URL__/content/images/size/w600/2023/11/Screenshot-2023-11-11-at-18-42-13-Studienfahrt-nach-Gillingham--Kent-GB--der-9.-Klassen.png 600w, __GHOST_URL__/content/images/size/w1000/2023/11/Screenshot-2023-11-11-at-18-42-13-Studienfahrt-nach-Gillingham--Kent-GB--der-9.-Klassen.png 1000w, __GHOST_URL__/content/images/size/w1600/2023/11/Screenshot-2023-11-11-at-18-42-13-Studienfahrt-nach-Gillingham--Kent-GB--der-9.-Klassen.png 1600w, __GHOST_URL__/content/images/2023/11/Screenshot-2023-11-11-at-18-42-13-Studienfahrt-nach-Gillingham--Kent-GB--der-9.-Klassen.png 1920w" sizes="(min-width: 720px) 720px"></figure><hr>

And here the one I'm getting with my updated version inside docker

 receive emails when new content is publishrfed!</p>

Now the question where does this go wrong?

ASAMedia commented 10 months ago

Another Update: I downloaded the original source files from 5.71.2 build them to an archive with yarn archive and used the resulting ghost-5.71.2.tgz.zip to update the ghost 5.71.0-alpine docker.

Result: The problem is still occuring the same way as before :(

So it seems like in the build or update process the reference to the js for the kg-cards/nodes goes missing. I will attach some log info below, where the missing functions/attr are named when clicking the save/update button in the lexical-editor:

log output
lfg-ghost | CodeBlockNode must implement static "getType" method lfg-ghost | CodeBlockNode must implement static "clone" method lfg-ghost | CodeBlockNode must implement "decorate" method lfg-ghost | CodeBlockNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | CodeBlockNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | ImageNode must implement static "getType" method lfg-ghost | ImageNode must implement static "clone" method lfg-ghost | ImageNode must implement "decorate" method lfg-ghost | ImageNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | MarkdownNode must implement static "getType" method lfg-ghost | MarkdownNode must implement static "clone" method lfg-ghost | MarkdownNode must implement "decorate" method lfg-ghost | MarkdownNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | MarkdownNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | VideoNode must implement static "getType" method lfg-ghost | VideoNode must implement static "clone" method lfg-ghost | VideoNode must implement "decorate" method lfg-ghost | VideoNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | AudioNode must implement static "getType" method lfg-ghost | AudioNode must implement static "clone" method lfg-ghost | AudioNode must implement "decorate" method lfg-ghost | AudioNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | AudioNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | CalloutNode must implement static "getType" method lfg-ghost | CalloutNode must implement static "clone" method lfg-ghost | CalloutNode must implement "decorate" method lfg-ghost | CalloutNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | CalloutNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | HorizontalRuleNode must implement static "getType" method lfg-ghost | HorizontalRuleNode must implement static "clone" method lfg-ghost | HorizontalRuleNode must implement "decorate" method lfg-ghost | HorizontalRuleNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | HorizontalRuleNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | HtmlNode must implement static "getType" method lfg-ghost | HtmlNode must implement static "clone" method lfg-ghost | HtmlNode must implement "decorate" method lfg-ghost | HtmlNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | HtmlNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | FileNode must implement static "getType" method lfg-ghost | FileNode must implement static "clone" method lfg-ghost | FileNode must implement "decorate" method lfg-ghost | FileNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | ToggleNode must implement static "getType" method lfg-ghost | ToggleNode must implement static "clone" method lfg-ghost | ToggleNode must implement "decorate" method lfg-ghost | ToggleNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | ToggleNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | ButtonNode must implement static "getType" method lfg-ghost | ButtonNode must implement static "clone" method lfg-ghost | ButtonNode must implement "decorate" method lfg-ghost | ButtonNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | ButtonNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | HeaderNode must implement static "getType" method lfg-ghost | HeaderNode must implement static "clone" method lfg-ghost | HeaderNode must implement "decorate" method lfg-ghost | HeaderNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | HeaderNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | BookmarkNode must implement static "getType" method lfg-ghost | BookmarkNode must implement static "clone" method lfg-ghost | BookmarkNode must implement "decorate" method lfg-ghost | PaywallNode must implement static "getType" method lfg-ghost | PaywallNode must implement static "clone" method lfg-ghost | PaywallNode must implement "decorate" method lfg-ghost | PaywallNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | PaywallNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | ProductNode must implement static "getType" method lfg-ghost | ProductNode must implement static "clone" method lfg-ghost | ProductNode must implement "decorate" method lfg-ghost | ProductNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | EmbedNode must implement static "getType" method lfg-ghost | EmbedNode must implement static "clone" method lfg-ghost | EmbedNode must implement "decorate" method lfg-ghost | EmbedNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | EmbedNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | EmailNode must implement static "getType" method lfg-ghost | EmailNode must implement static "clone" method lfg-ghost | EmailNode must implement "decorate" method lfg-ghost | EmailNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | EmailNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | GalleryNode must implement static "getType" method lfg-ghost | GalleryNode must implement static "clone" method lfg-ghost | GalleryNode must implement "decorate" method lfg-ghost | GalleryNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | GalleryNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | EmailCtaNode must implement static "getType" method lfg-ghost | EmailCtaNode must implement static "clone" method lfg-ghost | EmailCtaNode must implement "decorate" method lfg-ghost | EmailCtaNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | EmailCtaNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | SignupNode must implement static "getType" method lfg-ghost | SignupNode must implement static "clone" method lfg-ghost | SignupNode must implement "decorate" method lfg-ghost | SignupNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | SignupNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | CollectionNode must implement static "getType" method lfg-ghost | CollectionNode must implement static "clone" method lfg-ghost | CollectionNode must implement "decorate" method lfg-ghost | CollectionNode should implement "importJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | CollectionNode should implement "exportJSON" method to ensure JSON and default HTML serialization works as expected lfg-ghost | [2023-11-12 21:53:13] INFO Adding one-off job to queue with current length = 0 called 'sendWebmentions' lfg-ghost | [2023-11-12 21:53:13] INFO "PUT /ghost/api/admin/posts/654ff84b2fecd90001949776/?formats=mobiledoc%2Clexical&save_revision=1&include=tags%2Cauthors%2Cauthors.roles%2Cemail%2Ctiers%2Cnewsletter%2Ccount.clicks%2Cpost_revisions%2Cpost_revisions.author" 200 133ms
sergiosgc commented 9 months ago

Something in the build system is broken. I build my docker instance similar to how you do it, and since 5.71.0, at least, I get two kg-default-nodes modules, one in ghost/node_modules/@tryghost and one in ghost/ghost/core/node_modules/@tryghost. Removing ghost/ghost/core/node_modules fixes the issue.

The duplicate module import creates two definitions of KoenigDecoratorNode. This causes the instanceof test in $isKoenigCard to fail, which causes exportTopLevelElementOrDecorator to fail on elements where $isKoenigCard should return true but returns false (Images and Cards, at least).

I know very little about Ghost's build system, but someone with more knowledge than me should be able to fix this fairly quickly.

The official images do not exhibit this problem. They may be building ghost differently.

ASAMedia commented 9 months ago

Wow great! Thanks @sergiosgc That will solve the issue till a fix is implemented.

Looks like kg-default-nodes is imported here "@tryghost/kg-default-nodes": "0.2.9", in the ghost/core/package.json and here const {DEFAULT_NODES} = require('@tryghost/kg-default-nodes'); in the ghost/core/core/server/lib/lexical.js

When I delete the line in the package.json and build, everything works as expected.

Maybe this could be a valid fix?

hsarji commented 9 months ago

This problem seems to impact Ghost(Pro) subscribers as well. I have a JavaScript code that uses the Admin API JavaScript Client that updates the content of one post. It used to work but now isn't working. I am seeing no errors. The post history shows that it is being updated but the content isn't changing. If I recall correctly, the source for the blog post used to show that it uses a markdown card. Now, I don't see a markdown class in the post's source.

I tried troubleshooting the code for several hours with the help of Bing AI to no avail. I agree, partially, with its observation:

The issue affects the mobiledoc format for posts, which is used by the Ghost API. The mobiledoc format is a JSON document that defines the structure and content of a post using cards, atoms, and markups. The problem is that the Ghost API is not creating the cards correctly, resulting in empty or corrupted posts.

I think the problem is that the API isn't creating the cards, so my post's history shows it is being updated but the Markdown card inside the post isn't changing.

github-actions[bot] commented 5 months ago

Our bot has automatically marked this issue as stale because there has not been any activity here in some time.

The issue will be closed soon if there are no further updates, however we ask that you do not post comments to keep the issue open if you are not actively working on a PR.

We keep the issue list minimal so we can keep focus on the most pressing issues. Closed issues can always be reopened if a new contributor is found. Thank you for understanding 🙂

daniellockyer commented 4 months ago

This should be fixed now!