diff --git a/src/compiler/compile/css/Stylesheet.ts b/src/compiler/compile/css/Stylesheet.ts index d448cda58e8e..eb284d05a5f9 100644 --- a/src/compiler/compile/css/Stylesheet.ts +++ b/src/compiler/compile/css/Stylesheet.ts @@ -9,7 +9,32 @@ function remove_css_prefix(name: string): string { return name.replace(/^-((webkit)|(moz)|(o)|(ms))-/, ''); } -const is_keyframes_node = (node: Node) => remove_css_prefix(node.name) === 'keyframes'; +const is_keyframes_node = (node: Node) => + remove_css_prefix(node.name) === 'keyframes'; + +const at_rule_has_declaration = ({ block }: Node): true => + block && + block.children && + block.children.find((node: Node) => node.type === 'Declaration'); + +function minify_declarations( + code: MagicString, + start: number, + declarations: Array +): number { + let c = start; + + declarations.forEach((declaration, i) => { + const separator = i > 0 ? ';' : ''; + if ((declaration.node.start - c) > separator.length) { + code.overwrite(c, declaration.node.start, separator); + } + declaration.minify(code); + c = declaration.node.end; + }); + + return c; +} // https://github.com/darkskyapp/string-hash/blob/master/index.js function hash(str: string): string { @@ -64,16 +89,7 @@ class Rule { code.remove(c, this.node.block.start); c = this.node.block.start + 1; - this.declarations.forEach((declaration, i) => { - const separator = i > 0 ? ';' : ''; - if ((declaration.node.start - c) > separator.length) { - code.overwrite(c, declaration.node.start, separator); - } - - declaration.minify(code); - - c = declaration.node.end; - }); + c = minify_declarations(code, c, this.declarations) code.remove(c, this.node.block.end - 1); } @@ -141,10 +157,12 @@ class Declaration { class Atrule { node: Node; children: Array; + declarations: Array; constructor(node: Node) { this.node = node; this.children = []; + this.declarations = []; } apply(node: Element, stack: Element[]) { @@ -179,11 +197,6 @@ class Atrule { }); code.remove(c, this.node.block.start); - } else if (is_keyframes_node(this.node)) { - let c = this.node.start + this.node.name.length + 1; - if (this.node.expression.start - c > 1) code.overwrite(c, this.node.expression.start, ' '); - c = this.node.expression.end; - if (this.node.block.start - c > 0) code.remove(c, this.node.block.start); } else if (this.node.name === 'supports') { let c = this.node.start + 9; if (this.node.expression.start - c > 1) code.overwrite(c, this.node.expression.start, ' '); @@ -192,12 +205,26 @@ class Atrule { c = query.end; }); code.remove(c, this.node.block.start); + } else { + let c = this.node.start + this.node.name.length + 1; + if(this.node.expression) { + if (this.node.expression.start - c > 1) code.overwrite(c, this.node.expression.start, ' '); + c = this.node.expression.end; + } + if (this.node.block && this.node.block.start - c > 0) { + code.remove(c, this.node.block.start); + } } // TODO other atrules if (this.node.block) { let c = this.node.block.start + 1; + if (this.declarations.length) { + c = minify_declarations(code, c, this.declarations); + // if the atrule has children, leave the last declaration semicolon alone + if (this.children.length) c++; + } this.children.forEach(child => { if (child.is_used(dev)) { @@ -296,6 +323,11 @@ export default class Stylesheet { this.keyframes.set(expression.name, `${this.id}-${expression.name}`); } }); + } else if (at_rule_has_declaration(node)) { + const at_rule_declarations = node.block.children + .filter(node => node.type === 'Declaration') + .map(node => new Declaration(node)); + atrule.declarations.push(...at_rule_declarations); } current_atrule = atrule; diff --git a/test/css/samples/supports-charset/expected.css b/test/css/samples/supports-charset/expected.css new file mode 100644 index 000000000000..55cfd4ea2dd9 --- /dev/null +++ b/test/css/samples/supports-charset/expected.css @@ -0,0 +1 @@ +@charset "utf-8"; \ No newline at end of file diff --git a/test/css/samples/supports-charset/input.svelte b/test/css/samples/supports-charset/input.svelte new file mode 100644 index 000000000000..25704d3eb454 --- /dev/null +++ b/test/css/samples/supports-charset/input.svelte @@ -0,0 +1,3 @@ + diff --git a/test/css/samples/supports-font-face/expected.css b/test/css/samples/supports-font-face/expected.css new file mode 100644 index 000000000000..652ecb1dc2af --- /dev/null +++ b/test/css/samples/supports-font-face/expected.css @@ -0,0 +1 @@ +@font-face{font-family:MyHelvetica;src:local('Helvetica Neue Bold'), local('HelveticaNeue-Bold'), url(MgOpenModernaBold.ttf);font-weight:bold} \ No newline at end of file diff --git a/test/css/samples/supports-font-face/input.svelte b/test/css/samples/supports-font-face/input.svelte new file mode 100644 index 000000000000..3ed82008bf7f --- /dev/null +++ b/test/css/samples/supports-font-face/input.svelte @@ -0,0 +1,7 @@ + diff --git a/test/css/samples/supports-import/expected.css b/test/css/samples/supports-import/expected.css new file mode 100644 index 000000000000..485d9d272f09 --- /dev/null +++ b/test/css/samples/supports-import/expected.css @@ -0,0 +1 @@ +@import 'custom.css';@import "common.css" screen;@import url(chrome://communicator/skin/);@import url(fineprint.css) print;@import url(landscape.css) screen and (orientation:landscape);@import url(red.css) (min-width:400px); \ No newline at end of file diff --git a/test/css/samples/supports-import/input.svelte b/test/css/samples/supports-import/input.svelte new file mode 100644 index 000000000000..dccfc4cb9582 --- /dev/null +++ b/test/css/samples/supports-import/input.svelte @@ -0,0 +1,8 @@ + diff --git a/test/css/samples/supports-namespace/expected.css b/test/css/samples/supports-namespace/expected.css new file mode 100644 index 000000000000..7ca9f4f23d13 --- /dev/null +++ b/test/css/samples/supports-namespace/expected.css @@ -0,0 +1 @@ +@namespace url(http://www.w3.org/1999/xhtml);@namespace svg url(http://www.w3.org/2000/svg);a{color:blue}svg|a{color:green}*|a{color:red} \ No newline at end of file diff --git a/test/css/samples/supports-namespace/input.svelte b/test/css/samples/supports-namespace/input.svelte new file mode 100644 index 000000000000..6322ac631011 --- /dev/null +++ b/test/css/samples/supports-namespace/input.svelte @@ -0,0 +1,19 @@ + diff --git a/test/css/samples/supports-nested-page/expected.css b/test/css/samples/supports-nested-page/expected.css new file mode 100644 index 000000000000..d526b5798952 --- /dev/null +++ b/test/css/samples/supports-nested-page/expected.css @@ -0,0 +1 @@ +@page vertical{size:A4 portrait;@top-center{content:"Vertical"}}@page :right{@top-center{content:"Preliminary edition"}@bottom-center{content:counter(page)}}@page :first{color:green;font-size:20pt;@top-left{content:"foo";color:blue}@top-right{content:"bar"}} \ No newline at end of file diff --git a/test/css/samples/supports-nested-page/input.svelte b/test/css/samples/supports-nested-page/input.svelte new file mode 100644 index 000000000000..a36c8263ceb7 --- /dev/null +++ b/test/css/samples/supports-nested-page/input.svelte @@ -0,0 +1,32 @@ + diff --git a/test/css/samples/supports-page/expected.css b/test/css/samples/supports-page/expected.css new file mode 100644 index 000000000000..6978c3ecec05 --- /dev/null +++ b/test/css/samples/supports-page/expected.css @@ -0,0 +1 @@ +@page{margin:1cm;size:A4;bleed:7pt} \ No newline at end of file diff --git a/test/css/samples/supports-page/input.svelte b/test/css/samples/supports-page/input.svelte new file mode 100644 index 000000000000..70c089c35687 --- /dev/null +++ b/test/css/samples/supports-page/input.svelte @@ -0,0 +1,7 @@ +