Shortcode with javascript breaking with Hugo v0.134.1+extended

I have a shortcode that includes a tag and it works with hugo server, but building the site returns this:

ERROR failed to process "/tags/artificial-intelligence/index.html": "/var/folders/hd/20k6ynwn6f181sz7l792lvzw0000gn/T/hugo-transform-error2126366384:967:52": unexpected … in expression on line 967 and column 52
    5:     let container = …

In v0.133 the shortcode still works. Maybe I should be escaping the code better to avoid that ... character?

This is the full bookmark.js code:

<!-- bookmarks.html -->
<div class="col-12">
    <h3>{{ T "external_links_for" }} {{ .Page.Title }}</h3>
    <div id="bookmarks-container" class="row"></div>
</div>
<script type="text/javascript">
(function() {
    let tag = '{{ .Get "tag" | safeJS }}'; 
    let displayMode = '{{ .Get "display" | default "grid" | safeJS }}';
    let container = document.getElementById("bookmarks-container");
    function createHtmlForGridItem(item) {
        // Create the bookmark container div
        let bookmarkContainer = document.createElement('div');
        bookmarkContainer.classList.add('col-6');

        // Create the main 'row' div
        let rowDiv = document.createElement('div');
        rowDiv.classList.add('row');

        // Create the image column
        let imageColDiv = document.createElement('div');
        imageColDiv.classList.add('col-sm-2', 'col-3');
        let imageAnchor = document.createElement('a');
        imageAnchor.href = item.url;
        imageAnchor.target = '_blank';
        imageAnchor.rel = 'nofollow';
        let image = document.createElement('img');
        image.src = item.imageURL || '/bookmarks/default-image.png';
        image.classList.add('img', 'w-100', 'border-radius-lg', 'shadow-lg');
        image.alt = 'image';
        imageAnchor.appendChild(image);
        imageColDiv.appendChild(imageAnchor);

        // Create the content column
        let contentColDiv = document.createElement('div');
        contentColDiv.classList.add('col-sm-10', 'col-9', 'my-auto');
        let title = document.createElement('h5');
        let titleAnchor = document.createElement('a');
        titleAnchor.href = item.url;
        titleAnchor.target = '_blank';
        titleAnchor.rel = 'nofollow';
        titleAnchor.classList.add('text-dark', 'font-weight-bold');
        titleAnchor.textContent = item.title;
        title.appendChild(titleAnchor);
        let excerpt = document.createElement('p');
        excerpt.classList.add('text-sm');
        excerpt.textContent = item.excerpt;
        contentColDiv.appendChild(title);
        contentColDiv.appendChild(excerpt);

        // Create the button container
        let buttonContainer = document.createElement('div');
        buttonContainer.classList.add('buttons', 'justify-content-center');
        let buttonAnchor = document.createElement('a');
        buttonAnchor.href = item.url;
        buttonAnchor.target = '_blank';
        buttonAnchor.rel = 'nofollow';
        buttonAnchor.classList.add('btn', 'btn-sm', 'btn-rounded', 'btn-dark', 'btn-icon-only', 'pt-1', 'mb-0');
        let icon = document.createElement('i');
        icon.classList.add('fas', 'fa-external-link-alt', 'text-xs');
        icon.setAttribute('aria-hidden', 'true');
        buttonAnchor.appendChild(icon);
        buttonContainer.appendChild(buttonAnchor);

        // Append the button container after the excerpt
        contentColDiv.appendChild(buttonContainer);

        // Append columns to the row
        rowDiv.appendChild(imageColDiv);
        rowDiv.appendChild(contentColDiv);

        // Create and append the horizontal rule
        let hr = document.createElement('hr');
        hr.classList.add('horizontal', 'dark', 'my-4');
        rowDiv.appendChild(hr);

        // Append the row to the bookmark container
        bookmarkContainer.appendChild(rowDiv);

        return bookmarkContainer;
    }

    function createHtmlForListItem(item) {
        // Create a container for the list item
        let listItemContainer = document.createElement('div');
        listItemContainer.classList.add('col-12'); // Full width of the container

        let listItem = document.createElement('div');
        listItem.classList.add('list-group-item');

        let titleAnchor = document.createElement('a');
        titleAnchor.href = item.url;
        titleAnchor.target = '_blank';
        titleAnchor.rel = 'nofollow';
        titleAnchor.classList.add('text-dark', 'font-weight-bold');
        titleAnchor.textContent = item.title;

        let icon = document.createElement('i');
        icon.classList.add('fas', 'fa-external-link-alt', 'text-xs', 'ms-1');
        titleAnchor.appendChild(icon);

        // Uncomment if you want to include the excerpt
        // let excerpt = document.createElement('p');
        // excerpt.classList.add('text-sm');
        // excerpt.textContent = item.excerpt;

        listItem.appendChild(titleAnchor);
        // listItem.appendChild(excerpt);

        listItemContainer.appendChild(listItem);

        return listItemContainer;
    }

    fetch('/bookmarks/shioridb.json')
    .then(response => response.json())
    .then(data => {
        let filteredBookmarks = data.filter(item => 
            item.tags && item.tags.some(t => t.name === tag))
            .sort((a, b) => a.title.toLowerCase().localeCompare(b.title.toLowerCase())); // Sorting alphabetically by title
    
        if (filteredBookmarks.length === 0) {
            container.innerHTML = `<p>No bookmarks found with the tag "${tag}".</p>`;
            return;
        }

        let bookmarksToShow = displayMode === "list" ? filteredBookmarks.slice(0, 15) : filteredBookmarks;
        
        bookmarksToShow.forEach(bookmark => {
            let bookmarkHtml;
            if (displayMode === "list") {
                bookmarkHtml = createHtmlForListItem(bookmark);
            } else {
                bookmarkHtml = createHtmlForGridItem(bookmark);
            }
            container.appendChild(bookmarkHtml);
        });

        // Add the "More" button if in list mode and there are more than 15 items
        if (displayMode === "list" && filteredBookmarks.length > 15) {
            let tags = filteredBookmarks
                .reduce((acc, curr) => acc.concat(curr.tags.map(tag => tag.name)), [])
                .filter((value, index, self) => self.indexOf(value) === index) // Remove duplicates
                .join(',');
            let buttonContainer = document.createElement('div');
            buttonContainer.classList.add('text-center', 'mt-3');
            
            let moreButton = document.createElement('a');
            moreButton.href = `/bookmarks/?t=${encodeURIComponent(tag)}`;
            moreButton.textContent = 'More Bookmarks';
            moreButton.classList.add('btn', 'btn-primary');
            
            buttonContainer.appendChild(moreButton);
            container.appendChild(buttonContainer);
        }
    })
    .catch(error => {
        container.innerHTML = `<p>Error loading bookmarks: ${error.message}</p>`;
    });    
})();
</script>

