How to create text without need of doing it in async function

Hi, I am trying to create text const with const rowText = figma.createText() and then specifying font with rowText.fontName = {family: "Open Sans", style: "Regular"}.

I am getting this Error:

I tried fixing it according to error instructions, but I am not using it in a async function. Is there a way to bypass it somehow?

Whole code:


figma.showUI(__html__, {height: 250, title: "Table Generator"})

// Calls to "parent.postMessage" from within the HTML page will trigger this
// callback. The callback will be passed the "pluginMessage" property of the
// posted message.

figma.ui.onmessage = msg => {

  // One way of distinguishing between different types of messages sent from
  // your HTML page is to use an object with a "type" property like this.

  if (msg.type === 'actionGenerate') {
    
    const {countRows, countColumns} = msg.formDataObj

    // Generate main (parent) frame with custom name and properties for proper auto-layouting
    const parentFrame = figma.createFrame()
    parentFrame.name = 'Table ' + countRows + 'x' + countColumns
    parentFrame.layoutMode = "HORIZONTAL"
    parentFrame.paddingTop = 25
    parentFrame.paddingRight = 16
    parentFrame.paddingBottom = 25
    parentFrame.paddingLeft = 16
    parentFrame.primaryAxisSizingMode = "AUTO"
    parentFrame.counterAxisSizingMode = "AUTO"
    
    // Generate lines according to 'countRow', name and resize them
    for (let i = 0; i < countColumns; i++) {

      const column = figma.createFrame()
          column.name = 'Column ' + (i+1)
          column.layoutMode = "VERTICAL"
          column.primaryAxisSizingMode = "AUTO"
          column.counterAxisSizingMode = "AUTO"
      
      parentFrame.appendChild(column)

      for (let j = 0; j < countRows; j++) {

        const row = figma.createFrame()
          row.name = 'Row ' + (j+1)
          row.layoutMode = "VERTICAL"
          row.primaryAxisSizingMode = "AUTO"
          row.counterAxisSizingMode = "AUTO"

        column.appendChild(row)

          // Generate lines
          const rowLine = figma.createLine()
            rowLine.name = 'Line ' + (j+1)
            rowLine.resize((908/countColumns),0)
      
            // Change color of lines
            const colorR = 224 / 255,
                  colorG = 224 / 255,
                  colorB = 224 / 255

            rowLine.strokes = [{type: "SOLID", color: {r: colorR, g: colorG, b: colorB}}]        

            row.appendChild(rowLine)
          
          const rowText = figma.createText()
            let description = "Edit me"
            figma.loadFontAsync({ family: "Open Sans", style: "Regular" })
            rowText.fontName = {family: "Open Sans", style: "Regular"}
            rowText.name = 'Item ' + (j+1)
            rowText.characters = description

            row.appendChild(rowText)

        // Select generated table and zoomm-in
        const selectFrame : FrameNode[] = []
        selectFrame.push(parentFrame)
        figma.currentPage.selection = selectFrame
        figma.viewport.scrollAndZoomIntoView(selectFrame)
      }
    }

    figma.closePlugin('Table generated successfully :)')
  } else if (msg.type === 'actionExit') {
    
    figma.closePlugin();
  }

};

If you don’t want to create an async function, you can create a new Promise for figma.loadFontAsync(font).

I am not sure how do you mean that or how to use it in this case, could you elaborate, please?

Create a Promise to load the font, wait for it to resolve, and then assign the loaded font and characters to the TextNode.

const rowText = figma.createText(),
	font = {family: "Open Sans", style: "Regular"};
const loadFont = new Promise(resolve => {
	figma.loadFontAsync(font);
	resolve()
});
loadFont.then(() => {
	rowText.fontName = font;
	rowText.characters = "Edit me";
});

What argument resolve() requires?

In this example, a value for resolve() is not required.

It wants an argument, but I have no idea what kind of
image

Is your code not compiling due to this syntax highlighting? Or are you just worried that something is highlighted? Try passing any value: undefined, boolean, string, etc.

But I repeat again:

It should say that when you hover

It is not compiling and error message looks like this:

After I give it any kind of value it compiles, but does not work properly when ran as plugin in Figma.

This is console output in Figma after running the plugin:

Thank you.

Quoting from the documentation:

However, note that loadFontAsync returns a Promise. Even a Promise resolves immediately, it still needs to round-trip to the JavaScript event loop.
loadFontAsync | Plugin API

Thus, you can try the following code:

let font = {family: "Open Sans", style: "Regular"};
figma.loadFontAsync(font).then(() => {
	let rowText = figma.createText();
	rowText.fontName = font;
	rowText.characters = "Edit me";
});

Text is still not showing up, only empty text nodes. Console output looks like this even after 10min of waiting:

There are still font loads in progress. Please ensure closePlugin is not called until after the font loading has resolved.

Do you close the plugin and see this message only after 10 minutes of waiting or is it displayed immediately after your plugin runs?

If this message is shown right after running the plugin, it means the promise (async function) didn’t finish yet and you already closed the plugin. This happens because your decision to use a promise instead of an async function desynchronized the threads. If you used an async function, you could just await for the fonts to load and continue doing the plugin things and close it like normal. But since you are now not waiting for the fonts to load, your plugin probably closes before the promise returns. Fonts don’t load and the text doesn’t get set so you get empty text boxes. Make sure you understand async functions well: Async functions - making promises friendly. Promises are just a different type of async functions so you won’t be able to magically run away from using async functions by using a promise.

It is displayed right away. I commented out figma.closePlugin() and text loaded, thanks for that :slight_smile: But what can I do for plugin to close automatically right after font is loaded?

You should only call figma.closePlugin() after the asynchronous code has completed. Therefore, you need to put this in asynchronous code and add a condition for the plugin to close.

You need to synchronize the code. I find it pretty simple and intuitive to do it by using an async function. But if you don’t want to use one, you can synchronize promises as well, but it’s less intuitive and requires more code.

I tried it with async function, but did not work for me, that is why I went the other way. Should’ve spent more time trying to deal with async :confused:

Here is what roughly your code should look like on a global level:

async function main() {
  // some regular code
  let a = 5
  // some async code
  await loadFont()
  // close plugin at the end
}

main()
1 Like