From 84d50ac1f150e46c3f64e1d0754e92dfe963ebf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 21 Sep 2017 18:18:55 +0200 Subject: [PATCH] Fix ordering of collected CSS --- .../__snapshots__/collect.test.js.snap | 264 ++++++++++++++---- src/server/__tests__/collect.test.js | 12 +- src/server/collect.js | 13 +- 3 files changed, 227 insertions(+), 62 deletions(-) diff --git a/src/server/__tests__/__snapshots__/collect.test.js.snap b/src/server/__tests__/__snapshots__/collect.test.js.snap index 6134c40ea..58e385584 100644 --- a/src/server/__tests__/__snapshots__/collect.test.js.snap +++ b/src/server/__tests__/__snapshots__/collect.test.js.snap @@ -1,34 +1,126 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`classname in @rule critical 1`] = `"@supports (object-fit: cover) { .linaria {} }@media (min-width: 600px) { .linaria {} }@charset () { .linaria {} }@import () { .linaria {} }@namespace () { .linaria {} }@media () { .linaria {} }@supports () { .linaria {} }@document () { .linaria {} }@page () { .linaria {} }@font-face () { .linaria {} }@keyframes () { .linaria {} }@viewport () { .linaria {} }@counter-style () { .linaria {} }@font-feature-values () { .linaria {} }"`; +exports[`classname in @rule critical 1`] = ` +"@supports (object-fit: cover) { + .linaria { + } +} +@media (min-width: 600px) { + .linaria { + } +} +@charset () { + .linaria { + } +} +@import () { + .linaria { + } +} +@namespace () { + .linaria { + } +} +@media () { + .linaria { + } +} +@supports () { + .linaria { + } +} +@document () { + .linaria { + } +} +@page () { + .linaria { + } +} +@font-face () { + .linaria { + } +} +@viewport () { + .linaria { + } +} +@counter-style () { + .linaria { + } +} +@font-feature-values () { + .linaria { + } +} +" +`; exports[`classname in @rule other 1`] = ` +"@supports (object-fit: cover) { + .other { + } +} +@media (min-width: 600px) { + .other { + } +} +@charset () { + .other { + } +} +@import () { + .other { + } +} +@namespace () { + .other { + } +} +@media () { + .other { + } +} +@supports () { + .other { + } +} +@document () { + .other { + } +} +@page () { + .other { + } +} +@font-face () { + .other { + } +} +@viewport () { + .other { + } +} +@counter-style () { + .other { + } +} +@font-feature-values () { + .other { + } +} " - -@supports (object-fit: cover) { .other {} } -@media (min-width: 600px) { .other {} } -@charset () { .other {} } -@import () { .other {} } -@namespace () { .other {} } -@media () { .other {} } -@supports () { .other {} } -@document () { .other {} } -@page () { .other {} } -@font-face () { .other {} } -@viewport () { .other {} } -@counter-style () { .other {} } -@font-feature-values () { .other {} }" `; exports[`collects complex css critical 1`] = ` -" - +".lotus { + vertical-align: top; +} @media (max-width: 1200px) { .lotus { vertical-align: bottom; } } - @supports (object-fit: contain) { .lotus { object-fit: contain; @@ -36,11 +128,10 @@ exports[`collects complex css critical 1`] = ` .linaria::before, .linaria::after { - content: ''; + content: \\"\\"; object-fit: contain; } } - @supports (object-fit: contain) { .lotus { object-fit: contain; @@ -48,62 +139,77 @@ exports[`collects complex css critical 1`] = ` .linaria::before, .linaria::after { - content: ''; + content: \\"\\"; object-fit: contain; } } +@supports (object-fit: contain) { + .lotus { + object-fit: contain; + } -.lotus { - vertical-align: top; + .linaria::before, + .linaria::after { + content: \\"\\"; + object-fit: contain; + } } +@supports (object-fit: contain) { + .lotus { + object-fit: contain; + } + .linaria::before, + .linaria::after { + content: \\"\\"; + object-fit: contain; + } +} .linaria { float: left; flex: 1; - animation: custom-animation .2s; + animation: custom-animation 0.2s; } - .linaria:hover { float: right; } - .linaria > span, .linaria + .linaria, .linaria ~ div { display: none; } - .linaria > span { display: none; } - .linaria::after { display: block; } - .lily { color: #fff; } - -[data-theme=dark] .lily { +[data-theme=\\"dark\\"] .lily { color: #000; } - -.linaria ~ div {} - -.linaria.linaria2{} - +.linaria ~ div { +} +.linaria.linaria2 { +} @keyframes custom-animation { - 0% { opacity: 0 } - 50% { opacity: 0 } - 100% { opacity: 1 } -}" + 0% { + opacity: 0; + } + 50% { + opacity: 0; + } + 100% { + opacity: 1; + } +} +" `; exports[`collects complex css other 1`] = ` -" - -@supports (object-fit: cover) { +"@supports (object-fit: cover) { .unrelated-nested { float: left; animation: custom-animation; @@ -119,21 +225,50 @@ exports[`collects complex css other 1`] = ` } .unrelated2 { - animation: custom-animation .3s; + animation: custom-animation 0.3s; } .unrelated3 { flex: 0; -}" +} +" `; -exports[`simple class name critical 1`] = `".linaria {}"`; +exports[`simple class name critical 1`] = ` +".linaria { +} +" +`; -exports[`simple class name other 1`] = `".classname {}"`; +exports[`simple class name other 1`] = ` +".classname { +} +" +`; -exports[`works with CSS combinators critical 1`] = `".linaria + span {}.linaria ~ div {}.linaria > a {}.linaria b {}"`; +exports[`works with CSS combinators critical 1`] = ` +".linaria + span { +} +.linaria ~ div { +} +.linaria > a { +} +.linaria b { +} +" +`; -exports[`works with CSS combinators other 1`] = `".other + span {}.other ~ div {}.other > a {}.other b {}"`; +exports[`works with CSS combinators other 1`] = ` +".other + span { +} +.other ~ div { +} +.other > a { +} +.other b { +} +" +`; exports[`works with global css critical 1`] = ` "body { @@ -146,11 +281,34 @@ html { h1 { font-weight: bold; -}.linaria:active {}.linaria::before {}" +} +.linaria:active { +} +.linaria::before { +} +" `; -exports[`works with global css other 1`] = `".other:active {}.other::before {}"`; +exports[`works with global css other 1`] = ` +".other:active { +} +.other::before { +} +" +`; -exports[`works with pseudo-class and pseudo-elements critical 1`] = `".linaria:active {}.linaria::before {}"`; +exports[`works with pseudo-class and pseudo-elements critical 1`] = ` +".linaria:active { +} +.linaria::before { +} +" +`; -exports[`works with pseudo-class and pseudo-elements other 1`] = `".other:active {}.other::before {}"`; +exports[`works with pseudo-class and pseudo-elements other 1`] = ` +".other:active { +} +.other::before { +} +" +`; diff --git a/src/server/__tests__/collect.test.js b/src/server/__tests__/collect.test.js index 2227f0dec..3fe120bf1 100644 --- a/src/server/__tests__/collect.test.js +++ b/src/server/__tests__/collect.test.js @@ -1,12 +1,16 @@ /* @flow */ import dedent from 'dedent'; +import prettier from 'prettier'; import collect from '../collect'; +const prettyPrint = (src: string) => + prettier.format(src, { parser: 'postcss' }); + const testCollect = (html, css) => { const { critical, other } = collect(html, css); - test('critical', () => expect(critical).toMatchSnapshot()); - test('other', () => expect(other).toMatchSnapshot()); + test('critical', () => expect(prettyPrint(critical)).toMatchSnapshot()); + test('other', () => expect(prettyPrint(other)).toMatchSnapshot()); }; const html = dedent` @@ -202,6 +206,6 @@ describe('works with global css', () => { `; const { critical, other } = collect(html, css, globalCSS); - test('critical', () => expect(critical).toMatchSnapshot()); - test('other', () => expect(other).toMatchSnapshot()); + test('critical', () => expect(prettyPrint(critical)).toMatchSnapshot()); + test('other', () => expect(prettyPrint(other)).toMatchSnapshot()); }); diff --git a/src/server/collect.js b/src/server/collect.js index c8c32d882..00aaa6e58 100644 --- a/src/server/collect.js +++ b/src/server/collect.js @@ -18,9 +18,7 @@ const collect = ( const stylesheet = postcss.parse(css); const htmlClassesRegExp = extractClassesFromHtml(html); - // Traverse @rules, insert to critical and other and remove - // the rule from stylesheet - stylesheet.walkAtRules(rule => { + const handleAtRule = rule => { let addedToCritical = false; rule.each(childRule => { @@ -39,13 +37,18 @@ const collect = ( } else { other.append(rule); } - }); + }; stylesheet.walkRules(rule => { if (rule.parent.name === 'keyframes') { return; } + if (rule.parent.type === 'atrule') { + handleAtRule(rule.parent); + return; + } + if (rule.selector.match(htmlClassesRegExp)) { critical.append(rule); } else { @@ -71,7 +74,7 @@ const collect = ( const extractClassesFromHtml = (html: string): RegExp => { const htmlClasses = []; - const regex = /\s+class="(.*)"/gm; + const regex = /\s+class="([^"]*)"/gm; let match = regex.exec(html); while (match !== null) {