Subscribe on changes!

compiler-sfc: HTML comment nodes are missing from element children when the element is a Vue transition

avatar
Aug 25th 2023

Vue version

3.3.4

Link to minimal reproduction

https://github.com/Sidnioulz/vue-sfcmod/blob/feat/template/src/template/__tests__/stringify.spec.ts

Steps to reproduce

  1. Use compileTemplate to compile with the following pattern: <Transition><!-- Comment --><input /></Transition>
  2. Explore the AST
  3. Notice the absence of a children node for the comment

What is expected?

There should be a node in the children with type 3 / COMMENT, which contains the comment.

What is actually happening?

It seems that when the element node is a Vue transition, specifically, comment nodes are missing. TransitionGroup works fine, though.

System Info

No response

Any additional comments?

I'm writing a codemod engine for Vue templates and this issue prevents me from preserving comments in templates.

For repro, I have a unit test suite with a test named 'Comment inside transition'. It may have been merged to main by the time you read this, though.

Relevant code in core: https://github.com/vuejs/core/blob/main/packages/compiler-dom/__tests__/transforms/Transition.spec.ts#L150. This is intentional, though I don't understand what the harm is in preserving comments.

avatar
Aug 31st 2023

set compilerOptions.comments to true see https://vuejs.org/api/options-rendering.html#compileroptions

avatar
Aug 31st 2023

Upon checking with the option on, I still think there's a bug with transition.

Attached are two ASTs, one for <Transition><!-- Comment --><input /></Transition> and one for <form><!-- Comment --><input /></form>.

On the Transition AST, you can see that there is no child node of NodeType.COMMENT, whereas on the form AST, it's rendered.

Transition AST

