Skip to content

Commit e4da249

Browse files
Kingwlyyx990803
authored andcommitted
feat: add comments option to allow preserving comments in template (#5951)
close #5392
1 parent 51c595a commit e4da249

File tree

12 files changed

+94
-4
lines changed

12 files changed

+94
-4
lines changed

flow/compiler.js

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ declare type CompilerOptions = {
2121

2222
// runtime user-configurable
2323
delimiters?: [string, string]; // template delimiters
24+
25+
// allow user kept comments
26+
comments?: boolean
2427
};
2528

2629
declare type CompiledResult = {
@@ -151,6 +154,7 @@ declare type ASTText = {
151154
type: 3;
152155
text: string;
153156
static?: boolean;
157+
isComment?: boolean;
154158
// 2.4 ssr optimization
155159
ssrOptimizability?: number;
156160
};

flow/options.js

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ declare type ComponentOptions = {
6868
name?: string;
6969
extends?: Class<Component> | Object;
7070
delimiters?: [string, string];
71+
comments?: boolean;
7172

7273
// private
7374
_isComponent?: true;

src/compiler/codegen/index.js

+6
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,8 @@ function needsNormalization (el: ASTElement): boolean {
423423
function genNode (node: ASTNode, state: CodegenState): string {
424424
if (node.type === 1) {
425425
return genElement(node, state)
426+
} if (node.type === 3 && node.isComment) {
427+
return genComment(node)
426428
} else {
427429
return genText(node)
428430
}
@@ -435,6 +437,10 @@ export function genText (text: ASTText | ASTExpression): string {
435437
})`
436438
}
437439

440+
export function genComment (comment: ASTText): string {
441+
return `_e('${comment.text}')`
442+
}
443+
438444
function genSlot (el: ASTElement, state: CodegenState): string {
439445
const slotName = el.slotName || '"default"'
440446
const children = genChildren(el, state)

src/compiler/parser/html-parser.js

+3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ export function parseHTML (html, options) {
8282
const commentEnd = html.indexOf('-->')
8383

8484
if (commentEnd >= 0) {
85+
if (options.shouldKeepComment) {
86+
options.comment(html.substring(4, commentEnd))
87+
}
8588
advance(commentEnd + 3)
8689
continue
8790
}

src/compiler/parser/index.js

+8
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export function parse (
9090
isUnaryTag: options.isUnaryTag,
9191
canBeLeftOpenTag: options.canBeLeftOpenTag,
9292
shouldDecodeNewlines: options.shouldDecodeNewlines,
93+
shouldKeepComment: options.comments,
9394
start (tag, attrs, unary) {
9495
// check namespace.
9596
// inherit parent ns if there is one
@@ -274,6 +275,13 @@ export function parse (
274275
})
275276
}
276277
}
278+
},
279+
comment (text: string) {
280+
currentParent.children.push({
281+
type: 3,
282+
text,
283+
isComment: true
284+
})
277285
}
278286
})
279287
return root

src/core/vdom/vnode.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ export default class VNode {
6464
}
6565
}
6666

67-
export const createEmptyVNode = () => {
67+
export const createEmptyVNode = (text: string = '') => {
6868
const node = new VNode()
69-
node.text = ''
69+
node.text = text
7070
node.isComment = true
7171
return node
7272
}

src/platforms/web/entry-runtime-with-compiler.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ Vue.prototype.$mount = function (
6464

6565
const { render, staticRenderFns } = compileToFunctions(template, {
6666
shouldDecodeNewlines,
67-
delimiters: options.delimiters
67+
delimiters: options.delimiters,
68+
comments: options.comments
6869
}, this)
6970
options.render = render
7071
options.staticRenderFns = staticRenderFns
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import Vue from 'vue'
2+
3+
describe('Comments', () => {
4+
it('comments should be kept', () => {
5+
const vm = new Vue({
6+
comments: true,
7+
data () {
8+
return {
9+
foo: 1
10+
}
11+
},
12+
template: '<div><span>node1</span><!--comment1-->{{foo}}<!--comment2--></div>'
13+
}).$mount()
14+
expect(vm.$el.innerHTML).toEqual('<span>node1</span><!--comment1-->1<!--comment2-->')
15+
})
16+
})

test/unit/modules/compiler/codegen.spec.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { parse } from 'compiler/parser/index'
22
import { optimize } from 'compiler/optimizer'
33
import { generate } from 'compiler/codegen'
4-
import { isObject } from 'shared/util'
4+
import { isObject, extend } from 'shared/util'
55
import { isReservedTag } from 'web/util/index'
66
import { baseOptions } from 'web/compiler/options'
77

@@ -474,6 +474,19 @@ describe('codegen', () => {
474474
)
475475
})
476476

477+
it('generate component with comment', () => {
478+
const options = extend({
479+
comments: true
480+
}, baseOptions)
481+
const template = '<div><!--comment--></div>'
482+
const generatedCode = `with(this){return _c('div',[_e('comment')])}`
483+
484+
const ast = parse(template, options)
485+
optimize(ast, options)
486+
const res = generate(ast, options)
487+
expect(res.render).toBe(generatedCode)
488+
})
489+
477490
it('not specified ast type', () => {
478491
const res = generate(null, baseOptions)
479492
expect(res.render).toBe(`with(this){return _c("div")}`)

test/unit/modules/compiler/optimizer.spec.js

+14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { parse } from 'compiler/parser/index'
2+
import { extend } from 'shared/util'
23
import { optimize } from 'compiler/optimizer'
34
import { baseOptions } from 'web/compiler/options'
45

@@ -11,6 +12,19 @@ describe('optimizer', () => {
1112
expect(ast.children[0].static).toBe(true) // span
1213
})
1314

15+
it('simple with comment', () => {
16+
const options = extend({
17+
comments: true
18+
}, baseOptions)
19+
const ast = parse('<h1 id="section1"><span>hello world</span><!--comment--></h1>', options)
20+
optimize(ast, options)
21+
expect(ast.static).toBe(true) // h1
22+
expect(ast.staticRoot).toBe(true)
23+
expect(ast.children.length).toBe(2)
24+
expect(ast.children[0].static).toBe(true) // span
25+
expect(ast.children[1].static).toBe(true) // comment
26+
})
27+
1428
it('skip simple nodes', () => {
1529
const ast = parse('<h1 id="section1">hello</h1>', baseOptions)
1630
optimize(ast, baseOptions)

test/unit/modules/compiler/parser.spec.js

+23
Original file line numberDiff line numberDiff line change
@@ -548,4 +548,27 @@ describe('parser', () => {
548548
const ast = parse(`<script type="x/template">&gt;<foo>&lt;</script>`, options)
549549
expect(ast.children[0].text).toBe(`&gt;<foo>&lt;`)
550550
})
551+
552+
it('should ignore comments', () => {
553+
const options = extend({}, baseOptions)
554+
const ast = parse(`<div>123<!--comment here--></div>`, options)
555+
expect(ast.tag).toBe('div')
556+
expect(ast.children.length).toBe(1)
557+
expect(ast.children[0].type).toBe(3)
558+
expect(ast.children[0].text).toBe('123')
559+
})
560+
561+
it('should kept comments', () => {
562+
const options = extend({
563+
comments: true
564+
}, baseOptions)
565+
const ast = parse(`<div>123<!--comment here--></div>`, options)
566+
expect(ast.tag).toBe('div')
567+
expect(ast.children.length).toBe(2)
568+
expect(ast.children[0].type).toBe(3)
569+
expect(ast.children[0].text).toBe('123')
570+
expect(ast.children[1].type).toBe(3) // parse comment with ASTText
571+
expect(ast.children[1].isComment).toBe(true) // parse comment with ASTText
572+
expect(ast.children[1].text).toBe('comment here')
573+
})
551574
})

types/options.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export interface ComponentOptions<V extends Vue> {
5454
name?: string;
5555
extends?: ComponentOptions<Vue> | typeof Vue;
5656
delimiters?: [string, string];
57+
comments?: boolean;
5758
}
5859

5960
export interface FunctionalComponentOptions {

0 commit comments

Comments
 (0)