Comment Tailwind CSS détecte la dépendance circulaire.
Dans cet article, nous analysons l'erreur générée dans substitutAtApply. Cette erreur concerne la dépendance circulaire détectée.
walk(rule.nodes, (child) => { if (child !== node) return throw new Error( `You cannot \`@apply\` the \`${candidate}\` utility here because it creates a circular dependency.`, ) })
Ceci est un aperçu de haut niveau du code autour de cette erreur.
marcher — fonction récursive :
Commençons par la marche :
export function walk( ast: AstNode[], visit: ( node: AstNode, utils: { parent: AstNode | null replaceWith(newNode: AstNode | AstNode[]): void context: Record<string, string> }, ) => void | WalkAction, parent: AstNode | null = null, context: Record<string, string> = {}, ) { for (let i = 0; i < ast.length; i++) { let node = ast[i] // We want context nodes to be transparent in walks. This means that // whenever we encounter one, we immediately walk through its children and // furthermore we also don't update the parent. if (node.kind === 'context') { walk(node.nodes, visit, parent, { …context, …node.context }) continue } let status = visit(node, { parent, replaceWith(newNode) { ast.splice(i, 1, …(Array.isArray(newNode) ? newNode : [newNode])) // We want to visit the newly replaced node(s), which start at the // current index (i). By decrementing the index here, the next loop // will process this position (containing the replaced node) again. i - }, context, }) ?? WalkAction.Continue // Stop the walk entirely if (status === WalkAction.Stop) return // Skip visiting the children of this node if (status === WalkAction.Skip) continue if (node.kind === 'rule') { walk(node.nodes, visit, node, context) } } }
walk est une fonction récursive située dans ast.ts.
Il s'appelle récursivement lorsque node.kind === 'context' ou lorsque node.kind === 'rule', la condition de rupture est basée sur le statut
// Stop the walk entirely if (status === WalkAction.Stop) return // Skip visiting the children of this node if (status === WalkAction.Skip) continue
Maintenant, faisons un zoom arrière et étudions le code à proximité de la fonction walk dans apply.ts
// Verify that we don't have any circular dependencies by verifying that // the current node does not appear in the new nodes. walk(newNodes, (child) => { if (child !== node) return // At this point we already know that we have a circular dependency. // // Figure out which candidate caused the circular dependency. This will // help to create a useful error message for the end user. for (let candidate of candidates) { let selector = `.${escape(candidate)}` for (let rule of candidateAst) { if (rule.kind !== 'rule') continue if (rule.selector !== selector) continue walk(rule.nodes, (child) => { if (child !== node) return throw new Error( `You cannot \`@apply\` the \`${candidate}\` utility here because it creates a circular dependency.`, ) }) } } })
Les auteurs de TailwindCSS ont ajouté des commentaires explicatifs dans la base de code lorsque cela est nécessaire ou il est logique de fournir un contexte supplémentaire
avec commentaires.
À propos de nous :
Chez Think Throo, nous avons pour mission d'enseigner les concepts architecturaux avancés de base de code utilisés dans les projets open source.
10x vos compétences en codage en pratiquant des concepts architecturaux avancés dans Next.js/React, apprenez les meilleures pratiques et construisez des projets de niveau production.
Nous sommes open source — https://github.com/thinkthroo/thinkthroo (Donnez-nous une étoile !)
Nous fournissons également des services de développement Web et de rédaction technique. Contactez-nous à hello@thinkthroo.com pour en savoir plus !
Références :
https://github.com/tailwindlabs/tailwindcss/blob/next/packages/tailwindcss/src/ast.ts#L70
https://github.com/tailwindlabs/tailwindcss/blob/c01b8254e822d4f328674357347ca0532f1283a0/packages/tailwindcss/src/apply.ts
https://stackoverflow.com/questions/71669246/need-help-using-apply-directive-in-tailwind-css
https://github.com/tailwindlabs/tailwindcss/issues/2807
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undress AI Tool
Images de déshabillage gratuites

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

La portée de JavaScript détermine la portée d'accessibilité des variables, qui sont divisées en étendue globale, fonction et au niveau du bloc; Le contexte détermine la direction de cela et dépend de la méthode d'appel de fonction. 1. Les étendues incluent la portée globale (accessible n'importe où), la portée de la fonction (valide uniquement dans la fonction) et la portée au niveau du bloc (LET et const sont valides dans {}). 2. Le contexte d'exécution contient l'objet variable, la chaîne de portée et les valeurs de cela. Cela pointe vers global ou non défini dans la fonction ordinaire, l'appel de méthode pointe vers l'objet d'appel, le constructeur pointe vers le nouvel objet, et peut également être explicitement spécifié par appel / application / liaison. 3. La fermeture fait référence aux fonctions accédant et en se souvenant des variables de portée externes. Ils sont souvent utilisés pour l'encapsulation et le cache, mais peuvent provoquer

Il existe deux méthodes de base pour obtenir la valeur du bouton radio sélectionné. 1. Utilisez QuerySelector pour obtenir directement l'élément sélectionné, et utilisez l'entrée [name = "Votre nom-radio"]: Sélecteur vérifié pour obtenir l'élément sélectionné et lire son attribut de valeur. Il convient aux navigateurs modernes et a un code concis; 2. Utilisez Document.PetelementsByName pour traverser et trouver la première radio vérifiée via la boucle Nodelist et obtenir sa valeur, qui convient aux scénarios compatibles avec les anciens navigateurs ou nécessitent un contrôle manuel du processus; De plus, vous devez faire attention à l'orthographe de l'attribut de nom, à la gestion des situations non sélectionnées et à un chargement dynamique du contenu

Il existe une différence essentielle entre les travailleurs Web de JavaScript et Javathreads dans un traitement simultané. 1. JavaScript adopte un modèle unique. WebWorkers est un fil indépendant fourni par le navigateur. Il convient pour effectuer des tâches longues qui ne bloquent pas l'interface utilisateur, mais ne peuvent pas utiliser le DOM; 2. Java prend en charge le multithreading réel à partir du niveau de la langue, créé via la classe de threads, adapté à un traitement simultanée complexe et côté serveur; 3. Les travailleurs Web utilisent PostMessage () pour communiquer avec le fil principal, qui est hautement sécurisé et isolé; Les threads Java peuvent partager la mémoire, de sorte que les problèmes de synchronisation doivent être prêts à prêter attention; 4. Les travailleurs Web sont plus adaptés à l'informatique parallèle frontale, comme le traitement d'image, et

CompositionAPI dans Vue3 convient plus à la logique complexe et à la dérivation de type, et OptionsAPI convient aux scénarios et débutants simples; 1. OptionsAPI organise le code en fonction d'options telles que les données et les méthodes, et a une structure claire mais les composants complexes sont fragmentés; 2. CompositionAPI utilise la configuration pour concentrer la logique liée, ce qui est propice à la maintenance et à la réutilisation; 3. CompositionAPI réalise la réutilisation logique sans conflit et paramétrisable par le biais de fonctions composables, ce qui est mieux que le mixin; 4. CompositionAPI a une meilleure prise en charge de la dérivation de type dactylographiée et de type plus précise; 5. Il n'y a pas de différence significative dans le volume de performances et d'emballage des deux; 6.

Le débogage des applications JavaScript complexes nécessite des outils d'utilisation systématiques. 1. Définissez des points d'arrêt et des points d'arrêt conditionnels pour intercepter les processus suspects, tels qu'avant l'entrée de la fonction, la boucle, le rappel asynchrone et le filtre en fonction des conditions; 2. Activer la fonction BlackBoxing pour bloquer les interférences de bibliothèque tierce; 3. Utiliser les déclarations du débogueur pour contrôler l'entrée de débogage en fonction du jugement environnemental; 4. Tracez le lien d'appel via CallStack, analysez le chemin d'exécution et l'état de la variable, localisez ainsi efficacement la cause profonde du problème.

La coulée de type est le comportement de la conversion automatique d'un type de valeur en un autre type en JavaScript. Les scénarios courants incluent: 1. Lorsque vous utilisez des opérateurs, si un côté est une chaîne, l'autre côté sera également converti en une chaîne, comme '5' 5. Le résultat est "55"; 2. Dans le contexte booléen, les valeurs non cooliennes seront implicitement converties en types booléens, tels que des chaînes vides, 0, nuls, non définies, etc., qui sont considérées comme fausses; 3. Null participe aux opérations numériques et sera convertie en 0, et non défini sera converti en NAN; 4. Les problèmes causés par la conversion implicite peuvent être évitées grâce à des fonctions de conversion explicites telles que Number (), String () et Boolean (). La maîtrise de ces règles aide

Les dates de format dans JavaScript peuvent être implémentées via des méthodes natives ou des bibliothèques tierces. 1. Utilisez des coutures d'objets à date native: Obtenez la partie de date via Gettillyar, Getmonth, GetDate et d'autres méthodes, et les épisser manuellement dans des formats Yyyy-MM et d'autres, qui conviennent aux besoins légers et ne reposent pas sur des bibliothèques tierces; 2. Utilisez la méthode TolocaleDateString: vous pouvez sortir tel que le format mm / dd / yyyy en fonction des habitudes locales, en charge multilingue, mais le format peut être incohérent en raison de différents environnements; 3. Utilisez des bibliothèques tierces telles que Day.js ou Date-FNS: Fournit une syntaxe concise et des fonctions riches, adaptées aux opérations fréquentes ou lorsque l'extensibilité est requise, comme DayJS ()

Utilisez Document.CreateElement () pour créer de nouveaux éléments; 2. Personnaliser les éléments via TextContent, ClassList, SetAttribute et d'autres méthodes; 3. Utilisez des méthodes APPEDCHILD () ou plus flexibles APPEND () pour ajouter des éléments au DOM; 4. Utiliser éventuellement INSERTBEFORE (), avant () et d'autres méthodes pour contrôler la position d'insertion; Le processus complet consiste à créer → Personnaliser → Ajouter, et vous pouvez mettre à jour dynamiquement le contenu de la page.
