SMELUKOV_DEV Telegram 118
Привет! Давненько тут ничего не было. Исправляюсь. Пока просто небольшая заметка, но чуть позже расскажу и покажу кое-что интересное ☺️
Сейчас я занимаюсь вопросом тришейкинга CSS в бандле Яндекс Маркета: пытаюсь определить CSS-классы, которые точно не используются и вырезать весь CSS, связанный с этими классами. Задачка оказалась чуть сложнее, чем казалось изначально, но все движется к завершению, о чем и расскажу позже.
Чтобы вырезать CSS неиспользуемых классов я беру CSSO, передаю ему CSS нашего бандла и список всех классов, которые точно используются, а CSSO отдает CSS без "мертвых" (неиспользуемых) стилей. Как такие стили могли попасть в бандл - другой вопрос, расскажу позже. Эта заметка о другом.

Исторически, для минификации CSS, мы используем cssnano.
Но теперь, в пайплайн обработки CSS добавился еще и CSSO. Казалось бы, все должно быть хорошо, но не тут-то было.
В нашем CSS есть вполне безобидная конструкция:
body {
font: .8em 'YS Text', Arial, Helvetica, sans-serif;
}


Если обработать ее отдельно через разные минификаторы, то получатся вполне валидные конструкции:
cssnano: body{font:.8em YS Text,Arial,Helvetica,sans-serif}
CSSO: body{font:.8em"YS Text",Arial,Helvetica,sans-serif}

А если обработать ее сначала через CSSO, а потом через cssnano, то получаем невалидный css:
body{font:.8em"YS Text"Arial,Helvetica,sans-serif}

Проблема вот здесь: .8em"YS Text"Arial
cssnano не вставил запятую перед Arial и получилась невалидное значение.
То есть вот такой вариант .8em "YS Text" cssnano минифицирует нормально, а вот такой .8em"YS Text" уже нет, хотя это валидное значение.
Пошел смотреть исходники cssnano, порадовало, что все разделено на пакеты. Это, по сути, набор плагинов для postcss.
Корень проблемы оказался вот здесь, в пакете postcss-minify-font-values. Тут определяется токен, на котором заканчивается описание внешнего вида (текст, размре и т.д.) и начинается описание font-family, и работает это по такой логике: "мамой клянусь - через 2 токена будет описание font-family" 😄
Например, для значения .8em "YS Text",Arial будет вот так:
- { type: 'word', value: '.8em' } <- здесь заканчивается описание внешнего вида и через 2 токена отсюда будет font-family
- { type: "space", value: " " } <- раз
- { type: 'string', quote: '"', value: 'YS Text' } <- два, а вот и font-family
- { type: 'div', value: ',', before: '', after: ' ' }
- { type: 'word', value: 'Arial' }

Но перед cssnano стоит CSSO и превращает эту конструкцию в .8em"YS Text",Arial и это абсолютно валидное значение, но логика той части cssnano, которая отвечает за работу со значениями font-свойств перестает работать:
- { type: 'word', value: '.8em' } <- через 2 токена должен быть font-family
- { type: 'string', quote: '"', value: 'YS Text' } <- раз
- { type: 'div', value: ',', before: '', after: ' ' } <- два... ой 😳
- { type: 'word', value: 'Arial' }

В результате, cssnano просто игнорирует этот токен и на выходе получаем .8em"YS Text"Arial

Недолго думая, занес в cssnano ПР с фиксом.
Там просто учтен кейс, в котором перед font-family можен не быть пробела и конструкция .8em"YS Text",Arial превратится в совершенно валидную .8em YS Text,Arial 🎉

Но проблема, на самом деле, глубже. Заключается она в том, что работа с CSS в cssnano и плагинах postcss (поверх которого работает cssnano) происходит на уровне токенов, а не на уровне детального AST, вот и получается, что разбор значений происходит не по спеке, а на "честном слове". Таким способом проблематично учесть всю сложность синтаксиса CSS (а он действительно сложный!). Вот пример еще одного issue из cssnano на тему странностей парсинга и трансформации.
css-tree (поверх которого работает CSSO) разбирает CSS по спеке и строит детальное AST.
Здесь можно посмотреть внутренности разбора любого значения.

У Романа Дворнова (автора css-tree и мейнтейнера CSSO) есть целый доклад на эту тему.

P.S.: возможно, в экосистеме postcss есть плагин, который генерит детальный AST по спеке, но в данном случае, postcss-minify-font-values , а точнее postcss-value-parser, при помощи которого парсятся значения, этого не делает
🔥247👍4



tgoop.com/smelukov_dev/118
Create:
Last Update:

