Thanks, @Gleb, it seems that this is a different issue. I think that your issue was about the hidden children of a parent, while mine is about instances of component that are influencing the performance of processing of that component.
Without seeing what kind of processing you are doing in your code and how you are doing it, it’s hard to say why that could be an issue. The number of instances is unlikely to cause slowness (unless these are two completely identical components of course).
I will record a video.
This may not be relevant, but I saw this in the API which was new to me.
Perhaps your code is being affected by this if you’re modifying the main component?
Sorry I don’t have any good ideas to help diagnose/fix, other than perhaps wrapping the code in an async block so it doesn’t block the main thread…
Here is a video: Instances treated as children in Figma Plugin API - YouTube
If the video is not clear, I can record it with a voice-over tomorrow.
I was doing some tests and the root of the problem lays in iterating on the children of the component. For some reason, Figma takes into consideration the instances of the component as well. It hapends in this line:
if (selected.children.every(child => {
if (child.type == 'INSTANCE') {
if ( child.mainComponent.remote === false ) {
// console.log(child.mainComponent.id, ' is not remote ')
return true
}
}
})
)
Thanks for your help.
Ok that’s weird. I don’t think this is what’s causing the issue but I wouldn’t advice you to put a function inside of the condition. Better store the result as a constant and use it in the condition. Just a bit of a personal advice.
Also it would be nice to take a look at the whole code or maxToGenerate function (and whatever other functions it depends on).
Thanks @Gleb, here is the code for maxToGenerate():
function returnHowManyCanBeGenerated() {
let selected = figma.currentPage.selection[0].children
let allVariants = []
selected.forEach(instance => {
if ( instance.mainComponent.parent.type == 'COMPONENT_SET' ) {
allVariants.push(instance.mainComponent.parent.children.length);
}
})
let numberOfPossibleUniques = allVariants.reduce((a, b) => a * b, 1)
let numberOfSecondsToGenerate = Math.floor((numberOfPossibleUniques * 68) / 1000)
// console.log(`number of possible uniques: ` + numberOfPossibleUniques)
figma.ui.postMessage({
type: 'numberOfPossibleUniques',
number: numberOfPossibleUniques,
time: numberOfSecondsToGenerate
})
return numberOfPossibleUniques
}
function maxToGenerate() {
if (returnHowManyCanBeGenerated() > 10000) return 10000
else return returnHowManyCanBeGenerated()
}
I was doing tests without this function as well (with a simple “console.log” instead) the time was indeed a bit shorter, but still significantly longer than when processing a component without instances. I will try to start a new project with the simplest code possible to track the root of the problem.
@Gleb here is a video with simplified code:
Here is the code:
UI:
<body style="background: #E0F8E0;">
<p style="color: green;">The right component was selected and processed. </p>
</body>
<script>
onmessage = (event) => {
if (event.data.pluginMessage.scene == 'selectComponent') {
document.querySelector('body').style.background = "white"
document.querySelector('body').innerHTML =
`
<h3>Select Component</h3>
`
} else if (document.getElementById('uniquenumber')) {
}
}
</script>
Code:
// @ts-nocheck
returnCurrentSelection()
figma.on("selectionchange", () => {
returnCurrentSelection()
})
function returnCurrentSelection() {
let selected = figma.currentPage.selection[0]
figma.showUI(__html__, {
width: 256,
height: 400,
title: "Component problem"
});
if (typeof selected !== "undefined"
&& selected.type === 'COMPONENT'
&& selected.children.every(child => {
if (child.type == 'INSTANCE') {
if ( child.mainComponent.remote === false ) {
return true
}
}
})
) {
console.log('hello')
} else {
figma.ui.postMessage({
scene: 'selectComponent'
})
}
}
I am not a seasoned developer, but it seems to me that the issue is that the instances are treated as children (which in my humble understanding should not be the case?). I triple-checked the documentation to make sure about the distinction of children (something that is inside the nodes tree) and instance (a node that lives on a separate tree).
When I console.log the parent of instances it is the Page node. The same goes when I console log the children of the component. They are just the layers that are in the component itself.
@Gleb, about putting the result of the condition under the constant:
I am not very good with the syntax yet, so I am just trying to “make it work” ;). I was trying to do what you advised, but it doesn’t work:
Just not sure how to do it, so I am leaving it as it was.
I meant this:
if (typeof selected !== "undefined"
&& selected.type === 'COMPONENT') {
// save result to constant
const isRemote = selected.children.every(child => {
if (child.type == 'INSTANCE') {
if ( child.mainComponent.remote === false ) {
return true
}
}
})
// check if constant is true
if (isRemote) {
console.log('hello')
}
}
But again it shouldn’t make much of a difference.
I tested your code in my file: https://figma.fun/btrmNr, it works perfectly fine and fast. There is zero slowness. So perhaps something is wrong with your file?
Thanks, @Gleb, I really appreciate the help and effort that you are putting into it!
I think this issue only shows up when you have complex components with a lot of elements. Based on your file, I added more complex components and was able to replicate the issue: Figma
Hello @Paulus Did you find a solution for the selection problem? I have the same situation, trying to find all TextNodes in the user’s selection, when instances involved with a lot of copies, then the performance is degraded.
I would appreciate a workaround in how to approach this issue in order to traverse as quick as possible the user’s selection in searching of TextNodes.
Thank you in advance!
Yes I did a brief test and couldn’t see any great difference. I’ll try again.
One note is that I’m looking for visible text nodes in the current selection, which is more tricky, because I cannot apply the filterAllWithCriteria to the selection object.
Any ideas?
const arr = [],
selection = figma.currentPage.selection;
selection.forEach(node => {
if (node.type === 'TEXT' && node.visible) {
arr.push(node)
}
else if (node.children) {
arr.push(...node.findAllWithCriteria({types: ['TEXT']}).filter(v => v.visible))
}
});
console.log('arr', arr);
Hi @Gleb, yes, we have this in the code, there is an improvement, but when selecting components with a lot of instances, the performance is worse than when you select an isolated instance or frame.
Is there any way to avoid this delay, should the API be slower when selecting components? Why is this behavior happening?
Thanks.
@Pablo_Sanchez AFAIK there is no fix to this. This is IMHO a Figma bug, I don’t see any logical explanation for why this happens. Not sure also if your case is what I described. A bug that I see is that while using node.children
on a Main Component Figma processes also it’s instances (which are not children).
Thank you @Paulus at least I know now that there is no room for improvement on our side. Let’s wait for Figma to resolve this internal performance issue.
Thanks to all!