Is het je opgevallen dat de CSS-eigenschappen op het tabblad Stijlen van Chrome DevTools er de laatste tijd wat gepolijster uitzien? Deze updates, uitgerold tussen Chrome 121 en 128, zijn het resultaat van een aanzienlijke verbetering in de manier waarop we CSS-waarden parseren en presenteren. In dit artikel leiden we u door de technische details van deze transformatie, waarbij we overgaan van een systeem voor het matchen van reguliere expressies naar een robuustere parser.
Laten we de huidige DevTools vergelijken met de vorige versie:
Een behoorlijk verschil, toch? Hier volgt een overzicht van de belangrijkste verbeteringen:
-
color-mix
. Een handig voorbeeld dat de twee kleurargumenten binnen decolor-mix
visueel weergeeft. -
pink
. Een klikbaar kleurvoorbeeld voor de genoemde kleurpink
. Klik erop om een kleurkiezer te openen voor eenvoudige aanpassingen. -
var(--undefined, [fallback value])
. Verbeterde verwerking van ongedefinieerde variabelen, waarbij de ongedefinieerde variabele grijs wordt weergegeven en de actieve fallback-waarde (in dit geval een HSL-kleur) wordt weergegeven met een klikbaar kleurvoorbeeld. -
hsl(…)
: Nog een klikbaar kleurvoorbeeld voor dehsl
kleurfunctie, die snelle toegang tot de kleurkiezer biedt. -
177deg
: een klikbare hoekklok waarmee u de hoekwaarde interactief kunt slepen en wijzigen. -
var(--saturation, …)
: Een klikbare link naar de aangepaste eigenschapsdefinitie, waardoor u gemakkelijk naar de relevante declaratie kunt springen.
Het verschil is opvallend. Om dit te bereiken moesten we DevTools leren de CSS-eigenschapswaarden veel beter te begrijpen dan voorheen.
Waren deze previews niet al beschikbaar?
Hoewel deze voorbeeldpictogrammen misschien bekend voorkomen, worden ze niet altijd consistent weergegeven, vooral niet in complexe CSS-syntaxis zoals in het bovenstaande voorbeeld. Zelfs als ze wel werkten, waren er vaak aanzienlijke inspanningen nodig om ze correct te laten functioneren.
De reden daarvoor is dat het systeem voor het analyseren van waarden sinds de eerste dagen van DevTools organisch is gegroeid. Het is echter niet in staat gebleken gelijke tred te houden met de recente verbazingwekkende nieuwe functies die we van CSS krijgen, en de daarmee gepaard gaande toename in taalcomplexiteit. Het systeem vereiste een volledig nieuw ontwerp om gelijke tred te houden met de evolutie en dat is precies wat we hebben gedaan!
Hoe CSS-eigenschapswaarden worden verwerkt
In DevTools is het proces van het weergeven en decoreren van eigendomsdeclaraties op het tabblad Stijlen opgesplitst in twee afzonderlijke fasen:
- Structurele analyse. In deze eerste fase wordt de eigendomsverklaring ontleed om de onderliggende componenten en hun relaties te identificeren. In de
border: 1px solid red
herkent het bijvoorbeeld1px
als een lengte,solid
als een string enred
als een kleur. - Weergave. Voortbouwend op de structurele analyse transformeert de weergavefase deze componenten in een HTML-representatie. Dit verrijkt de weergegeven eigendomstekst met interactieve elementen en visuele aanwijzingen. De kleurwaarde
red
wordt bijvoorbeeld weergegeven met een klikbaar kleurpictogram dat, wanneer erop wordt geklikt, een kleurkiezer onthult voor eenvoudige aanpassing.
Reguliere expressies
Voorheen vertrouwden we op reguliere expressies (regexes) om de eigenschapswaarden voor structurele analyse te ontleden. We hebben een lijst met regexes bijgehouden die overeenkomen met de stukjes eigenschapswaarde die we als decoratie beschouwden. Er waren bijvoorbeeld expressies die overeenkwamen met CSS-kleuren, lengtes, hoeken, ingewikkelder subexpressies zoals var
-functieaanroepen, enzovoort. We hebben de tekst van links naar rechts gescand om waardeanalyses uit te voeren, waarbij we voortdurend op zoek waren naar de eerste uitdrukking uit de lijst die overeenkomt met het volgende stuk tekst.
Hoewel dit meestal prima werkte, bleef het aantal gevallen waarin dit niet gebeurde groeien. Door de jaren heen hebben we een groot aantal bugrapporten ontvangen waarin de matching niet helemaal klopte. Toen we deze oplosten – sommige eenvoudig, andere behoorlijk uitgebreid – moesten we onze aanpak heroverwegen om onze technische schulden op afstand te houden. Laten we eens een paar van de problemen bekijken!
Overeenkomende color-mix()
De regex die we gebruikten voor de color-mix()
functie was de volgende:
/color-mix\(.*,\s*(?<firstColor>.+)\s*,\s*(?<secondColor>.+)\s*\)/g
Wat overeenkomt met de syntaxis:
color-mix(<color-interpolation-method>, [<color> && <percentage [0,100]>?]#{2})
Probeer het volgende voorbeeld uit te voeren om de overeenkomsten te visualiseren.
const re = /color-mix\(.*,\s*(?<firstColor>.+)\s*,\s*(?<secondColor>.+)\s*\)/g;
// it works - simpler example
const simpler = re.exec('color-mix(in srgb, pink, hsl(127deg 100% 50%))');
console.table(simpler.groups);
re.exec('');
// it doesn't work - complex example
const complex = re.exec('color-mix(in srgb, pink, var(--undefined, hsl(127deg var(--saturation, 100%) 50%)))');
console.table(complex.groups);
Het eenvoudigere voorbeeld werkt prima. In het complexere voorbeeld is de <firstColor>
-match echter hsl(177deg var(--saturation
and <secondColor>
match is 100%) 50%))
, wat volkomen zinloos is.
We wisten dat dit een probleem was. CSS als formele taal is tenslotte niet regulier , dus hebben we al een speciale behandeling toegevoegd om met ingewikkeldere functieargumenten om te gaan, zoals var
-functies. Zoals je in de eerste schermafbeelding kunt zien, werkte dat echter nog steeds niet in alle gevallen.
Bijpassende tan()
Een van de meest hilarische gerapporteerde bugs betrof de trigonometrische tan()
functie. De regex die we gebruikten voor het matchen van kleuren bevatte een subexpressie \b[a-zA-Z]+\b(?!-)
voor het matchen van benoemde kleuren, zoals het red
trefwoord. Vervolgens hebben we gecontroleerd of het overeenkomende deel daadwerkelijk een benoemde kleur is, en raad eens: tan
is ook een benoemde kleur! We hebben dus tan()
-expressies ten onrechte geïnterpreteerd als kleuren.
Overeenkomende var()
Laten we een ander voorbeeld bekijken, var()
functies met een fallback die andere var()
referenties bevat: var(--non-existent, var(--margin-vertical))
.
Onze regex voor var()
zou graag overeenkomen met deze waarde. Alleen stopt het matchen bij het eerste haakje sluiten. De bovenstaande tekst wordt dus gematcht als var(--non-existent, var(--margin-vertical)
. Dit is een beperking uit het leerboek van het matchen van reguliere expressies. Talen die matchende haakjes vereisen, zijn fundamenteel niet regulier.
Overgang naar een CSS-parser
Wanneer tekstanalyse met reguliere expressies niet meer werkt (omdat de geanalyseerde taal niet regulier is), is er een canonieke volgende stap: gebruik een parser voor grammatica van een hoger type. Voor CSS betekent dat een parser voor contextvrije talen. In feite bestond een dergelijk parsersysteem al in de codebase van DevTools: Lezer van CodeMirror, wat de basis vormt voor bijvoorbeeld syntaxisaccentuering in CodeMirror, de editor die je in het paneel Bronnen vindt. Met de CSS-parser van Lezer konden we (niet-abstracte) syntaxisbomen voor CSS-regels produceren en konden we deze gebruiken. Overwinning.
Alleen vonden we het out-of-the-box onhaalbaar om rechtstreeks van regex-gebaseerde matching naar parser-gebaseerde matching te migreren: de twee benaderingen werken vanuit tegengestelde richtingen. Bij het matchen van waarden met reguliere expressies scande DevTools de invoer van links naar rechts, waarbij herhaaldelijk werd geprobeerd de vroegste overeenkomst te vinden in een geordende lijst met patronen. Met een syntaxisboom zou het matchen van onderaf beginnen, bijvoorbeeld door eerst de argumenten van een aanroep te analyseren, voordat wordt geprobeerd de functieaanroep te matchen. Zie het als het evalueren van een rekenkundige uitdrukking, waarbij u eerst uitdrukkingen tussen haakjes zou overwegen, dan vermenigvuldigende operatoren en vervolgens additieve operatoren. In dit kader komt de op regex gebaseerde matching overeen met het evalueren van de rekenkundige expressie van links naar rechts. We wilden echt niet het hele matchingsysteem helemaal opnieuw schrijven: er waren 15 verschillende matchers en rendererparen, met duizenden regels code, waardoor het onwaarschijnlijk was dat we het in één keer konden verzenden.
Daarom hebben we een oplossing bedacht waarmee we stapsgewijze wijzigingen konden aanbrengen, die we hieronder in meer detail zullen beschrijven. Kortom, we hebben de tweefasige aanpak behouden, maar in de eerste fase proberen we subexpressies bottom-up te matchen (en zo te breken met de regex-stroom), en in de tweede fase renderen we top-down. In beide fasen konden we de bestaande op regex gebaseerde matchers en renders vrijwel ongewijzigd gebruiken en konden we ze dus één voor één migreren.
Fase 1: Bottom-up matching
De eerste fase doet min of meer precies en uitsluitend wat er op de cover staat. We doorkruisen de boom in volgorde van onder naar boven en proberen subexpressies te matchen bij elk syntaxisboomknooppunt dat we bezoeken. Om een specifieke subexpressie te matchen, kan een matcher regex gebruiken, net zoals in het bestaande systeem. Vanaf versie 128 doen we dat in enkele gevallen zelfs nog, bijvoorbeeld voor het matchen van lengtes . Als alternatief kan een matcher de structuur analyseren van de subboom die is geworteld in het huidige knooppunt. Hierdoor kan het syntaxisfouten opsporen en tegelijkertijd structurele informatie vastleggen.
Beschouw het voorbeeld van de syntaxisboom hierboven:
Voor deze boom zouden onze matchers in de volgende volgorde een aanvraag indienen:
-
hsl(
177deg
var(--saturation, 100%) 50%)
: Eerst ontdekken we het eerste argument van dehsl
functieaanroep, de tinthoek. We matchen het met een hoekmatcher, zodat we de hoekwaarde kunnen versieren met het hoekpictogram. -
hsl(177deg
var(--saturation, 100%)
50%)
: Ten tweede ontdekken we devar
-functieaanroep met een var-matcher. Bij zulke oproepen willen we vooral twee dingen doen:- Zoek de declaratie van de variabele op en bereken de waarde ervan, en voeg respectievelijk een link en een popover toe aan de naam van de variabele om er verbinding mee te maken.
- Versier het gesprek met een kleurenpictogram als de berekende waarde een kleur is. Er is eigenlijk nog een derde ding, maar daar zullen we later over praten.
-
hsl(177deg var(--saturation, 100%) 50%)
: Ten slotte matchen we de aanroepexpressie voor dehsl
-functie, zodat we deze kunnen decoreren met het kleurenpictogram.
Naast het zoeken naar subexpressies die we willen verfraaien, is er eigenlijk een tweede functie die we gebruiken als onderdeel van het matchingproces. Merk op dat we in stap #2 zeiden dat we de berekende waarde voor een variabelenaam moesten opzoeken. Sterker nog, we gaan nog een stap verder en verspreiden de resultaten de boom in. En niet alleen voor de variabele, maar ook voor de fallback-waarde! Het is gegarandeerd dat bij het bezoeken van een var
-functieknooppunt de onderliggende elementen ervan vooraf zijn bezocht, zodat we al de resultaten kennen van eventuele var
-functies die mogelijk in de fallback-waarde voorkomen. Daarom kunnen we var
-functies eenvoudig en goedkoop direct vervangen door hun resultaten, waardoor we triviaal vragen kunnen beantwoorden als "Is het resultaat van deze var
een kleur?", zoals we deden in stap #2.
Fase 2: Rendering van bovenaf
Voor de tweede fase keren we de richting om. Op basis van de wedstrijdresultaten uit fase 1 renderen we de boom in HTML door deze in volgorde van boven naar beneden te doorlopen. Voor elk bezocht knooppunt controleren we of het overeenkomt en zo ja, dan bellen we de corresponderende renderer van de matcher. We vermijden de noodzaak van speciale afhandeling voor knooppunten die alleen tekst bevatten (zoals de NumberLiteral
"50%") door een standaard matcher en renderer voor tekstknooppunten op te nemen. Renderers voeren eenvoudigweg HTML-knooppunten uit, die, wanneer ze worden samengevoegd, de weergave van de waarde van het onroerend goed produceren, inclusief de decoraties ervan.
Voor de voorbeeldstructuur is dit de volgorde waarin de eigenschapswaarde wordt weergegeven:
- Bezoek de
hsl
functieaanroep. Het kwam overeen, dus roep de kleurfunctie-renderer aan. Het doet twee dingen:- Berekent de werkelijke kleurwaarde met behulp van het directe vervangingsmechanisme voor eventuele
var
argumenten, en tekent vervolgens een kleurenpictogram. - Geeft recursief de onderliggende elementen van de
CallExpression
weer. Dit zorgt automatisch voor het weergeven van de functienaam, haakjes en komma's, die alleen maar tekst zijn.
- Berekent de werkelijke kleurwaarde met behulp van het directe vervangingsmechanisme voor eventuele
- Bezoek het eerste argument van de
hsl
oproep. Het kwam overeen, dus roep de hoekrenderer aan, die het hoekpictogram en de tekst van de hoek tekent. - Bezoek het tweede argument, de
var
-aanroep. Het kwam overeen, dus roep de var renderer aan, die het volgende uitvoert:- De tekst
var(
aan het begin. - De variabele krijgt een naam en versiert deze met een link naar de definitie van de variabele of met een grijze tekstkleur om aan te geven dat deze niet gedefinieerd is. Er wordt ook een popover aan de variabele toegevoegd om informatie over de waarde ervan weer te geven.
- De komma en geeft vervolgens recursief de fallback-waarde weer.
- Een sluitend haakje.
- De tekst
- Bezoek het laatste argument van de
hsl
oproep. Het kwam niet overeen, dus voer gewoon de tekstinhoud uit.
Is het je opgevallen dat in dit algoritme een render volledig bepaalt hoe de kinderen van een overeenkomend knooppunt worden weergegeven? Het recursief weergeven van de kinderen is proactief. Deze truc heeft een stapsgewijze migratie mogelijk gemaakt van op regex gebaseerde weergave naar op syntaxisboom gebaseerde weergave. Voor knooppunten die overeenkomen met een oudere regex-matcher, kan de overeenkomstige renderer in zijn oorspronkelijke vorm worden gebruikt. In syntaxisboomtermen zou het de verantwoordelijkheid op zich nemen voor het weergeven van de gehele subboom, en het resultaat ervan (een HTML-knooppunt) zou netjes in het omringende weergaveproces kunnen worden ingeplugd. Dit gaf ons de mogelijkheid om matchers en renderers in paren te porten en ze één voor één uit te wisselen.
Een andere leuke eigenschap van renderers die de weergave van de kinderen van hun overeenkomende knooppunten regelen, is dat het ons de mogelijkheid geeft om te redeneren over de afhankelijkheden tussen de pictogrammen die we toevoegen. In het bovenstaande voorbeeld hangt de kleur die door de hsl
-functie wordt geproduceerd uiteraard af van de tintwaarde. Dat betekent dat de kleur die door het kleurenpictogram wordt weergegeven, afhangt van de hoek die wordt weergegeven door het hoekpictogram. Als de gebruiker de hoekeditor via dat pictogram opent en de hoek wijzigt, kunnen we nu de kleur van het kleurenpictogram in realtime bijwerken:
Zoals je in het bovenstaande voorbeeld kunt zien, gebruiken we dit mechanisme ook voor andere pictogramcombinaties, zoals voor color-mix()
en de twee kleurkanalen ervan, of var
-functies die een kleur retourneren uit de fallback.
Prestatie-impact
Toen we ons in dit probleem verdiepten om de betrouwbaarheid te verbeteren en langdurige problemen op te lossen, verwachtten we enige prestatievermindering, aangezien we een volwaardige parser waren gaan gebruiken. Om dit uit te testen hebben we een benchmark gemaakt die ongeveer 3,5k eigendomsdeclaraties weergeeft en zowel de regex-gebaseerde als parser-gebaseerde versies geprofileerd met 6x throttling op een M1-machine.
Zoals we hadden verwacht, bleek de op parsing gebaseerde aanpak in dat geval 27% langzamer te zijn dan de op regex gebaseerde aanpak. Het renderen van de op regex gebaseerde aanpak duurde 11 seconden en het renderen op basis van een parser duurde 15 seconden.
Gezien de overwinningen die we behalen met de nieuwe aanpak, hebben we besloten hiermee verder te gaan.
Dankbetuigingen
Onze diepste dank gaat uit naar Sofia Emelianova en Jecelyn Yeen voor hun onschatbare hulp bij het bewerken van dit bericht!
Download de voorbeeldkanalen
Overweeg om Chrome Canary , Dev of Beta te gebruiken als uw standaard ontwikkelingsbrowser. Met deze voorbeeldkanalen krijgt u toegang tot de nieuwste DevTools-functies, kunt u geavanceerde webplatform-API's testen en kunt u problemen op uw site opsporen voordat uw gebruikers dat doen!
Neem contact op met het Chrome DevTools-team
Gebruik de volgende opties om de nieuwe functies, updates of iets anders gerelateerd aan DevTools te bespreken.
- Stuur feedback en functieverzoeken naar ons op crbug.com .
- Rapporteer een DevTools-probleem met Meer opties > Help > Rapporteer een DevTools-probleem in DevTools.
- Tweet op @ChromeDevTools .
- Laat reacties achter op Wat is er nieuw in DevTools YouTube-video's of DevTools Tips YouTube-video's .
Is het je opgevallen dat de CSS-eigenschappen op het tabblad Stijlen van Chrome DevTools er de laatste tijd wat gepolijster uitzien? Deze updates, uitgerold tussen Chrome 121 en 128, zijn het resultaat van een aanzienlijke verbetering in de manier waarop we CSS-waarden parseren en presenteren. In dit artikel leiden we u door de technische details van deze transformatie, waarbij we overgaan van een systeem voor het matchen van reguliere expressies naar een robuustere parser.
Laten we de huidige DevTools vergelijken met de vorige versie:
Een behoorlijk verschil, toch? Hier volgt een overzicht van de belangrijkste verbeteringen:
-
color-mix
. Een handig voorbeeld dat de twee kleurargumenten binnen decolor-mix
visueel weergeeft. -
pink
. Een klikbaar kleurvoorbeeld voor de genoemde kleurpink
. Klik erop om een kleurkiezer te openen voor eenvoudige aanpassingen. -
var(--undefined, [fallback value])
. Verbeterde verwerking van ongedefinieerde variabelen, waarbij de ongedefinieerde variabele grijs wordt weergegeven en de actieve fallback-waarde (in dit geval een HSL-kleur) wordt weergegeven met een klikbaar kleurvoorbeeld. -
hsl(…)
: Nog een klikbaar kleurvoorbeeld voor dehsl
kleurfunctie, die snelle toegang tot de kleurkiezer biedt. -
177deg
: een klikbare hoekklok waarmee u de hoekwaarde interactief kunt slepen en wijzigen. -
var(--saturation, …)
: Een klikbare link naar de aangepaste eigenschapsdefinitie, waardoor u gemakkelijk naar de relevante declaratie kunt springen.
Het verschil is opvallend. Om dit te bereiken moesten we DevTools leren de CSS-eigenschapswaarden veel beter te begrijpen dan voorheen.
Waren deze previews niet al beschikbaar?
Hoewel deze voorbeeldpictogrammen misschien bekend voorkomen, worden ze niet altijd consistent weergegeven, vooral niet in complexe CSS-syntaxis zoals in het bovenstaande voorbeeld. Zelfs als ze wel werkten, waren er vaak aanzienlijke inspanningen nodig om ze correct te laten functioneren.
De reden daarvoor is dat het systeem voor het analyseren van waarden sinds de eerste dagen van DevTools organisch is gegroeid. Het heeft echter geen gelijke tred kunnen houden met de recente verbazingwekkende nieuwe functies die we van CSS krijgen, en de daarmee gepaard gaande toename van de taalcomplexiteit. Het systeem vereiste een volledig nieuw ontwerp om gelijke tred te houden met de evolutie en dat is precies wat we hebben gedaan!
Hoe CSS-eigenschapswaarden worden verwerkt
In DevTools is het proces van het weergeven en decoreren van eigendomsdeclaraties op het tabblad Stijlen opgesplitst in twee afzonderlijke fasen:
- Structurele analyse. In deze eerste fase wordt de eigendomsverklaring ontleed om de onderliggende componenten en hun relaties te identificeren. In de
border: 1px solid red
herkent het bijvoorbeeld1px
als een lengte,solid
als een string enred
als een kleur. - Weergave. Voortbouwend op de structurele analyse transformeert de weergavefase deze componenten in een HTML-representatie. Dit verrijkt de weergegeven eigendomstekst met interactieve elementen en visuele aanwijzingen. De kleurwaarde
red
wordt bijvoorbeeld weergegeven met een klikbaar kleurpictogram dat, wanneer erop wordt geklikt, een kleurkiezer onthult voor eenvoudige aanpassing.
Reguliere expressies
Voorheen vertrouwden we op reguliere expressies (regexes) om de eigenschapswaarden voor structurele analyse te ontleden. We hebben een lijst met regexes bijgehouden die overeenkomen met de stukjes eigenschapswaarde die we als decoratie beschouwden. Er waren bijvoorbeeld expressies die overeenkwamen met CSS-kleuren, lengtes, hoeken, ingewikkelder subexpressies zoals var
-functieaanroepen, enzovoort. We hebben de tekst van links naar rechts gescand om waardeanalyses uit te voeren, waarbij we voortdurend op zoek waren naar de eerste uitdrukking uit de lijst die overeenkomt met het volgende stuk tekst.
Hoewel dit meestal prima werkte, bleef het aantal gevallen waarin dit niet gebeurde groeien. Door de jaren heen hebben we een groot aantal bugrapporten ontvangen waarin de matching niet helemaal klopte. Toen we deze oplosten – sommige eenvoudig, andere behoorlijk uitgebreid – moesten we onze aanpak heroverwegen om onze technische schulden op afstand te houden. Laten we eens een paar van de problemen bekijken!
Overeenkomende color-mix()
De regex die we gebruikten voor de color-mix()
functie was de volgende:
/color-mix\(.*,\s*(?<firstColor>.+)\s*,\s*(?<secondColor>.+)\s*\)/g
Wat overeenkomt met de syntaxis:
color-mix(<color-interpolation-method>, [<color> && <percentage [0,100]>?]#{2})
Probeer het volgende voorbeeld uit te voeren om de overeenkomsten te visualiseren.
const re = /color-mix\(.*,\s*(?<firstColor>.+)\s*,\s*(?<secondColor>.+)\s*\)/g;
// it works - simpler example
const simpler = re.exec('color-mix(in srgb, pink, hsl(127deg 100% 50%))');
console.table(simpler.groups);
re.exec('');
// it doesn't work - complex example
const complex = re.exec('color-mix(in srgb, pink, var(--undefined, hsl(127deg var(--saturation, 100%) 50%)))');
console.table(complex.groups);
Het eenvoudigere voorbeeld werkt prima. In het complexere voorbeeld is de <firstColor>
-match echter hsl(177deg var(--saturation
and <secondColor>
match is 100%) 50%))
, wat volkomen zinloos is.
We wisten dat dit een probleem was. CSS als formele taal is tenslotte niet regulier , dus hebben we al een speciale behandeling toegevoegd om met ingewikkeldere functieargumenten om te gaan, zoals var
-functies. Zoals je in de eerste schermafbeelding kunt zien, werkte dat echter nog steeds niet in alle gevallen.
Bijpassende tan()
Een van de meest hilarische gerapporteerde bugs betrof de trigonometrische tan()
functie . De regex die we gebruikten voor het matchen van kleuren bevatte een subexpressie \b[a-zA-Z]+\b(?!-)
voor het matchen van benoemde kleuren, zoals het red
trefwoord. Vervolgens hebben we gecontroleerd of het overeenkomende deel daadwerkelijk een benoemde kleur is, en raad eens: tan
is ook een benoemde kleur! We hebben dus tan()
-expressies ten onrechte geïnterpreteerd als kleuren.
Overeenkomende var()
Laten we een ander voorbeeld bekijken, var()
functies met een fallback die andere var()
referenties bevat: var(--non-existent, var(--margin-vertical))
.
Onze regex voor var()
zou graag overeenkomen met deze waarde. Alleen stopt het matchen bij het eerste haakje sluiten. Dus de bovenstaande tekst wordt gematcht als var(--non-existent, var(--margin-vertical)
. Dit is een beperking uit het leerboek van het matchen van reguliere expressies. Talen die matchende haakjes vereisen, zijn fundamenteel niet regulier.
Overgang naar een CSS-parser
Wanneer tekstanalyse met reguliere expressies niet meer werkt (omdat de geanalyseerde taal niet regulier is), is er een canonieke volgende stap: gebruik een parser voor grammatica van een hoger type. Voor CSS betekent dat een parser voor contextvrije talen. In feite bestond een dergelijk parsersysteem al in de codebase van DevTools: Lezer van CodeMirror, wat de basis vormt voor bijvoorbeeld syntaxisaccentuering in CodeMirror, de editor die je in het paneel Bronnen vindt. Met de CSS-parser van Lezer konden we (niet-abstracte) syntaxisbomen voor CSS-regels produceren en konden we deze gebruiken. Overwinning.
Alleen vonden we het out-of-the-box onhaalbaar om rechtstreeks van regex-gebaseerde matching naar parser-gebaseerde matching te migreren: de twee benaderingen werken vanuit tegengestelde richtingen. Bij het matchen van waarden met reguliere expressies scande DevTools de invoer van links naar rechts, waarbij herhaaldelijk werd geprobeerd de vroegste overeenkomst te vinden in een geordende lijst met patronen. Met een syntaxisboom zou het matchen van onderaf beginnen, bijvoorbeeld door eerst de argumenten van een aanroep te analyseren, voordat wordt geprobeerd de functieaanroep te matchen. Zie het als het evalueren van een rekenkundige uitdrukking, waarbij u eerst uitdrukkingen tussen haakjes zou overwegen, dan vermenigvuldigende operatoren en vervolgens additieve operatoren. In dit kader komt de op regex gebaseerde matching overeen met het evalueren van de rekenkundige expressie van links naar rechts. We wilden echt niet het hele matchingsysteem helemaal opnieuw schrijven: er waren 15 verschillende matchers en rendererparen, met duizenden regels code, waardoor het onwaarschijnlijk was dat we het in één keer konden verzenden.
Daarom hebben we een oplossing bedacht waarmee we stapsgewijze wijzigingen konden aanbrengen, die we hieronder in meer detail zullen beschrijven. Kortom, we hebben de tweefasige aanpak behouden, maar in de eerste fase proberen we subexpressies bottom-up te matchen (en zo te breken met de regex-stroom), en in de tweede fase renderen we top-down. In beide fasen konden we de bestaande op regex gebaseerde matchers en renders vrijwel ongewijzigd gebruiken en konden we ze dus één voor één migreren.
Fase 1: Bottom-up matching
De eerste fase doet min of meer precies en uitsluitend wat er op de cover staat. We doorkruisen de boom in volgorde van onder naar boven en proberen subexpressies te matchen bij elk syntaxisboomknooppunt dat we bezoeken. Om een specifieke subexpressie te matchen, kan een matcher regex gebruiken, net zoals in het bestaande systeem. Vanaf versie 128 doen we dat in enkele gevallen zelfs nog, bijvoorbeeld voor het matchen van lengtes . Als alternatief kan een matcher de structuur analyseren van de subboom die is geworteld in het huidige knooppunt. Hierdoor kan het syntaxisfouten opsporen en tegelijkertijd structurele informatie vastleggen.
Beschouw het voorbeeld van de syntaxisboom hierboven:
Voor deze boom zouden onze matchers in de volgende volgorde een aanvraag indienen:
-
hsl(
177deg
var(--saturation, 100%) 50%)
: Eerst ontdekken we het eerste argument van dehsl
-functieaanroep, de tinthoek. We matchen het met een hoekmatcher, zodat we de hoekwaarde kunnen versieren met het hoekpictogram. -
hsl(177deg
var(--saturation, 100%)
50%)
: Ten tweede ontdekken we devar
-functieaanroep met een var-matcher. Bij zulke oproepen willen we vooral twee dingen doen:- Zoek de declaratie van de variabele op en bereken de waarde ervan, en voeg respectievelijk een link en een popover toe aan de naam van de variabele om er verbinding mee te maken.
- Versier het gesprek met een kleurenpictogram als de berekende waarde een kleur is. Er is eigenlijk nog een derde ding, maar daar zullen we later over praten.
-
hsl(177deg var(--saturation, 100%) 50%)
: Ten slotte matchen we de aanroepexpressie voor dehsl
-functie, zodat we deze kunnen decoreren met het kleurenpictogram.
Naast het zoeken naar subexpressies die we willen verfraaien, is er eigenlijk een tweede functie die we gebruiken als onderdeel van het matchingproces. Merk op dat we in stap #2 zeiden dat we de berekende waarde voor een variabelenaam moesten opzoeken. Sterker nog, we gaan nog een stap verder en verspreiden de resultaten hogerop. En niet alleen voor de variabele, maar ook voor de fallback-waarde! Het is gegarandeerd dat bij het bezoeken van een var
-functieknooppunt de onderliggende elementen ervan vooraf zijn bezocht, zodat we al de resultaten kennen van eventuele var
-functies die mogelijk in de fallback-waarde voorkomen. Daarom kunnen we var
-functies eenvoudig en goedkoop vervangen door hun resultaten, waardoor we triviaal vragen kunnen beantwoorden als "Is het resultaat van deze var
een kleur?", zoals we deden in stap #2.
Fase 2: Rendering van bovenaf
Voor de tweede fase keren we de richting om. Op basis van de wedstrijdresultaten uit fase 1 renderen we de boom in HTML door deze in volgorde van boven naar beneden te doorlopen. Voor elk bezocht knooppunt controleren we of het overeenkomt en zo ja, dan bellen we de corresponderende renderer van de matcher. We vermijden de noodzaak van speciale afhandeling voor knooppunten die alleen tekst bevatten (zoals de NumberLiteral
"50%") door een standaard matcher en renderer voor tekstknooppunten op te nemen. Renderers voeren eenvoudigweg HTML-knooppunten uit, die, wanneer ze worden samengevoegd, de weergave van de waarde van het onroerend goed produceren, inclusief de decoraties ervan.
Voor de voorbeeldstructuur is dit de volgorde waarin de eigenschapswaarde wordt weergegeven:
- Bezoek de
hsl
functieaanroep. Het kwam overeen, dus roep de kleurfunctie-renderer aan. Het doet twee dingen:- Berekent de werkelijke kleurwaarde met behulp van het directe vervangingsmechanisme voor eventuele
var
argumenten, en tekent vervolgens een kleurenpictogram. - Geeft recursief de onderliggende elementen van de
CallExpression
weer. Dit zorgt automatisch voor het weergeven van de functienaam, haakjes en komma's, die alleen maar tekst zijn.
- Berekent de werkelijke kleurwaarde met behulp van het directe vervangingsmechanisme voor eventuele
- Bezoek het eerste argument van de
hsl
oproep. Het kwam overeen, dus roep de hoekrenderer aan, die het hoekpictogram en de tekst van de hoek tekent. - Bezoek het tweede argument, de
var
-aanroep. Het kwam overeen, dus roep de var renderer aan, die het volgende uitvoert:- De tekst
var(
aan het begin. - De variabele krijgt een naam en versiert deze met een link naar de definitie van de variabele of met een grijze tekstkleur om aan te geven dat deze niet gedefinieerd is. Er wordt ook een popover aan de variabele toegevoegd om informatie over de waarde ervan weer te geven.
- De komma en geeft vervolgens recursief de fallback-waarde weer.
- Een sluitend haakje.
- De tekst
- Bezoek het laatste argument van de
hsl
oproep. Het kwam niet overeen, dus voer gewoon de tekstinhoud uit.
Is het je opgevallen dat in dit algoritme een render volledig bepaalt hoe de kinderen van een overeenkomend knooppunt worden weergegeven? Het recursief weergeven van de kinderen is proactief. Deze truc heeft een stapsgewijze migratie mogelijk gemaakt van op regex gebaseerde weergave naar op syntaxisboom gebaseerde weergave. Voor knooppunten die overeenkomen met een oudere regex-matcher, kan de overeenkomstige renderer in zijn oorspronkelijke vorm worden gebruikt. In syntaxisboomtermen zou het de verantwoordelijkheid op zich nemen voor het weergeven van de gehele subboom, en het resultaat ervan (een HTML-knooppunt) zou netjes in het omringende weergaveproces kunnen worden aangesloten. Dit gaf ons de mogelijkheid om matchers en renderers in paren te porten en ze één voor één uit te wisselen.
Een andere leuke eigenschap van renderers die de weergave van de kinderen van hun overeenkomende knooppunten regelen, is dat het ons de mogelijkheid geeft om te redeneren over de afhankelijkheden tussen de pictogrammen die we toevoegen. In het bovenstaande voorbeeld hangt de kleur die door de hsl
-functie wordt geproduceerd uiteraard af van de tintwaarde. Dat betekent dat de kleur die door het kleurenpictogram wordt weergegeven, afhangt van de hoek die wordt weergegeven door het hoekpictogram. Als de gebruiker de hoekeditor via dat pictogram opent en de hoek wijzigt, kunnen we nu de kleur van het kleurenpictogram in realtime bijwerken:
Zoals je in het bovenstaande voorbeeld kunt zien, gebruiken we dit mechanisme ook voor andere pictogramcombinaties, zoals voor color-mix()
en de twee kleurkanalen ervan, of var
-functies die een kleur retourneren uit de fallback.
Prestatie-impact
Toen we ons in dit probleem verdiepten om de betrouwbaarheid te verbeteren en langdurige problemen op te lossen, verwachtten we enige prestatievermindering, aangezien we een volwaardige parser waren gaan gebruiken. Om dit uit te testen hebben we een benchmark gemaakt die ongeveer 3,5k eigendomsdeclaraties weergeeft en zowel de regex-gebaseerde als parser-gebaseerde versies geprofileerd met 6x throttling op een M1-machine.
Zoals we hadden verwacht, bleek de op parsing gebaseerde aanpak in dat geval 27% langzamer te zijn dan de op regex gebaseerde aanpak. Het renderen van de op regex gebaseerde aanpak duurde 11 seconden en het renderen op basis van een parser duurde 15 seconden.
Gezien de overwinningen die we behalen met de nieuwe aanpak, hebben we besloten hiermee verder te gaan.
Dankbetuigingen
Onze diepste dank gaat uit naar Sofia Emelianova en Jecelyn Yeen voor hun onschatbare hulp bij het bewerken van dit bericht!
Download de voorbeeldkanalen
Overweeg om Chrome Canary , Dev of Beta te gebruiken als uw standaard ontwikkelingsbrowser. Met deze voorbeeldkanalen krijgt u toegang tot de nieuwste DevTools-functies, kunt u geavanceerde webplatform-API's testen en kunt u problemen op uw site opsporen voordat uw gebruikers dat doen!
Neem contact op met het Chrome DevTools-team
Gebruik de volgende opties om de nieuwe functies, updates of iets anders gerelateerd aan DevTools te bespreken.
- Stuur feedback en functieverzoeken naar ons op crbug.com .
- Rapporteer een DevTools-probleem met Meer opties > Help > Rapporteer een DevTools-probleem in DevTools.
- Tweet op @ChromeDevTools .
- Laat reacties achter op Wat is er nieuw in DevTools YouTube-video's of DevTools Tips YouTube-video's .
Is het je opgevallen dat de CSS-eigenschappen op het tabblad Stijlen van Chrome DevTools er de laatste tijd wat gepolijster uitzien? Deze updates, uitgerold tussen Chrome 121 en 128, zijn het resultaat van een aanzienlijke verbetering in de manier waarop we CSS-waarden parseren en presenteren. In dit artikel leiden we u door de technische details van deze transformatie, waarbij we overgaan van een systeem voor het matchen van reguliere expressies naar een robuustere parser.
Laten we de huidige DevTools vergelijken met de vorige versie:
Een behoorlijk verschil, toch? Hier volgt een overzicht van de belangrijkste verbeteringen:
-
color-mix
. Een handig voorbeeld dat de twee kleurargumenten binnen decolor-mix
visueel weergeeft. -
pink
. Een klikbaar kleurvoorbeeld voor de genoemde kleurpink
. Klik erop om een kleurkiezer te openen voor eenvoudige aanpassingen. -
var(--undefined, [fallback value])
. Verbeterde verwerking van ongedefinieerde variabelen, waarbij de ongedefinieerde variabele grijs wordt weergegeven en de actieve fallback-waarde (in dit geval een HSL-kleur) wordt weergegeven met een klikbaar kleurvoorbeeld. -
hsl(…)
: Nog een klikbaar kleurvoorbeeld voor dehsl
kleurfunctie, die snelle toegang tot de kleurkiezer biedt. -
177deg
: een klikbare hoekklok waarmee u de hoekwaarde interactief kunt slepen en wijzigen. -
var(--saturation, …)
: een klikbare link naar de definitie van de aangepaste eigenschap, waardoor het gemakkelijk is om naar de relevante verklaring te springen.
Het verschil is opvallend. Om dit te bereiken, moesten we Devtools leren om CSS -eigendomswaarden veel beter te begrijpen dan voorheen.
Waren deze previews niet al beschikbaar?
Hoewel deze preview -pictogrammen misschien bekend lijken, zijn ze niet altijd consistent weergegeven, vooral in complexe CSS -syntaxis zoals het voorbeeld hierboven. Zelfs in gevallen waarin ze werkten, was er vaak aanzienlijke inspanningen nodig om ze correct te laten functioneren.
De reden daarvoor is dat het systeem voor het analyseren van waarden sinds de eerste dagen van Devtools organisch groeit. Het is echter niet in staat geweest om de recente geweldige nieuwe functies bij te houden die we van CSS krijgen en de overeenkomstige toename van de taalcomplexiteit. Het systeem vereiste een volledig herontwerp om de evolutie bij te houden en dat is precies wat we deden!
Hoe CSS -eigenschapswaarden worden verwerkt
In Devtools wordt het proces van het weergeven en decoreren van eigenschapsverklaringen op het tabblad Styles opgesplitst in twee verschillende fasen:
- Structurele analyse. Deze beginfase ontleedt de vastgoedverklaring om zijn onderliggende componenten en hun relaties te identificeren. Bijvoorbeeld, in de aangifte
border: 1px solid red
, zou het1px
herkennen als een lengte,solid
als een string enred
als een kleur. - Rendering. Voortbouwend op de structurele analyse, transformeert de renderingfase deze componenten in een HTML -weergave. Dit verrijkt de weergegeven eigenschapstekst met interactieve elementen en visuele signalen. De kleurwaarde
red
wordt bijvoorbeeld weergegeven met een klikbaar kleurenpictogram dat, wanneer geklikt, een kleurenkiezer onthult voor eenvoudige wijziging.
Regelmatige uitdrukkingen
Eerder vertrouwden we op reguliere uitdrukkingen (regexen) om de eigenschapswaarden voor structurele analyse te ontleden. We hebben een lijst met regexen bijgehouden die overeenkomen met de bits van eigenschapswaarden die we hebben overwogen te decoreren. Er waren bijvoorbeeld uitdrukkingen die overeenkwamen met CSS-kleuren, lengtes, hoeken, meer gecompliceerde subexpressies zoals var
-functieaanroepen, enzovoort. We hebben de tekst van links naar rechts gescand om waardeanalyse uit te voeren, continu op zoek naar de eerste uitdrukking uit de lijst die overeenkomt met het volgende stuk van de tekst.
Hoewel dit meestal prima werkte, het aantal gevallen waarin het niet bleef groeien. In de loop der jaren hebben we een groot aantal bugrapporten ontvangen waarbij de matching het niet helemaal goed deed. Terwijl we ze hebben opgelost - sommige oplossingen eenvoudig, anderen behoorlijk uitgebreid - moesten we onze aanpak heroverwegen om onze technische schuld op afstand te houden. Laten we enkele problemen bekijken!
Bijpassende color-mix()
De regex die we gebruikten voor de functie color-mix()
was de volgende:
/color-mix\(.*,\s*(?<firstColor>.+)\s*,\s*(?<secondColor>.+)\s*\)/g
Die overeenkomt met zijn syntaxis:
color-mix(<color-interpolation-method>, [<color> && <percentage [0,100]>?]#{2})
Probeer het volgende voorbeeld uit te voeren om de wedstrijden te visualiseren.
const re = /color-mix\(.*,\s*(?<firstColor>.+)\s*,\s*(?<secondColor>.+)\s*\)/g;
// it works - simpler example
const simpler = re.exec('color-mix(in srgb, pink, hsl(127deg 100% 50%))');
console.table(simpler.groups);
re.exec('');
// it doesn't work - complex example
const complex = re.exec('color-mix(in srgb, pink, var(--undefined, hsl(127deg var(--saturation, 100%) 50%)))');
console.table(complex.groups);
Het eenvoudiger voorbeeld werkt prima. In het meer complexe voorbeeld is de <firstColor>
match echter hsl(177deg var(--saturation
en <secondColor>
match is 100%) 50%))
, wat volledig betekenisloos is.
We wisten dat dit een probleem was. CSS als een formele taal is immers niet regelmatig , dus we hebben al speciale behandeling opgenomen om met meer gecompliceerde functieargumenten aan te pakken, zoals var
-functies. Zoals u echter in de eerste screenshot kunt zien, werkte dat in alle gevallen nog steeds niet.
Matching tan()
Een van de meer hilarische gerapporteerde bugs ging over de trigonometrische tan()
functie. De regex die we gebruikten voor bijpassende kleuren omvatte een subexpressie \b[a-zA-Z]+\b(?!-)
voor het matchen van de naam kleuren zoals het red
trefwoord. Vervolgens hebben we gecontroleerd of het bijpassende onderdeel eigenlijk een genoemde kleur is, en raad eens, tan
is ook een genoemde kleur! Dus we hebben tan()
uitdrukkingen ten onrechte geïnterpreteerd als kleuren.
Matching var()
Laten we eens kijken naar een ander voorbeeld, var()
-functies met een fallback die andere var()
referenties bevat: var(--non-existent, var(--margin-vertical))
.
Onze regex voor var()
zou graag overeenkomen met deze waarde. Behalve dat het zou stoppen met matchen bij de eerste sluiting van het sluiten. Dus de bovenstaande tekst wordt geëvenaard als var(--non-existent, var(--margin-vertical)
. Dit is een beperking van het handboek van overeenkomende reguliere expressie. Talen die overeenkomende haakjes vereisen, zijn fundamenteel niet regelmatig.
Overgang naar een CSS -parser
Wanneer tekstanalyse met behulp van reguliere expressies stopt met werken (omdat de geanalyseerde taal niet regelmatig is) is er een canonieke volgende stap: gebruik een parser voor een hogere grammatica. Voor CSS betekent dat een parser voor contextvrije talen. In feite bestond een dergelijk parsersysteem al in de LEZER van de DevTools Codebase: Codemirror's, de basis voor bijvoorbeeld syntaxis die in Codemirror wordt benadrukt, de redacteur die u in het paneel Bronnen vindt. LEZER's CSS Parser Laten we (niet-abstract) syntaxisbomen produceren voor CSS-regels en was klaar voor ons om te gebruiken. Overwinning.
Behalve, uit de doos, vonden we het onhaalbaar om te migreren van op Regex gebaseerde matching naar op Parser gebaseerde matching rechtstreeks: de twee benaderingen werken vanuit tegengestelde richtingen. Bij het matchen van stukken waarden met reguliere uitdrukkingen zouden Devtools de invoer van links naar rechts scannen, waardoor de vroegste match herhaaldelijk probeerde te vinden uit een geordende lijst met patronen. Met een syntaxisboom zou matching van onder op beginnen, bijvoorbeeld, het analyseren van de argumenten van een oproep eerst, voordat hij probeert de functieaanroep te matchen. Zie het als het evalueren van een rekenkundige expressie, waarbij u eerst haakjesuitdrukkingen zou overwegen, vervolgens multiplicatieve operatoren en vervolgens additieve operators. In deze framing komt de op Regex gebaseerde matching overeen met het evalueren van de rekenkundige expressie van links naar rechts. We wilden het hele matching -systeem echt niet helemaal opnieuw herschrijven: er waren 15 verschillende matchers en renderer -paren, met duizenden lijnen code voor hen, waardoor het onwaarschijnlijk was dat we het in een enkele mijlpaal konden verzenden.
Dus kwamen we met een oplossing waarmee we incrementele wijzigingen konden aanbrengen, die we hieronder in meer detail zullen beschrijven. Kortom, we hebben de tweefasenbenadering gehouden, maar in de eerste fase proberen we sub-expressies bottom-up te evenaren (dus breken met de regex-stroom), en in de tweede fase geven we top-down. In beide fasen konden we de bestaande Regex-gebaseerde matchers en renderers gebruiken, praktisch ongewijzigd, en konden ze dus één voor één migreren.
Fase 1: Bottom-up matching
De eerste fase min of meer precies en exclusief doet wat er op de dekking staat. We doorkruisen de boom in volgorde van onder naar boven en proberen sub-expressies te matchen bij elk syntaxisboomknooppunt dat we bezoeken. Om een specifieke subexpressie te evenaren, zou een matcher regex kunnen gebruiken, net zoals in het bestaande systeem. Vanaf versie 128 doen we dat eigenlijk nog steeds in enkele gevallen, bijvoorbeeld voor bijpassende lengtes . Als alternatief kan een matcher de structuur van de substructuur die op het huidige knooppunt is geworteld analyseren. Hierdoor kan het syntaxisfouten vangen en tegelijkertijd structurele informatie opnemen.
Overweeg het voorbeeld van de syntaxis van bovenaf:
Voor deze boom zouden onze matchers in de volgende volgorde van toepassing zijn:
-
hsl(
177deg
var(--saturation, 100%) 50%)
: Eerst ontdekken we het eerste argument van dehsl
functieaanroep, de tinthoek. We matchen het met een hoek matcher, zodat we de hoekwaarde kunnen versieren met het hoekpictogram. -
hsl(177deg
var(--saturation, 100%)
50%)
: Ten tweede ontdekken we devar
-functieaanroep met een VAR-matcher. Voor dergelijke oproepen willen we vooral twee dingen doen:- Zoek de verklaring van de variabele op en bereken de waarde ervan en voeg een link en een popover toe aan de variabele naam om respectievelijk verbinding te maken.
- Versier de oproep met een kleurenpictogram als de berekende waarde een kleur is. Er is eigenlijk een derde ding, maar daar zullen we later over praten.
-
hsl(177deg var(--saturation, 100%) 50%)
: Ten slotte passen we de oproepuitdrukking voor dehsl
functie overeen, zodat we deze kunnen versieren met het kleurenpictogram.
Naast het zoeken naar subexpressies die we graag willen versieren, is er eigenlijk een tweede functie die we gebruiken als onderdeel van het matchingproces. Merk op dat we in stap #2 zeiden dat we de berekende waarde opzoeken voor een variabele naam. In feite gaan we dat nog een stap verder en verspreiden we de resultaten in de boom. En niet alleen voor de variabele, maar ook voor de fallback -waarde! Het is gegarandeerd dat bij het bezoeken van een var
-functie -knooppunt, de kinderen van tevoren zijn bezocht, dus we kennen de resultaten van alle var
-functies die mogelijk in de fallback -waarde verschijnen. Daarom zijn we in staat om var
-functies gemakkelijk en goedkoop te vervangen door hun resultaten, waarmee we vragen kunnen beantwoorden als "Is het resultaat van deze var
-oproep een kleur?", Zoals we deden in stap #2.
Fase 2: top-down rendering
Voor de tweede fase keren we de richting om. Als we de matchresultaten van fase 1 nemen, geven we de boom naar HTML door deze van boven naar beneden te doorkruisen. Voor elk bezochte knooppunt controleren we of het overeenkomt en zo ja, bel de bijbehorende renderer van de matcher. We vermijden de behoefte aan speciale afhandeling voor knooppunten die alleen tekst bevatten (zoals de NumberLiteral
"50%") door een standaard matcher en renderer op te nemen voor tekstknooppunten. Renderers voert eenvoudig HTML -knooppunten uit, die, wanneer ze worden samengesteld, de weergave van de eigenschapswaarde produceren, inclusief de decoraties.
Voor de voorbeeldboom is hier de volgorde waarin de eigenschapswaarde wordt weergegeven:
- Bezoek de
hsl
-functieaanroep. Het kwam overeen, dus roep de kleurfunctie Renderer aan. Het doet twee dingen:- Berekent de werkelijke kleurwaarde met behulp van het on-the-fly substitutiemechanisme voor alle
var
-argumenten en tekent vervolgens een kleurenpictogram. - Recursief weergeven de kinderen van de
CallExpression
. Dit zorgt voor automatisch voor het weergeven van de functienaam, haakjes en komma's, die slechts tekst zijn.
- Berekent de werkelijke kleurwaarde met behulp van het on-the-fly substitutiemechanisme voor alle
- Bezoek het eerste argument van de
hsl
-oproep. Het kwam overeen, dus noem de hoek renderer, die het hoekpictogram en de tekst van de hoek tekent. - Bezoek het tweede argument, dat de
var
-oproep is. Het kwam overeen, dus roep de var renderer aan, die het volgende uitvoert:- De tekst
var(
aan het begin. - De variabele naam en versiert deze met een link naar de definitie van de variabele of met een grijze tekstkleur om aan te geven dat deze niet was gedefinieerd, het voegt ook een popover toe aan de variabele om informatie over de waarde ervan weer te geven.
- De komma en vervolgens recursief de fallback -waarde weergegeven.
- Een afsluitende haakjes.
- De tekst
- Bezoek het laatste argument van de
hsl
-oproep. Het kwam niet overeen, dus voer gewoon de tekstinhoudsinstellingen uit.
Heb je gemerkt dat in dit algoritme een render volledig bepaalt hoe de kinderen van een overeenkomende knooppunt worden weergegeven? Recursief weergeven van de kinderen is proactief. Deze truc is wat een stapsgewijze migratie mogelijk maakte van op regex gebaseerde rendering tot syntaxis-gebaseerde rendering. Voor knooppunten gekoppeld aan een legacy regex-matcher, kan de bijbehorende renderer in zijn oorspronkelijke vorm worden gebruikt. In syntaxisboomtermen zou het de verantwoordelijkheid nemen voor het renderen van de gehele substree, en het resultaat ervan (een HTML -knooppunt) zou netjes kunnen worden aangesloten op het omliggende renderingproces. Dit gaf ons de optie om matchers en renderers in paren te porten en ze een voor een uit te ruilen.
Een ander cool kenmerk van renderers die de weergave van de kinderen van hun gematchte knooppunt controleren, is dat het ons de mogelijkheid geeft om te redeneren over afhankelijkheden tussen de pictogrammen die we toevoegen. In het bovenstaande voorbeeld hangt de kleur die wordt geproduceerd door de hsl
-functie duidelijk af van de tintwaarde. Dat betekent dat de kleur die wordt getoond door het kleurenpictogram afhankelijk is van de hoek die wordt weergegeven door het hoekpictogram. Als de gebruiker de hoekeditor via dat pictogram opent en de hoek wijzigt, kunnen we nu de kleur van het kleurpictogram in realtime bijwerken:
Zoals u in het bovenstaande voorbeeld kunt zien, gebruiken we dit mechanisme ook voor andere pictogramparen, zoals voor color-mix()
en de twee kleurenkanalen, of var
-functies die een kleur terugkeren uit de fallback.
Prestatie -impact
Toen we in dit probleem duiken voor het verbeteren van de betrouwbaarheid en het oplossen van langdurige problemen, verwachtten we wat prestatieregressie, aangezien we een volwaardige parser begonnen te runnen. Voor het testen van dit hebben we een benchmark gemaakt die ongeveer 3,5k eigendomsklaringen weergeeft en zowel de op Regex gebaseerde als op parser gebaseerde versies met 6x throttling op een M1-machine profileerde.
Zoals we hadden verwacht, bleek de op parsing gebaseerde aanpak 27% langzamer te zijn dan de op Regex gebaseerde aanpak voor die zaak. De op Regex gebaseerde aanpak duurde 11s om de gebaseerde aanpak van Parser te renderen en duurde 15s om te renderen.
Gezien de overwinningen die we krijgen van de nieuwe aanpak, hebben we besloten om ermee verder te gaan.
Erkenningen
Onze diepste dankbaarheid gaat uit naar Sofia Emelianova en Jecelyn Yeen voor hun onschatbare hulp bij het bewerken van dit bericht!
Download de voorbeeldkanalen
Overweeg het gebruik van de Chrome Canary , Dev of Beta als uw standaardontwikkelingsbrowser. Deze preview-kanalen geven u toegang tot de nieuwste DevTools-functies, kunt u geavanceerde webplatform-API's testen en u helpen problemen op uw site te vinden voordat uw gebruikers dat doen!
Neem contact op met het Chrome Devtools -team
Gebruik de volgende opties om de nieuwe functies, updates of iets anders met betrekking tot Devtools te bespreken.
- Dien feedback en functieverzoeken in op CRBUG.com .
- Rapporteer een probleem met DevTools met behulp van de More Options > Help > Rapporteer een probleem met DevTools in Devtools.
- Tweet op @chromedevtools .
- Laat opmerkingen achter over wat er nieuw is in Devtools YouTube -video's of devtools tips YouTube -video's .