{
  "type": 0,
  "children": [
    {
      "type": 1,
      "ns": 0,
      "tag": "Transition",
      "tagType": 1,
      "props": [],
      "isSelfClosing": false,
      "children": [
        {
          "type": 1,
          "ns": 0,
          "tag": "input",
          "tagType": 0,
          "props": [],
          "isSelfClosing": true,
          "children": [],
          "loc": {
            "start": {
              "column": 29,
              "line": 1,
              "offset": 28
            },
            "end": {
              "column": 38,
              "line": 1,
              "offset": 37
            },
            "source": "<input />"
          },
          "codegenNode": {
            "type": 4,
            "loc": {
              "start": {
                "column": 29,
                "line": 1,
                "offset": 28
              },
              "end": {
                "column": 38,
                "line": 1,
                "offset": 37
              },
              "source": "<input />"
            },
            "content": "_hoisted_1",
            "isStatic": false,
            "constType": 2,
            "hoisted": {
              "type": 13,
              "tag": "\"input\"",
              "patchFlag": "-1 /* HOISTED */",
              "isBlock": false,
              "disableTracking": false,
              "isComponent": false,
              "loc": {
                "start": {
                  "column": 29,
                  "line": 1,
                  "offset": 28
                },
                "end": {
                  "column": 38,
                  "line": 1,
                  "offset": 37
                },
                "source": "<input />"
              }
            }
          }
        }
      ],
      "loc": {
        "start": {
          "column": 1,
          "line": 1,
          "offset": 0
        },
        "end": {
          "column": 51,
          "line": 1,
          "offset": 50
        },
        "source": "<Transition><!-- Comment --><input /></Transition>"
      },
      "codegenNode": {
        "type": 13,
        "children": {
          "type": 15,
          "loc": {
            "start": {
              "column": 1,
              "line": 1,
              "offset": 0
            },
            "end": {
              "column": 51,
              "line": 1,
              "offset": 50
            },
            "source": "<Transition><!-- Comment --><input /></Transition>"
          },
          "properties": [
            {
              "type": 16,
              "loc": {
                "source": "",
                "start": {
                  "line": 1,
                  "column": 1,
                  "offset": 0
                },
                "end": {
                  "line": 1,
                  "column": 1,
                  "offset": 0
                }
              },
              "key": {
                "type": 4,
                "loc": {
                  "source": "",
                  "start": {
                    "line": 1,
                    "column": 1,
                    "offset": 0
                  },
                  "end": {
                    "line": 1,
                    "column": 1,
                    "offset": 0
                  }
                },
                "content": "default",
                "isStatic": true,
                "constType": 3
              },
              "value": {
                "type": 18,
                "returns": [
                  {
                    "type": 1,
                    "ns": 0,
                    "tag": "input",
                    "tagType": 0,
                    "props": [],
                    "isSelfClosing": true,
                    "children": [],
                    "loc": {
                      "start": {
                        "column": 29,
                        "line": 1,
                        "offset": 28
                      },
                      "end": {
                        "column": 38,
                        "line": 1,
                        "offset": 37
                      },
                      "source": "<input />"
                    },
                    "codegenNode": {
                      "type": 4,
                      "loc": {
                        "start": {
                          "column": 29,
                          "line": 1,
                          "offset": 28
                        },
                        "end": {
                          "column": 38,
                          "line": 1,
                          "offset": 37
                        },
                        "source": "<input />"
                      },
                      "content": "_hoisted_1",
                      "isStatic": false,
                      "constType": 2,
                      "hoisted": {
                        "type": 13,
                        "tag": "\"input\"",
                        "patchFlag": "-1 /* HOISTED */",
                        "isBlock": false,
                        "disableTracking": false,
                        "isComponent": false,
                        "loc": {
                          "start": {
                            "column": 29,
                            "line": 1,
                            "offset": 28
                          },
                          "end": {
                            "column": 38,
                            "line": 1,
                            "offset": 37
                          },
                          "source": "<input />"
                        }
                      }
                    }
                  }
                ],
                "newline": false,
                "isSlot": true,
                "loc": {
                  "start": {
                    "column": 29,
                    "line": 1,
                    "offset": 28
                  },
                  "end": {
                    "column": 38,
                    "line": 1,
                    "offset": 37
                  },
                  "source": "<input />"
                }
              }
            },
            {
              "type": 16,
              "loc": {
                "source": "",
                "start": {
                  "line": 1,
                  "column": 1,
                  "offset": 0
                },
                "end": {
                  "line": 1,
                  "column": 1,
                  "offset": 0
                }
              },
              "key": {
                "type": 4,
                "loc": {
                  "source": "",
                  "start": {
                    "line": 1,
                    "column": 1,
                    "offset": 0
                  },
                  "end": {
                    "line": 1,
                    "column": 1,
                    "offset": 0
                  }
                },
                "content": "_",
                "isStatic": true,
                "constType": 3
              },
              "value": {
                "type": 4,
                "loc": {
                  "source": "",
                  "start": {
                    "line": 1,
                    "column": 1,
                    "offset": 0
                  },
                  "end": {
                    "line": 1,
                    "column": 1,
                    "offset": 0
                  }
                },
                "content": "1 /* STABLE */",
                "isStatic": false,
                "constType": 0
              }
            }
          ]
        },
        "isBlock": true,
        "disableTracking": false,
        "isComponent": true,
        "loc": {
          "start": {
            "column": 1,
            "line": 1,
            "offset": 0
          },
          "end": {
            "column": 51,
            "line": 1,
            "offset": 50
          },
          "source": "<Transition><!-- Comment --><input /></Transition>"
        }
      }
    }
  ],
  "helpers": {},
  "components": [],
  "directives": [],
  "hoists": [
    {
      "type": 13,
      "tag": "\"input\"",
      "patchFlag": "-1 /* HOISTED */",
      "isBlock": false,
      "disableTracking": false,
      "isComponent": false,
      "loc": {
        "start": {
          "column": 29,
          "line": 1,
          "offset": 28
        },
        "end": {
          "column": 38,
          "line": 1,
          "offset": 37
        },
        "source": "<input />"
      }
    }
  ],
  "imports": [],
  "cached": 0,
  "temps": 0,
  "codegenNode": {
    "type": 13,
    "children": {
      "type": 15,
      "loc": {
        "start": {
          "column": 1,
          "line": 1,
          "offset": 0
        },
        "end": {
          "column": 51,
          "line": 1,
          "offset": 50
        },
        "source": "<Transition><!-- Comment --><input /></Transition>"
      },
      "properties": [
        {
          "type": 16,
          "loc": {
            "source": "",
            "start": {
              "line": 1,
              "column": 1,
              "offset": 0
            },
            "end": {
              "line": 1,
              "column": 1,
              "offset": 0
            }
          },
          "key": {
            "type": 4,
            "loc": {
              "source": "",
              "start": {
                "line": 1,
                "column": 1,
                "offset": 0
              },
              "end": {
                "line": 1,
                "column": 1,
                "offset": 0
              }
            },
            "content": "default",
            "isStatic": true,
            "constType": 3
          },
          "value": {
            "type": 18,
            "returns": [
              {
                "type": 1,
                "ns": 0,
                "tag": "input",
                "tagType": 0,
                "props": [],
                "isSelfClosing": true,
                "children": [],
                "loc": {
                  "start": {
                    "column": 29,
                    "line": 1,
                    "offset": 28
                  },
                  "end": {
                    "column": 38,
                    "line": 1,
                    "offset": 37
                  },
                  "source": "<input />"
                },
                "codegenNode": {
                  "type": 4,
                  "loc": {
                    "start": {
                      "column": 29,
                      "line": 1,
                      "offset": 28
                    },
                    "end": {
                      "column": 38,
                      "line": 1,
                      "offset": 37
                    },
                    "source": "<input />"
                  },
                  "content": "_hoisted_1",
                  "isStatic": false,
                  "constType": 2,
                  "hoisted": {
                    "type": 13,
                    "tag": "\"input\"",
                    "patchFlag": "-1 /* HOISTED */",
                    "isBlock": false,
                    "disableTracking": false,
                    "isComponent": false,
                    "loc": {
                      "start": {
                        "column": 29,
                        "line": 1,
                        "offset": 28
                      },
                      "end": {
                        "column": 38,
                        "line": 1,
                        "offset": 37
                      },
                      "source": "<input />"
                    }
                  }
                }
              }
            ],
            "newline": false,
            "isSlot": true,
            "loc": {
              "start": {
                "column": 29,
                "line": 1,
                "offset": 28
              },
              "end": {
                "column": 38,
                "line": 1,
                "offset": 37
              },
              "source": "<input />"
            }
          }
        },
        {
          "type": 16,
          "loc": {
            "source": "",
            "start": {
              "line": 1,
              "column": 1,
              "offset": 0
            },
            "end": {
              "line": 1,
              "column": 1,
              "offset": 0
            }
          },
          "key": {
            "type": 4,
            "loc": {
              "source": "",
              "start": {
                "line": 1,
                "column": 1,
                "offset": 0
              },
              "end": {
                "line": 1,
                "column": 1,
                "offset": 0
              }
            },
            "content": "_",
            "isStatic": true,
            "constType": 3
          },
          "value": {
            "type": 4,
            "loc": {
              "source": "",
              "start": {
                "line": 1,
                "column": 1,
                "offset": 0
              },
              "end": {
                "line": 1,
                "column": 1,
                "offset": 0
              }
            },
            "content": "1 /* STABLE */",
            "isStatic": false,
            "constType": 0
          }
        }
      ]
    },
    "isBlock": true,
    "disableTracking": false,
    "isComponent": true,
    "loc": {
      "start": {
        "column": 1,
        "line": 1,
        "offset": 0
      },
      "end": {
        "column": 51,
        "line": 1,
        "offset": 50
      },
      "source": "<Transition><!-- Comment --><input /></Transition>"
    }
  },
  "loc": {
    "start": {
      "column": 1,
      "line": 1,
      "offset": 0
    },
    "end": {
      "column": 51,
      "line": 1,
      "offset": 50
    },
    "source": "<Transition><!-- Comment --><input /></Transition>"
  },
  "filters": []
}

