html drag/drop setDragImage doesnt set ghost image on first drag

Pre-loading the drag feedback images outside of the event listener seems to avoid the issue where the drag image does not appear on the first drag. There are a variety of ways to do this and the best one is highly dependent on exactly what you are trying to do. Following is an approach, where the url for the drag image is stored in a data attribute on the draggable element and the drag feedback image for each element is created and stored in an object beforehand.

Following are jQuery and vanilla JS examples:

const images = {};
const draggable = $('div');
draggable.each((i, elem) => {
  const src = $(elem).data('src');
  const img = new Image();
  img.src = src;
  images[src] = img;
});

draggable.on('dragstart', (event) => {
  const src = $(event.currentTarget).data('src');
  const img = images[src];
  const drag = event.originalEvent.dataTransfer;
  drag.setDragImage(img, 0, 0);
  drag.setData('text/uri-list', src);
});
div {
  border: 1px solid #000000;
  height: 100px;
  width: 100px;
  line-height: 100px;
  text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div draggable="true" data-src="https://via.placeholder.com/50/0000FF">drag me</div>
<div draggable="true" data-src="https://via.placeholder.com/50/FF0000">drag me</div>

const images = {};
const elems = document.querySelectorAll('div');
for (const elem of elems) {
  const source = elem.dataset.src;
  const image = new Image();
  image.src = source;
  images[source] = image;
  elem.addEventListener('dragstart', (event) => {
    const src = event.currentTarget.dataset.src;
    const img = images[src];
    event.dataTransfer.setDragImage(img, 0, 0);
    event.dataTransfer.setData('text/uri-list', src);
  });
}
div {
  border: 1px solid #000000;
  height: 100px;
  width: 100px;
  line-height: 100px;
  text-align: center;
}
<div draggable="true" data-src="https://via.placeholder.com/50/0000FF">drag me</div>
<div draggable="true" data-src="https://via.placeholder.com/50/FF0000">drag me</div>

So this is old, but I've just been struggling with this as well. I found that the issue was that I was creating the ghost image inside the dragstart event, which I see you're doing as well.

So the drag would have already started by the time you create your custom ghost image, meaning it wont be visible until you start a new drag.

So just try calling createDragImage outside of the dragstart. Worked for me.