vite-plugin-vue icon indicating copy to clipboard operation
vite-plugin-vue copied to clipboard

TypeScript types in pug templates get not removed

Open sschneider-ihre-pvs opened this issue 3 years ago • 16 comments

Describe the bug

Having something like

:filter-by="[keyName as string ?? 'key', valueName as string ?? 'value']"

in a pug template is fine with volar, but vite doesn't seem to expect that kind of thing and compiles it to js as is

"filter-by": [$props.keyName as string ?? 'key', $props.valueName as string ?? 'value'],

which leads to some cryptic error messages like

SyntaxError: missing ] after element list

Reproduction

Hello World

System Info

System:
    OS: Windows 10 10.0.19042
    CPU: (16) x64 Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz
    Memory: 1.32 GB / 15.75 GB
  Binaries:
    Node: 16.14.2
    Yarn: 1.22.4
    npm: 8.5.0
  Browsers:
    Edge: Spartan (44.19041.1023.0), Chromium (98.0.1108.62)
    Internet Explorer: 11.0.19041.1
  npmPackages:
    @vitejs/plugin-vue: ^2.3.1 => 2.3.1

Used Package Manager

npm

Logs

No response

Validations

sschneider-ihre-pvs avatar Apr 29 '22 05:04 sschneider-ihre-pvs

Is this a bug in Vite or in @vue/compiler-sfc?

Shinigami92 avatar Apr 29 '22 09:04 Shinigami92

It seems a bug in Vite. When this condition is met, it is transpiled here. https://github.com/vitejs/vite/blob/f3d15f106f378c3850b62fbebd69fc8f7c7f944b/packages/plugin-vue/src/main.ts#L229 https://github.com/vitejs/vite/blob/f3d15f106f378c3850b62fbebd69fc8f7c7f944b/packages/plugin-vue/src/main.ts#L193-L208

But if it does not meet, it is not transpiled. https://github.com/vitejs/vite/blob/f3d15f106f378c3850b62fbebd69fc8f7c7f944b/packages/plugin-vue/src/main.ts#L238-L250

So in theory, this does not work. (I did not test)

<template src="foo.html"></template> <!-- foo.html includes typescript syntax -->
<script lang="ts" setup>
export const foo = 'foo'
</script>

sapphi-red avatar May 04 '22 00:05 sapphi-red

Oh, so you would like to remove types from templates using src? I'm not sure if this is possible right now. Also that would not be a bug but a feature request, would it? 🤔 Feel free to open a PR and try to enhance this behavior.

Shinigami92 avatar May 04 '22 06:05 Shinigami92

Well, currently it is assumed that every piece of js code in the template is vanilla js. I think that if you have script lang="ts" the probability is high that you have ts syntax in the template. It seems that the possibility is currently not checked, and the statements get copied to js code. Another way could be to indicate that you can only use vanilla js in html templates.

sschneider-ihre-pvs avatar May 04 '22 06:05 sschneider-ihre-pvs

Well, currently it is assumed that every piece of js code in the template is vanilla js. I think that if you have script lang="ts" the probability is high that you have ts syntax in the template. It seems that the possibility is currently not checked, and the statements get copied to js code. Another way could be to indicate that you can only use vanilla js in html templates.

I specifically talk about template with using src I assume TypeScript types get removed if you use SFC with <script lang="ts"> together with <template lang="pug"> but without src for template

Shinigami92 avatar May 04 '22 06:05 Shinigami92

I'm not the issuer (just in case).

When a <template> is written in html and is not using external src, it gets directly in the main module. Typescript support inside <template> is supported with intention. https://github.com/vitejs/vite/blob/f3d15f106f378c3850b62fbebd69fc8f7c7f944b/packages/plugin-vue/src/template.ts#L156-L162 Typescript support for <template> written in html and not using external src relies on this part. https://github.com/vitejs/vite/blob/f3d15f106f378c3850b62fbebd69fc8f7c7f944b/packages/plugin-vue/src/main.ts#L193-L208 But when this condition is not met, the code above does not run. https://github.com/vitejs/vite/blob/f3d15f106f378c3850b62fbebd69fc8f7c7f944b/packages/plugin-vue/src/main.ts#L229 So if a <template> uses external src or it is not written in html, it does not work with typescript.

Just wanted to say, it also does not work.

sapphi-red avatar May 04 '22 06:05 sapphi-red

Ah ok, then I misunderstood. And in my case I didn't use src and it didn't get removed.

sschneider-ihre-pvs avatar May 04 '22 06:05 sschneider-ihre-pvs

That would match my pug case.

So if a

sschneider-ihre-pvs avatar May 04 '22 06:05 sschneider-ihre-pvs

This is the repro with pug and without external src. https://stackblitz.com/edit/vitejs-vite-ustutd?file=src%2Fcomponents%2FHelloWorld.vue

sapphi-red avatar May 04 '22 06:05 sapphi-red

This is the repro with pug and without external src. https://stackblitz.com/edit/vitejs-vite-ustutd?file=src%2Fcomponents%2FHelloWorld.vue

thanks for the repo, I added that to the report.

sschneider-ihre-pvs avatar May 04 '22 06:05 sschneider-ihre-pvs

can confirm I'm experiencing the same bug without src

philefstat avatar Sep 16 '22 09:09 philefstat

Same issue, typescript got not removed in pug template

Screen Shot 2023-01-16 at 15 17 33

men232 avatar Jan 16 '23 14:01 men232

In my project, when I use the combination of API options, Pug, and Vite for building, I encounter an unexpected token error due to TypeScript type assertion in the Pug template. However, when I switch to the Composition API, the error disappears.

For someone in need, I've created a Vite plugin to remove type assertions. This may help some Pug users. I'm uncertain if there are other TypeScript syntax will break Vite, but removing type assertions will solve my problem.