Привет! Давненько тут ничего не было. Исправляюсь. Пока просто небольшая заметка, но чуть позже расскажу и покажу кое-что интересное ☺️
Сейчас я занимаюсь вопросом тришейкинга CSS в бандле Яндекс Маркета: пытаюсь определить CSS-классы, которые точно не используются и вырезать весь CSS, связанный с этими классами. Задачка оказалась чуть сложнее, чем казалось изначально, но все движется к завершению, о чем и расскажу позже.
Чтобы вырезать CSS неиспользуемых классов я беру CSSO, передаю ему CSS нашего бандла и список всех классов, которые точно используются, а CSSO отдает CSS без "мертвых" (неиспользуемых) стилей. Как такие стили могли попасть в бандл - другой вопрос, расскажу позже. Эта заметка о другом.

Исторически, для минификации CSS, мы используем cssnano.
Но теперь, в пайплайн обработки CSS добавился еще и CSSO. Казалось бы, все должно быть хорошо, но не тут-то было.
В нашем CSS есть вполне безобидная конструкция:
body {
font: .8em 'YS Text', Arial, Helvetica, sans-serif;
}


Если обработать ее отдельно через разные минификаторы, то получатся вполне валидные конструкции:
cssnano: body{font:.8em YS Text,Arial,Helvetica,sans-serif}
CSSO: body{font:.8em"YS Text",Arial,Helvetica,sans-serif}

А если обработать ее сначала через CSSO, а потом через cssnano, то получаем невалидный css:
body{font:.8em"YS Text"Arial,Helvetica,sans-serif}

Проблема вот здесь: .8em"YS Text"Arial
cssnano не вставил запятую перед Arial и получилась невалидное значение.
То есть вот такой вариант .8em "YS Text" cssnano минифицирует нормально, а вот такой .8em"YS Text" уже нет, хотя это валидное значение.
Пошел смотреть исходники cssnano, порадовало, что все разделено на пакеты. Это, по сути, набор плагинов для postcss.
Корень проблемы оказался вот здесь, в пакете postcss-minify-font-values. Тут определяется токен, на котором заканчивается описание внешнего вида (текст, размре и т.д.) и начинается описание font-family, и работает это по такой логике: "мамой клянусь - через 2 токена будет описание font-family" 😄
Например, для значения .8em "YS Text",Arial будет вот так:
- { type: 'word', value: '.8em' } <- здесь заканчивается описание внешнего вида и через 2 токена отсюда будет font-family
- { type: "space", value: " " } <- раз
- { type: 'string', quote: '"', value: 'YS Text' } <- два, а вот и font-family
- { type: 'div', value: ',', before: '', after: ' ' }
- { type: 'word', value: 'Arial' }

Но перед cssnano стоит CSSO и превращает эту конструкцию в .8em"YS Text",Arial и это абсолютно валидное значение, но логика той части cssnano, которая отвечает за работу со значениями font-свойств перестает работать:
- { type: 'word', value: '.8em' } <- через 2 токена должен быть font-family
- { type: 'string', quote: '"', value: 'YS Text' } <- раз
- { type: 'div', value: ',', before: '', after: ' ' } <- два... ой 😳
- { type: 'word', value: 'Arial' }

В результате, cssnano просто игнорирует этот токен и на выходе получаем .8em"YS Text"Arial

Недолго думая, занес в cssnano ПР с фиксом.
Там просто учтен кейс, в котором перед font-family можен не быть пробела и конструкция .8em"YS Text",Arial превратится в совершенно валидную .8em YS Text,Arial 🎉

Но проблема, на самом деле, глубже. Заключается она в том, что работа с CSS в cssnano и плагинах postcss (поверх которого работает cssnano) происходит на уровне токенов, а не на уровне детального AST, вот и получается, что разбор значений происходит не по спеке, а на "честном слове". Таким способом проблематично учесть всю сложность синтаксиса CSS (а он действительно сложный!). Вот пример еще одного issue из cssnano на тему странностей парсинга и трансформации.
css-tree (поверх которого работает CSSO) разбирает CSS по спеке и строит детальное AST.
Здесь можно посмотреть внутренности разбора любого значения.

У Романа Дворнова (автора css-tree и мейнтейнера CSSO) есть целый доклад на эту тему.

P.S.: возможно, в экосистеме postcss есть плагин, который генерит детальный AST по спеке, но в данном случае, postcss-minify-font-values , а точнее postcss-value-parser, при помощи которого парсятся значения, этого не делает

BY Сергей Мелюков




Share with your friend now:
tgoop.com/smelukov_dev/118

View MORE
Open in Telegram


Telegram News

Date: |

For crypto enthusiasts, there was the “gm” app, a self-described “meme app” which only allowed users to greet each other with “gm,” or “good morning,” a common acronym thrown around on Crypto Twitter and Discord. But the gm app was shut down back in September after a hacker reportedly gained access to user data. Clear ‘Ban’ on Telegram How to create a business channel on Telegram? (Tutorial) Choose quality over quantity. Remember that one high-quality post is better than five short publications of questionable value.
from us


Telegram Сергей Мелюков
FROM American