It feels like you don’t give us the whole story :slight_smile:

  • how does /tags/artificial-intelligence/index.html looks like?
  • what is “/var/folders/hd/20k6ynwn6f181sz7l792lvzw0000gn/T/hugo-transform-error2126366384:967:52” all about?

Did you delete the resources folder? Just in case, I wouldn’t expect that to fix things…

I’m afraid tag pages aren’t very exciting :slightly_smiling_face:

All I have is some frontmatter and I call the shortcode with the tag parameter, like this.

{{< bookmarks tag="ai" display="list" >}}

The /var/folders/... aren’t mine, I guess they are hugo temporary directories.

Gave it a go at deleting the resources but got the same result.

Looking at it again, it complains explicitly about the three dots… it looks to me as if your javascript is in the summary or excerpt of an article, basically like this:

some text 
<script type="">
some code ...

Without the entire code, an error is created. To avoid that issue, I would check inside the shortcode if we are in a preview/summary and then return nothing.

A better attempt to fix this would be to move the Javascript out of the shortcode into it’s own file and load that when needed. If the template adds variables to the JS you can add those variables into data-variablename="value" attributes on the HTML code that is printed and then read from within the JS.

Just figured out that this is related to the minify output setting. Once turned off the site builds as expected. Not sure if there were any changes to that part of the code from 0.133 to 0.134.

Page is live and working: Artificial Intelligence

Update: Also, you were right about some part of the script making it into the summary. Just noticed this:

<h3>Bookmarks for GregoryAI for Multiple Sclerosis</h3>
    <div id="bookmarks-container" class="row"></div>
</div>
<script type="text/javascript">
(function() {
    let tag = 'gregory-ms'; 
    let displayMode = 'grid';
    let …</script></div></div></p>

The best fix is to only render the summary in tag pages for actual content and not other sections that may have a tag.