From f25a995f7bf9f1bc4d4b86d465e66fb88135909a Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Sat, 21 Aug 2021 00:05:58 +0800 Subject: [PATCH] collapse whitespace in class and style attributes (#6613) --- src/compiler/compile/nodes/Element.ts | 23 ++++ .../collapse-element-class-name/expected.js | 114 ++++++++++++++++++ .../collapse-element-class-name/input.svelte | 41 +++++++ .../_expected.html | 5 +- 4 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 test/js/samples/collapse-element-class-name/expected.js create mode 100644 test/js/samples/collapse-element-class-name/input.svelte diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index dbde8f1b2d..837a0296d0 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -96,6 +96,8 @@ const react_attributes = new Map([ ['htmlFor', 'for'] ]); +const attributes_to_compact_whitespace = ['class', 'style']; + function get_namespace(parent: Element, element: Element, explicit_namespace: string) { const parent_element = parent.find_nearest(/^Element/); @@ -241,6 +243,8 @@ export default class Element extends Node { this.validate(); + this.optimise(); + component.apply_stylesheet(this); } @@ -750,6 +754,25 @@ export default class Element extends Node { get slot_template_name() { return this.attributes.find(attribute => attribute.name === 'slot').get_static_value() as string; } + + optimise() { + attributes_to_compact_whitespace.forEach(attribute_name => { + const attribute = this.attributes.find(a => a.name === attribute_name); + if (attribute && !attribute.is_true) { + attribute.chunks.forEach((chunk, index) => { + if (chunk.type === 'Text') { + let data = chunk.data.replace(/[\s\n\t]+/g, ' '); + if (index === 0) { + data = data.trimLeft(); + } else if (index === attribute.chunks.length - 1) { + data = data.trimRight(); + } + chunk.data = data; + } + }); + } + }); + } } function should_have_attribute( diff --git a/test/js/samples/collapse-element-class-name/expected.js b/test/js/samples/collapse-element-class-name/expected.js new file mode 100644 index 0000000000..a55affe76e --- /dev/null +++ b/test/js/samples/collapse-element-class-name/expected.js @@ -0,0 +1,114 @@ +/* generated by Svelte vX.Y.Z */ +import { + SvelteComponent, + assign, + attr, + compute_rest_props, + create_component, + destroy_component, + detach, + element, + exclude_internal_props, + init, + insert, + mount_component, + safe_not_equal, + space, + transition_in, + transition_out +} from "svelte/internal"; + +import Component from "./Component.svelte"; + +function create_fragment(ctx) { + let div; + let div_class_value; + let div_style_value; + let div_other_value; + let t; + let component; + let current; + + component = new Component({ + props: { + class: "\n\t\tbutton\n\t\tbutton--size--" + /*size*/ ctx[0] + "\n\t\tbutton--theme--" + /*theme*/ ctx[1] + "\n \t" + (/*$$restProps*/ ctx[2].class || ''), + style: "\n\t\tcolor: green;\n\t\tbackground: white;\n\t\tfont-size: " + /*size*/ ctx[0] + ";\n \ttransform: " + /*$$restProps*/ ctx[2].scale + " " + /*$$restProps*/ ctx[2].rotate + ";\n\t\t" + /*$$restProps*/ ctx[2].styles, + other: "\n\t\tbutton\n\t\tbutton--size--" + /*size*/ ctx[0] + "\n\t\tbutton--theme--" + /*theme*/ ctx[1] + "\n \t" + (/*$$restProps*/ ctx[2].class || '') + } + }); + + return { + c() { + div = element("div"); + t = space(); + create_component(component.$$.fragment); + attr(div, "class", div_class_value = "button button--size--" + /*size*/ ctx[0] + " button--theme--" + /*theme*/ ctx[1] + " " + (/*$$restProps*/ ctx[2].class || '')); + attr(div, "style", div_style_value = "color: green; background: white; font-size: " + /*size*/ ctx[0] + "; transform: " + /*$$restProps*/ ctx[2].scale + " " + /*$$restProps*/ ctx[2].rotate + "; " + /*$$restProps*/ ctx[2].styles); + attr(div, "other", div_other_value = "\n\t\tbutton\n\t\tbutton--size--" + /*size*/ ctx[0] + "\n\t\tbutton--theme--" + /*theme*/ ctx[1] + "\n \t" + (/*$$restProps*/ ctx[2].class || '')); + }, + m(target, anchor) { + insert(target, div, anchor); + insert(target, t, anchor); + mount_component(component, target, anchor); + current = true; + }, + p(ctx, [dirty]) { + if (!current || dirty & /*size, theme, $$restProps*/ 7 && div_class_value !== (div_class_value = "button button--size--" + /*size*/ ctx[0] + " button--theme--" + /*theme*/ ctx[1] + " " + (/*$$restProps*/ ctx[2].class || ''))) { + attr(div, "class", div_class_value); + } + + if (!current || dirty & /*size, $$restProps*/ 5 && div_style_value !== (div_style_value = "color: green; background: white; font-size: " + /*size*/ ctx[0] + "; transform: " + /*$$restProps*/ ctx[2].scale + " " + /*$$restProps*/ ctx[2].rotate + "; " + /*$$restProps*/ ctx[2].styles)) { + attr(div, "style", div_style_value); + } + + if (!current || dirty & /*size, theme, $$restProps*/ 7 && div_other_value !== (div_other_value = "\n\t\tbutton\n\t\tbutton--size--" + /*size*/ ctx[0] + "\n\t\tbutton--theme--" + /*theme*/ ctx[1] + "\n \t" + (/*$$restProps*/ ctx[2].class || ''))) { + attr(div, "other", div_other_value); + } + + const component_changes = {}; + if (dirty & /*size, theme, $$restProps*/ 7) component_changes.class = "\n\t\tbutton\n\t\tbutton--size--" + /*size*/ ctx[0] + "\n\t\tbutton--theme--" + /*theme*/ ctx[1] + "\n \t" + (/*$$restProps*/ ctx[2].class || ''); + if (dirty & /*size, $$restProps*/ 5) component_changes.style = "\n\t\tcolor: green;\n\t\tbackground: white;\n\t\tfont-size: " + /*size*/ ctx[0] + ";\n \ttransform: " + /*$$restProps*/ ctx[2].scale + " " + /*$$restProps*/ ctx[2].rotate + ";\n\t\t" + /*$$restProps*/ ctx[2].styles; + if (dirty & /*size, theme, $$restProps*/ 7) component_changes.other = "\n\t\tbutton\n\t\tbutton--size--" + /*size*/ ctx[0] + "\n\t\tbutton--theme--" + /*theme*/ ctx[1] + "\n \t" + (/*$$restProps*/ ctx[2].class || ''); + component.$set(component_changes); + }, + i(local) { + if (current) return; + transition_in(component.$$.fragment, local); + current = true; + }, + o(local) { + transition_out(component.$$.fragment, local); + current = false; + }, + d(detaching) { + if (detaching) detach(div); + if (detaching) detach(t); + destroy_component(component, detaching); + } + }; +} + +function instance($$self, $$props, $$invalidate) { + const omit_props_names = ["size","theme"]; + let $$restProps = compute_rest_props($$props, omit_props_names); + let { size } = $$props; + let { theme } = $$props; + + $$self.$$set = $$new_props => { + $$props = assign(assign({}, $$props), exclude_internal_props($$new_props)); + $$invalidate(2, $$restProps = compute_rest_props($$props, omit_props_names)); + if ('size' in $$new_props) $$invalidate(0, size = $$new_props.size); + if ('theme' in $$new_props) $$invalidate(1, theme = $$new_props.theme); + }; + + return [size, theme, $$restProps]; +} + +class Component_1 extends SvelteComponent { + constructor(options) { + super(); + init(this, options, instance, create_fragment, safe_not_equal, { size: 0, theme: 1 }); + } +} + +export default Component_1; \ No newline at end of file diff --git a/test/js/samples/collapse-element-class-name/input.svelte b/test/js/samples/collapse-element-class-name/input.svelte new file mode 100644 index 0000000000..a4cb283778 --- /dev/null +++ b/test/js/samples/collapse-element-class-name/input.svelte @@ -0,0 +1,41 @@ + + +
+ + \ No newline at end of file diff --git a/test/server-side-rendering/samples/spread-attributes-white-space/_expected.html b/test/server-side-rendering/samples/spread-attributes-white-space/_expected.html index a73bb17e8c..24473a7b12 100644 --- a/test/server-side-rendering/samples/spread-attributes-white-space/_expected.html +++ b/test/server-side-rendering/samples/spread-attributes-white-space/_expected.html @@ -2,7 +2,4 @@ bar "> - \ No newline at end of file + \ No newline at end of file