[Resolved] Adding header <script></script> tag w/ async code is breaking the publishing process

I am trying to inject a script into my project header that currently works as a script ran after a button press. i injected it into the header with the following code:

<script>
console.log('were here')
    (async function() {
 async function fetchAssetData(slug) {
                const apiUrl = '[XANO BASE URL GOES HERE]/assets/getSingleAsset';
                const response = await fetch(`${apiUrl}?url=${slug}`);
                const data = await response.json();
                console.log(data)
                return data;
            }
    
            function setMetaTags(title, description, imageUrl, pageUrl, twitterUsername) {
                // Set meta tags as shown in the previous example
                const metaTags = [
                    { name: 'og:title', content: title },
                    { name: 'og:description', content: description },
                    { name: 'og:image', content: imageUrl },
                    { name: 'og:url', content: pageUrl },
                    { name: 'og:type', content: 'website' },
                    { name: 'twitter:card', content: 'summary_large_image' },
                    { name: 'twitter:title', content: title },
                    { name: 'twitter:description', content: description },
                    { name: 'twitter:image', content: imageUrl },
                    { name: 'twitter:site', content: twitterUsername },
                ];
    
                for (const tag of metaTags) {
                    const metaTag = document.createElement('meta');
                    const nameAttribute = tag.name.startsWith('twitter') ? 'name' : 'property';
                    metaTag.setAttribute(nameAttribute, tag.name);
                    metaTag.setAttribute('content', tag.content);
                    document.head.appendChild(metaTag);
                }
            }
    
          function removeTrailingSlash(str) {
            return str.endsWith('/') ? str.slice(0, -1) : str;
          }
    
            async function init() {
            console.log('here_starting the init function')
            console.log(window.location.href)
                const url = new URL(window.location.href);
                console.log(url)
                const slug = removeTrailingSlash(url.pathname).split('/').pop();
                console.log('slug : ' + slug)
    
                if (slug) {
                    const assetData = await fetchAssetData(slug);
                    const title = assetData.name || 'Fallback Title';
                    const description = assetData.shortDescription || 'Fallback Description';
                    const imageUrl = assetData.logo || 'Fallback Image URL';
                    const pageUrl = url.href;
                    const twitterUsername = '@your_twitter_username';
    
                    setMetaTags(title, description, imageUrl, pageUrl, twitterUsername);
                }
            }
    
            init();
    
})();



</script>

when inject this into the header, the build fails to complete. When run the same code as an action after a button press, the code executes without any issue.

IS there some reason this would cause the build to fail? Is async code not allowed in the header of the entire project?

eventually i always get this:

on the other hand when i publish wiht only a console.log() statement in the head code, there is no build failure. What could the issue here be when the code runs fine when ran on page?

I guess just start commenting out things till you find the syntax that is the problem. :man_shrugging: It would be interesting to understand what linting the build process does to custom code. And if there was any log to view to get some clue beyond “CODEBUILD_FAILED”. Not especially helpful thoughts :slightly_smiling_face: but I’ve got to start somewhere.

