Repository: vuejs/vue
Pull request: feat(compiler): condenses staticClass whitespace (fix #12113)

Template "static" classes used to preserve whitespace after compilation, resulting in builds that had bigger file outputs with whitespace in component's `staticClass` attributes, as specified in #12113 and [this issue](https://github.com/prettier/prettier/issues/10918#issuecomment-854023245) as well.

fix #12113

<!--
Please make sure to read the Pull Request Guidelines:
https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#pull-request-guidelines
-->

<!-- PULL REQUEST TEMPLATE -->
<!-- (Update "[ ]" to "[x]" to check a box) -->

**What kind of change does this PR introduce?** (check at least one)

- [x] Bugfix
- [x] Feature
- [ ] Code style update
- [ ] Refactor
- [ ] Build-related changes
- [ ] Other, please describe:

**Does this PR introduce a breaking change?** (check one)

- [ ] Yes
- [X] No

If yes, please describe the impact and migration path for existing applications:

**The PR fulfills these requirements:**

- [ ] It's submitted to the `dev` branch for v2.x (or to a previous version branch), _not_ the `master` branch
- [ ] When resolving a specific issue, it's referenced in the PR's title (e.g. `fix #xxx[,#xxx]`, where "xxx" is the issue number)
- [ ] All tests are passing: https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#development-setup
- [ ] New/updated tests are included

If adding a **new feature**, the PR's description includes:
- [ ] A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it)

**Other information:**


Changed files:
filename: src/platforms/web/compiler/modules/class.js
patch: @@ -23,7 +23,7 @@ function transformNode (el: ASTElement, options: CompilerOptions) {
     }
   }
   if (staticClass) {
-    el.staticClass = JSON.stringify(staticClass)
+    el.staticClass = JSON.stringify(staticClass.replace(/\s+/g, ' ').trim())
   }
   const classBinding = getBindingAttr(el, 'class', false /* getStatic */)
   if (classBinding) {

filename: test/ssr/ssr-string.spec.js
patch: @@ -1351,7 +1351,7 @@ describe('SSR: renderToString', () => {
       </div>
       `
     }, result => {
-      expect(result).toContain(`<div class="a\nb"></div>`)
+      expect(result).toContain(`<div class="a b"></div>`)
       done()
     })
   })

filename: test/unit/features/directives/class.spec.js
patch: @@ -152,6 +152,39 @@ describe('Directive v-bind:class', () => {
     }).then(done)
   })
 
+  // css static classes should only contain a single space in between,
+  // as all the text inside of classes is shipped as a JS string
+  // and this could lead to useless spacing in static classes
+  it('condenses whitespace in staticClass', done => {
+    const vm = new Vue({
+      template: '<div class=" test1\ntest2\ttest3 test4   test5 \n \n \ntest6\t"></div>',
+    }).$mount()
+    expect(vm.$el.className).toBe('test1 test2 test3 test4 test5 test6')
+    done()
+  })
+
+  it('condenses whitespace in staticClass merge in a component', done => {
+    const vm = new Vue({
+      template: `
+        <component1 class="\n\t staticClass \t\n" :class="componentClass1">
+        </component1>
+      `,
+      data: {
+        componentClass1: 'componentClass1',
+      },
+      components: {
+        component1: {
+          template: '<div class="\n\t test \t\n"></div>'
+        },
+      }
+    }).$mount()
+    expect(vm.$el.className).toBe('test staticClass componentClass1')
+    vm.componentClass1 = 'c1'
+    waitForUpdate(() => {
+      expect(vm.$el.className).toBe('test staticClass c1')
+    }).then(done)
+  })
+
   // a vdom patch edge case where the user has several un-keyed elements of the
   // same tag next to each other, and toggling them.
   it('properly remove staticClass for toggling un-keyed children', done => {