vite-plugin-remove-pug-type-assertion.ts

import fs from "fs"
import type { Plugin } from "vite"

const vitePluginPugBuild = (): Plugin => {
  return {
    name: "vite-plugin-remove-pug-type-assertion",
    enforce: "pre",
    apply: "build",
    load(id: string) {
      if (!id.endsWith(".vue")) return
      
      let content = fs.readFileSync(id, "utf-8")
      // Remove type assertion in pug block for vue files.
      content = content.replace(/(?<==".+)( as [\w<>|', ]+)/g, '')
      return content
    },
  }
}

export default function() {
  return vitePluginPugBuild()
}

Config your vite.config.ts:

import vue from '@vitejs/plugin-vue'
import removePugAssertion from '[some path]/vite-plugin-remove-pug-type-assertion'

export default defineConfig({
  plugins: [
    removePugAssertion(),
    vue(),
  ],
...

This is only for building Vue, not for dev server. It loads all Vue SFCs and replaces assertions only in the template block by checking if =" appears before the assertion. I don't check if the user is using Pug or HTML, but I believe it will not break HTML. Please avoid to use double quotes in your assertion, like v as "apple" | "banana". Instead, use single quotes. There may be some bugs in this plugin, and some assertions may not be detected. I hope this helps you.

Reference for .pug file (Japanese)

Nathan7139 avatar Sep 14 '23 08:09 Nathan7139

In my project, when I use the combination of API options, Pug, and Vite for building, I encounter an unexpected token error due to TypeScript type assertion in the Pug template. However, when I switch to the Composition API, the error disappears.

For someone in need, I've created a Vite plugin to remove type assertions. This may help some Pug users. I'm uncertain if there are other TypeScript syntax will break Vite, but removing type assertions will solve my problem.

vite-plugin-remove-pug-type-assertion.ts

import fs from "fs"
import type { Plugin } from "vite"

const vitePluginPugBuild = (): Plugin => {
  return {
    name: "vite-plugin-remove-pug-type-assertion",
    enforce: "pre",
    apply: "build",
    load(id: string) {
      if (!id.endsWith(".vue")) return
      
      let content = fs.readFileSync(id, "utf-8")
      // Remove type assertion in pug block for vue files.
      content = content.replace(/(?<==".+)( as [\w<>|', ]+)/g, '')
      return content
    },
  }
}

export default function() {
  return vitePluginPugBuild()
}

Config your vite.config.ts:

import vue from '@vitejs/plugin-vue'
import removePugAssertion from '[some path]/vite-plugin-remove-pug-type-assertion'

export default defineConfig({
  plugins: [
    removePugAssertion(),
    vue(),
  ],
...

This is only for building Vue, not for dev server. It loads all Vue SFCs and replaces assertions only in the template block by checking if =" appears before the assertion. I don't check if the user is using Pug or HTML, but I believe it will not break HTML. Please avoid to use double quotes in your assertion, like v as "apple" | "banana". Instead, use single quotes. There may be some bugs in this plugin, and some assertions may not be detected. I hope this helps you.

Reference for .pug file (Japanese)

Would it be possible to extend this for optional brackets? :something="v as someType | someOtherType" :something="(v as someType | someOtherType)"

hinogi avatar Apr 26 '24 07:04 hinogi

In my project, when I use the combination of API options, Pug, and Vite for building, I encounter an unexpected token error due to TypeScript type assertion in the Pug template. However, when I switch to the Composition API, the error disappears.

For someone in need, I've created a Vite plugin to remove type assertions. This may help some Pug users. I'm uncertain if there are other TypeScript syntax will break Vite, but removing type assertions will solve my problem.

vite-plugin-remove-pug-type-assertion.ts

import fs from "fs"
import type { Plugin } from "vite"

const vitePluginPugBuild = (): Plugin => {
  return {
    name: "vite-plugin-remove-pug-type-assertion",
    enforce: "pre",
    apply: "build",
    load(id: string) {
      if (!id.endsWith(".vue")) return
      
      let content = fs.readFileSync(id, "utf-8")
      // Remove type assertion in pug block for vue files.
      content = content.replace(/(?<==".+)( as [\w<>|', ]+)/g, '')
      return content
    },
  }
}

export default function() {
  return vitePluginPugBuild()
}

Config your vite.config.ts:

import vue from '@vitejs/plugin-vue'
import removePugAssertion from '[some path]/vite-plugin-remove-pug-type-assertion'

export default defineConfig({
  plugins: [
    removePugAssertion(),
    vue(),
  ],
...

This is only for building Vue, not for dev server. It loads all Vue SFCs and replaces assertions only in the template block by checking if =" appears before the assertion. I don't check if the user is using Pug or HTML, but I believe it will not break HTML. Please avoid to use double quotes in your assertion, like v as "apple" | "banana". Instead, use single quotes. There may be some bugs in this plugin, and some assertions may not be detected. I hope this helps you.

Reference for .pug file (Japanese)

image

sschneider-ihre-pvs avatar Apr 29 '24 10:04 sschneider-ihre-pvs

import { readFileSync } from 'node:fs';

export default function () {
  return {
    name: 'vite-plugin-remove-pug-type-assertion',
    enforce: 'pre',
    load(id: string) {
      if (!id.endsWith('.vue')) return;
      let content = readFileSync(id, 'utf-8');
      const regex = new RegExp(/(?<==")(.+)( as [\w<>|', ]+)/, 'g');
      while (regex.test(content)) {
        content = content.replace(regex, '$1');
      }

      return content;
    },
  };
}

I just worked on the former suggestion for a vite solution with regard to build/serve and multiple assertions in a line

sschneider-ihre-pvs avatar Apr 30 '24 08:04 sschneider-ihre-pvs