@lindsay_knowcode’s approach of stepping through it seems right, but a first thing to try: put a semicolon between your initial console.log and the start of your IIFE. When I ran prettier on your code, it interpreted the (async function() ... expression as being a second called set of arguments for the console.log. A semicolon would make the separation more explicit and maybe fix your challenge.

1 Like

hey @lindsay_knowcode and @raydeck

Thanks for the input guys, i updated my code to the following simple IIFE with a non-invoked function held within and it too broke the publishing. the IIFE by itself did not break the publishing process

<script>

console.log('were here');

(async function () {
  async function fetchAssetData(slug) {
  const apiUrl = 'https://[BASE URL]/assets/getSingleAsset';
  const response = await fetch(`${apiUrl}?url=${slug}`);
  const data = await response.json();
  console.log(data)
  return data;
}

})();
</script>

[update]
trying it minified

<script>
!async function(){async function n(n){let t=await fetch(`https://[baseURL]/assets/getSingleAsset?url=${n}`),a=await t.json();return console.log(a),a}}();
</script>

[updates update]
minified code, properly semiColon’d, still is breaking the publishing process.

@Quentin @Mael

are there any obvious reasons for my async function to be breaking the publishing process?

been waiting on this too :rofl:
Screen Shot 2023-04-28 at 9.18.18 AM

Maybe is due to the fact that your async function takes more time than what puppeteer is waiting when prerendering the page (I think it’s waiting for a custom event triggered by code injected by weweb).
Have you tried removing everything in the async function, just to see if it works?
Anyway if you build it locally you should see the error in the console.

1 Like

how do i build locally? i can’t publish to download the files.

why would this break the publishing process tho?

moreover, this code that is breaking (the internal async function) is never actually invoked in the snippet that breaks the publishing process. it’s basically dead code living on the page.

You can check this with the team, I just had a quick look at the sample project shared by Quentin.
It looks like prerendering is done by loading the page in an headless browser, waiting for code execution and saving the result to disk, so I think your code gets executed.
Again, it’s only a wild guess, I’m sure the weweb team has the right answer for this.

Don’t you have the source code of the app if you are on the right plan? (Is there a sample project with Vue.JS exported code for review? - #4 by Quentin)

i should BUT the code is only exposed after a successful publishing. are you saying that i can download the source code of the version that i’m currently working on without first clicking this button?

1 Like

Two other ideas:

  1. Make the IIFE sync. No really good reason for it to be async, even in the previous example (init() was fire and forget).
(function () {
  async function fetchAssetData(slug) {
    const apiUrl = 'https://[BASE URL]/assets/getSingleAsset';
    const response = await fetch(`${apiUrl}?url=${slug}`);
    const data = await response.json();
    console.log(data)
    return data;
  }

})();
  1. Another idea - could you wrap the code in a try-catch?
(async function () {
  try { 
    async function fetchAssetData(slug) {
      try { 
      const apiUrl = 'https://[BASE URL]/assets/getSingleAsset';
      const response = await fetch(`${apiUrl}?url=${slug}`);
      const data = await response.json();
      console.log(data)
      return data;
      } catch(e) {
        console.warn("Error in fetchAssetData", slug); 
      } 
    }
  } catch(e) {
     console.warn("Error in the IIFE", e);
  }
})();

nice try but no cigar

<script>
(async function () {
  try { 
    async function fetchAssetData(slug) {
      try { 
      const apiUrl = 'https://[BASE URL]/assets/getSingleAsset';
      const response = await fetch(`${apiUrl}?url=${slug}`);
      const data = await response.json();
      console.log(data)
      return data;
      } catch(e) {
        console.warn("Error in fetchAssetData", slug); 
      } 
    }
  } catch(e) {
     console.warn("Error in the IIFE", e);
  }
})();

</script>

this just failed a build but i appreciate the suggestion!

[update]
I was able to publish with this. i was originally thinking there was an issue with the async portion. seems to go deeper than that…

(function() {
 async function init() {
    console.log('asdf');
  };

  init();

})();

and this too

<script>
(function() {
 async function init() {
    console.log('peepee');
    return "poopoo"
  };

 console.log(init());

})();

</script>

something about the api call is causing the issue

1 Like

Final Code format that is not crashing the build process.

<script>
(function() {

function setMetaTags(title, description, imageUrl, pageUrl, twitterUsername) {
  // Set meta tags as shown in the previous example
  const metaTags = [{
      name: 'og:title',
      content: title
    },
    {
      name: 'og:description',
      content: description
    },
    {
      name: 'og:image',
      content: imageUrl
    },
    {
      name: 'og:url',
      content: pageUrl
    },
    {
      name: 'og:type',
      content: 'website'
    },
    {
      name: 'twitter:card',
      content: 'summary_large_image'
    },
    {
      name: 'twitter:title',
      content: title
    },
    {
      name: 'twitter:description',
      content: description
    },
    {
      name: 'twitter:image',
      content: imageUrl
    },
    {
      name: 'twitter:site',
      content: twitterUsername
    },
  ];

  for (const tag of metaTags) {
    const metaTag = document.createElement('meta');
    const nameAttribute = tag.name.startsWith('twitter') ? 'name' : 'property';
    metaTag.setAttribute(nameAttribute, tag.name);
    metaTag.setAttribute('content', tag.content);
    document.head.appendChild(metaTag);
  }
}

async function fetchAssetData(slug) {
  const apiUrl = 'https://[BASE URL]/assets/getSingleAsset?url=' + slug;
  const response = await fetch(apiUrl)
  const assetData = await response.json()
  console.log(response)
  const title = assetData.name || 'Fallback Title';
    const description = assetData.shortDescription || 'Fallback Description';
    const imageUrl = assetData.logo || 'Fallback Image URL';
    const pageUrl = "https:/www.weweb-preview.io/George-75";
    const twitterUsername = '@your_twitter_username';

    setMetaTags(title, description, imageUrl, pageUrl, twitterUsername);
}

console.log(fetchAssetData('George-75'))

})();

</script>

Sadly, this does not allow for a URL previewer/social preview to pick up the injected tags but this seems to be a bigger issue detailed here

1 Like