Form AST

{
  "type": 0,
  "children": [
    {
      "type": 1,
      "ns": 0,
      "tag": "form",
      "tagType": 0,
      "props": [],
      "isSelfClosing": false,
      "children": [
        {
          "type": 3,
          "content": " Comment ",
          "loc": {
            "start": {
              "column": 7,
              "line": 1,
              "offset": 6
            },
            "end": {
              "column": 23,
              "line": 1,
              "offset": 22
            },
            "source": "<!-- Comment -->"
          }
        },
        {
          "type": 1,
          "ns": 0,
          "tag": "input",
          "tagType": 0,
          "props": [],
          "isSelfClosing": true,
          "children": [],
          "loc": {
            "start": {
              "column": 23,
              "line": 1,
              "offset": 22
            },
            "end": {
              "column": 32,
              "line": 1,
              "offset": 31
            },
            "source": "<input />"
          },
          "codegenNode": {
            "type": 4,
            "loc": {
              "start": {
                "column": 23,
                "line": 1,
                "offset": 22
              },
              "end": {
                "column": 32,
                "line": 1,
                "offset": 31
              },
              "source": "<input />"
            },
            "content": "_hoisted_1",
            "isStatic": false,
            "constType": 2,
            "hoisted": {
              "type": 13,
              "tag": "\"input\"",
              "patchFlag": "-1 /* HOISTED */",
              "isBlock": false,
              "disableTracking": false,
              "isComponent": false,
              "loc": {
                "start": {
                  "column": 23,
                  "line": 1,
                  "offset": 22
                },
                "end": {
                  "column": 32,
                  "line": 1,
                  "offset": 31
                },
                "source": "<input />"
              }
            }
          }
        }
      ],
      "loc": {
        "start": {
          "column": 1,
          "line": 1,
          "offset": 0
        },
        "end": {
          "column": 39,
          "line": 1,
          "offset": 38
        },
        "source": "<form><!-- Comment --><input /></form>"
      },
      "codegenNode": {
        "type": 13,
        "tag": "\"form\"",
        "children": [
          {
            "type": 3,
            "content": " Comment ",
            "loc": {
              "start": {
                "column": 7,
                "line": 1,
                "offset": 6
              },
              "end": {
                "column": 23,
                "line": 1,
                "offset": 22
              },
              "source": "<!-- Comment -->"
            }
          },
          {
            "type": 1,
            "ns": 0,
            "tag": "input",
            "tagType": 0,
            "props": [],
            "isSelfClosing": true,
            "children": [],
            "loc": {
              "start": {
                "column": 23,
                "line": 1,
                "offset": 22
              },
              "end": {
                "column": 32,
                "line": 1,
                "offset": 31
              },
              "source": "<input />"
            },
            "codegenNode": {
              "type": 4,
              "loc": {
                "start": {
                  "column": 23,
                  "line": 1,
                  "offset": 22
                },
                "end": {
                  "column": 32,
                  "line": 1,
                  "offset": 31
                },
                "source": "<input />"
              },
              "content": "_hoisted_1",
              "isStatic": false,
              "constType": 2,
              "hoisted": {
                "type": 13,
                "tag": "\"input\"",
                "patchFlag": "-1 /* HOISTED */",
                "isBlock": false,
                "disableTracking": false,
                "isComponent": false,
                "loc": {
                  "start": {
                    "column": 23,
                    "line": 1,
                    "offset": 22
                  },
                  "end": {
                    "column": 32,
                    "line": 1,
                    "offset": 31
                  },
                  "source": "<input />"
                }
              }
            }
          }
        ],
        "isBlock": true,
        "disableTracking": false,
        "isComponent": false,
        "loc": {
          "start": {
            "column": 1,
            "line": 1,
            "offset": 0
          },
          "end": {
            "column": 39,
            "line": 1,
            "offset": 38
          },
          "source": "<form><!-- Comment --><input /></form>"
        }
      }
    }
  ],
  "helpers": {},
  "components": [],
  "directives": [],
  "hoists": [
    {
      "type": 13,
      "tag": "\"input\"",
      "patchFlag": "-1 /* HOISTED */",
      "isBlock": false,
      "disableTracking": false,
      "isComponent": false,
      "loc": {
        "start": {
          "column": 23,
          "line": 1,
          "offset": 22
        },
        "end": {
          "column": 32,
          "line": 1,
          "offset": 31
        },
        "source": "<input />"
      }
    }
  ],
  "imports": [],
  "cached": 0,
  "temps": 0,
  "codegenNode": {
    "type": 13,
    "tag": "\"form\"",
    "children": [
      {
        "type": 3,
        "content": " Comment ",
        "loc": {
          "start": {
            "column": 7,
            "line": 1,
            "offset": 6
          },
          "end": {
            "column": 23,
            "line": 1,
            "offset": 22
          },
          "source": "<!-- Comment -->"
        }
      },
      {
        "type": 1,
        "ns": 0,
        "tag": "input",
        "tagType": 0,
        "props": [],
        "isSelfClosing": true,
        "children": [],
        "loc": {
          "start": {
            "column": 23,
            "line": 1,
            "offset": 22
          },
          "end": {
            "column": 32,
            "line": 1,
            "offset": 31
          },
          "source": "<input />"
        },
        "codegenNode": {
          "type": 4,
          "loc": {
            "start": {
              "column": 23,
              "line": 1,
              "offset": 22
            },
            "end": {
              "column": 32,
              "line": 1,
              "offset": 31
            },
            "source": "<input />"
          },
          "content": "_hoisted_1",
          "isStatic": false,
          "constType": 2,
          "hoisted": {
            "type": 13,
            "tag": "\"input\"",
            "patchFlag": "-1 /* HOISTED */",
            "isBlock": false,
            "disableTracking": false,
            "isComponent": false,
            "loc": {
              "start": {
                "column": 23,
                "line": 1,
                "offset": 22
              },
              "end": {
                "column": 32,
                "line": 1,
                "offset": 31
              },
              "source": "<input />"
            }
          }
        }
      }
    ],
    "isBlock": true,
    "disableTracking": false,
    "isComponent": false,
    "loc": {
      "start": {
        "column": 1,
        "line": 1,
        "offset": 0
      },
      "end": {
        "column": 39,
        "line": 1,
        "offset": 38
      },
      "source": "<form><!-- Comment --><input /></form>"
    }
  },
  "loc": {
    "start": {
      "column": 1,
      "line": 1,
      "offset": 0
    },
    "end": {
      "column": 39,
      "line": 1,
      "offset": 38
    },
    "source": "<form><!-- Comment --><input /></form>"
  },
  "filters": []
}