Repository: vuejs/vue
Pull request: fix: whitespace: 'condense' should honor <pre> tag as well

<!--
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
- [ ] 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:**

- [x] 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)
- [x] All tests are passing: https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#development-setup
- [x] 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/compiler/parser/index.js
patch: @@ -351,7 +351,7 @@ export function parse (
         text = preserveWhitespace ? ' ' : ''
       }
       if (text) {
-        if (whitespaceOption === 'condense') {
+        if (!inPre && whitespaceOption === 'condense') {
           // condense consecutive whitespaces into single space
           text = text.replace(whitespaceRE, ' ')
         }

filename: test/unit/modules/compiler/parser.spec.js
patch: @@ -820,12 +820,14 @@ describe('parser', () => {
     expect(ast.children[3].children[0].text).toBe('.\n  Have fun!\n')
   })
 
+  const condenseOptions = extend({
+    whitespace: 'condense',
+    // should be ignored when whitespace is specified
+    preserveWhitespace: false
+  }, baseOptions)
+
   it(`whitespace: 'condense'`, () => {
-    const options = extend({
-      whitespace: 'condense',
-      // should be ignored when whitespace is specified
-      preserveWhitespace: false
-    }, baseOptions)
+    const options = extend({}, condenseOptions)
     const ast = parse('<p>\n  Welcome to <b>Vue.js</b>    <i>world</i>  \n  <span>.\n  Have fun!\n</span></p>', options)
     expect(ast.tag).toBe('p')
     expect(ast.children.length).toBe(5)
@@ -842,4 +844,41 @@ describe('parser', () => {
     expect(ast.children[4].tag).toBe('span')
     expect(ast.children[4].children[0].text).toBe('. Have fun! ')
   })
+
+  it(`preserve whitespace in <pre> tag with whitespace: 'condense'`, function () {
+    const options = extend({}, condenseOptions)
+    const ast = parse('<pre><code>  \n<span>hi</span>\n  </code><span> </span></pre>', options)
+    const code = ast.children[0]
+    expect(code.children[0].type).toBe(3)
+    expect(code.children[0].text).toBe('  \n')
+    expect(code.children[2].type).toBe(3)
+    expect(code.children[2].text).toBe('\n  ')
+
+    const span = ast.children[1]
+    expect(span.children[0].type).toBe(3)
+    expect(span.children[0].text).toBe(' ')
+  })
+
+  it(`ignore the first newline in <pre> tag with whitespace: 'condense'`, function () {
+    const options = extend({}, condenseOptions)
+    const ast = parse('<div><pre>\nabc</pre>\ndef<pre>\n\nabc</pre></div>', options)
+    const pre = ast.children[0]
+    expect(pre.children[0].type).toBe(3)
+    expect(pre.children[0].text).toBe('abc')
+    const text = ast.children[1]
+    expect(text.type).toBe(3)
+    expect(text.text).toBe(' def')
+    const pre2 = ast.children[2]
+    expect(pre2.children[0].type).toBe(3)
+    expect(pre2.children[0].text).toBe('\nabc')
+  })
+
+  it(`keep first newline after unary tag in <pre> with whitespace: 'condense'`, () => {
+    const options = extend({}, condenseOptions)
+    const ast = parse('<pre>abc<input>\ndef</pre>', options)
+    expect(ast.children[1].type).toBe(1)
+    expect(ast.children[1].tag).toBe('input')
+    expect(ast.children[2].type).toBe(3)
+    expect(ast.children[2].text).toBe('\ndef')
+  })
 })