vite icon indicating copy to clipboard operation
vite copied to clipboard

Component Framework global components are not correctly loaded when using pug + scoped style

Open Shinigami92 opened this issue 1 year ago • 3 comments

Describe the bug

With Quasar I'm using the @quasar/vite-plugin v1.1.1 and the plugin property autoImportComponentCase: 'pascal' When using this in combination with a template lang=pug and style scoped I get warnings and a blank white page with no rendered content.

At Quasar Land (Discord) we (@yusufkandemir, @patak-dev and me) already found out that there is a new incompatibility coming from @vitejs/plugin-vue >= v3 and that the template also gets applied a scoped query param where as when not using pug it does not.

image https://discord.com/channels/415874313728688138/902518756436226079/1002122942852902964

image https://discord.com/channels/415874313728688138/902518756436226079/1002127704138715176


Current workaround: Using a css class named like the component and use that instead of scoped keyword.

Reproduction

https://stackblitz.com/edit/vitejs-vite-llrb6t?file=src%2FApp.vue,package.json,src%2Fmain.ts,vite.config.ts&terminal=dev

System Info

System:
    OS: macOS 12.4
    CPU: (10) arm64 Apple M1 Max
    Memory: 4.91 GB / 32.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 18.4.0 - ~/.nvm/versions/node/v18.4.0/bin/node
    npm: 8.12.1 - ~/.nvm/versions/node/v18.4.0/bin/npm
  Browsers:
    Chrome: 103.0.5060.134
    Safari: 15.5
  npmPackages:
    @vitejs/plugin-vue: ~3.0.1 => 3.0.1 
    vite: ~3.0.3 => 3.0.3

Used Package Manager

pnpm

Logs

No response

Validations

Shinigami92 avatar Jul 28 '22 10:07 Shinigami92

The value of the autoImportComponentCase doesn't affect the behavior. (as long as you match it in your code of course)

Also, let me move over my text from Discord to here so that it's more readable and copyable.

If you use scoped css but not pug, it still works.

For some reason, when you pug and scoped css at the same time, the template also gets &scoped=... in the resource URL. And, the regex targeting the template can't match it, so the auto-loading gets disabled on that template.

HTML + Regular SCSS: template: http://localhost:5173/src/App.vue style: http://localhost:5173/src/App.vue?vue&type=style&index=0&lang.scss

HTML + Scoped SCSS: template: http://localhost:5173/src/App.vue style: http://localhost:5173/src/App.vue?vue&type=style&index=0&scoped=7a7a37b1&lang.scss

Pug + Regular SCSS: template: http://localhost:5173/src/App.vue?vue&type=template&lang.js style: http://localhost:5173/src/App.vue?vue&type=style&index=0&lang.scss

Pug + Scoped SCSS: template: http://localhost:5173/src/App.vue?vue&type=template&scoped=7a7a37b1&lang.js style: http://localhost:5173/src/App.vue?vue&type=style&index=0&scoped=7a7a37b1&lang.scss

The solution is to update to regex to allow it, but the question is whether this behavior of Vite is intended or not.

https://github.com/quasarframework/quasar/blob/bb44635a8e97210937eb3539968a6b6aa37ae778/vite-plugin/src/vue-transform.js#L6

export const vueTransformRegex = /\.vue(?:\?vue&type=(?:template|script)(?:&setup=true)?&lang\.(?:j|t)s)?$/

When using Pug + Scopes SCSS, if it's intended for the template resource query to also get scoped, I'll update the regex above to allow it. Do you know if it's intended?

Also, by any chance, do you know if there is a more future-proof solution than just doing this in our Vite plugin:

transform (src, id) {
  if (vueTransformRegex.test(id) === true) {
    return {
      code: vueTransform(src, opts.autoImportComponentCase),
      map: null // provide source map if available
    }
  } else if // ...

or perhaps loosen up the regex, or have a better way of following the changes on this kind of stuff? Any input is welcome!

yusufkandemir avatar Jul 28 '22 10:07 yusufkandemir

the question is whether this behavior of Vite is intended or not.

This is intended. When lang or src attribute is not defined on <template>, it is inlined in the main request. So the URL ends with .vue. https://github.com/vitejs/vite/blob/cd69358177dd3d93bc19084ad0ee09f6b85c047c/packages/plugin-vue/src/main.ts#L253-L255 When using pug, it is not inlined and scope=$id was added for build --watch (https://github.com/vitejs/vite/pull/7989). When the template is inlined in the main request, this is not needed. So pug one includes scoped=7a7a37b1 but html one does not include it.

do you know if there is a more future-proof solution than just doing this in our Vite plugin

I think doing something similar to this would be more future-proof. https://github.com/vitejs/vite/blob/cd69358177dd3d93bc19084ad0ee09f6b85c047c/packages/plugin-vue/src/index.ts#L180-L197

const f = id => {
  if (id.endsWith('.vue')) return true

  const { query } = parseVueRequest(id)
  return (
    query.vue &&
    (query.type === 'script' || query.type === 'template')) &&
    ('lang.ts' in query || 'lang.js' in query)
  )
}

sapphi-red avatar Jul 29 '22 04:07 sapphi-red

@sapphi-red I wonder if plugin-vue should export some utilities to handle these cases. It could be easier to change internals later

patak-dev avatar Jul 29 '22 06:07 patak-dev