Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(css): remove css-post plugin sourcemap #9914

Merged
merged 3 commits into from
Aug 30, 2022

Conversation

sapphi-red
Copy link
Member

Description

fixes #9830

/src/components/HelloWorld.vue has the sourcemap below.

{
  "version": 3,
  "mappings": "AACA;AAEA;AAAA,EACA;AAAA,IACA;AAAA,EACA;AAAA,EACA;AACA;AACA;AAAA,MACA;AAAA,IACA;AAAA,EACA;AACA",
  "names": [],
  "sources": [
    "/home/projects/mkliybgym.github/src/components/HelloWorld.vue"
  ],
  "file": "/home/projects/mkliybgym.github/src/components/HelloWorld.vue",
  "sourcesContent": [
    "<script lang=\"ts\">\nimport Vue from 'vue';\n\nexport default Vue.extend({\n  props: {\n    msg: { type: String },\n  },\n  data() {\ndebugger;\n    return {\n      count: 0,\n    };\n  },\n});\n</script>\n\n<template>\n  <div>\n    <h1>{{ msg }}</h1>\n\n    <div class=\"card\">\n      <button type=\"button\" @click=\"count++\">count is {{ count }}</button>\n      <p>\n        Edit\n        <code>components/HelloWorld.vue</code> to test HMR\n      </p>\n    </div>\n\n    <p>\n      Check out\n      <a href=\"https://vuejs.org/guide/quick-start.html#local\" target=\"_blank\"\n        >create-vue</a\n      >, the official Vue + Vite starter\n    </p>\n    <p>\n      Install\n      <a href=\"https://github.com/johnsoncodehk/volar\" target=\"_blank\">Volar</a>\n      in your IDE for a better DX\n    </p>\n    <p class=\"read-the-docs\">Click on the Vite and Vue logos to learn more</p>\n  </div>\n</template>\n\n<style lang=\"postcss\" scoped>\n.read-the-docs {\n  color: #888;\n}\n</style>\n"
  ]
}

/src/components/HelloWorld.vue?vue&type=style&index=0&scoped=true&lang.postcss has the sourcemap below.

{
  "version": 3,
  "sources": [
    "/home/projects/mkliybgym.github/src/components/HelloWorld.vue"
  ],
  "names": [],
  "mappings": ";AA4CA;EACE,WAAW;AACb",
  "file": "HelloWorld.vue",
  "sourcesContent": [
    "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.read-the-docs {\n  color: #888;\n}\n"
  ]
}

/src/components/HelloWorld.vue's sourcesContent has correct content but /src/components/HelloWorld.vue?vue&type=style&index=0&scoped=true&lang.postcss has a empty lines for non-style part.
Actually, this sourcemap comes from vite-plugin-vue2 and needs a fix on their side.
That said, vite:css-post does not need to return sourcemap as the sourcemap is injected inside CSS. So I removed it by setting map: { mappings: '' }.

Additional context


What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

Before submitting the PR, please make sure you do the following

  • Read the Contributing Guidelines.
  • Read the Pull Request Guidelines and follow the Commit Convention.
  • Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
  • Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g. fixes #123).
  • Ideally, include relevant tests that fail without this PR but pass with it.

@sapphi-red sapphi-red added feat: css p3-minor-bug An edge case that only affects very specific usage (priority) labels Aug 30, 2022
@patak-dev patak-dev merged commit c9521e7 into vitejs:main Aug 30, 2022
@sapphi-red sapphi-red deleted the fix/css-post-sourcemap branch August 30, 2022 15:28
@BenceSzalai
Copy link
Contributor

BenceSzalai commented Nov 3, 2022

For anyone trying to wrap their had around this, like I did, here's what I've figured:

  • Vite loads the css and template (as a render function) parts of single file Vue components in separate requests
  • The request for /src/components/HelloWorld.vue?vue&type=style&index=0&scoped=true&lang.postcss shows how the css part is loaded in the reproduction project linked in the original issue: Sourcemap failure on Chrome for Vue 2 components with CSS  #9830
  • The full response for the above request depends on the Accept header.
  • When Accept: "text/css" header is present, Vite simply sends the css extracted from the template + a source map. When devSourcemap: false this sourcemap is like the one from above, with the lots of \n\n\n\n\n\n\n\n\n\n\n\s. It is apparently generated wrong by vite-plugin-vue2 as also indicated here: Source missing in chrome when debugging underfin/vite-plugin-vue2#191
  • When Accept: "*/*" header is present, Vite understands that the request is coming from Vite client and should be responded to with a HMR JS file, which includes boilerplate that hooks the file up with the Vite Client, and it contains the original css from the above request in a variable.
  • When the plugins are executed against the response before sending it back by loadAndTransform() in transformRequest.ts the plugin vite:css-post comes at the end, which does the HMR wrapping when Accept: "*/*".
  • So at this point there is the original CSS with whatever SourceMap is attached to it by any other previous plugins. vite:css-post grabs this css with the SourceMap and puts it inside a JS variable within the HMR boilerplate code and returns this code for further processing by other plugins.
  • Usually plugins do changes to the response one after another and those changes are collected in the context under ctx.sourcemapChain as consecutive sourcemaps. At the end these sourcemaps are merged to generate the final sourcemap to be attached to the response.
  • However when vite:css-post decided to put the generated css into a JS variable it left the sourcemap in the context. Therefore finally the HMR JS file was returned to the browser with the sourcemap that was generated for the css file.

At this point the issue is two fold:

  • Any sourcemaps generated for the css file will not be a proper sourcemap for the HMR JS response, because that is served under an URL that corresponds to the .vue template file, so the browser expects this sourcemap to establish the relationship between the HMR JS file and the original Vue SFC, which it does not.
  • The sourcemap generated by vite-plugin-vue2 wrongly maps all lines from the original template as \n causing the browser to render these lines as blanks.

The good thing is however that the css code wrapped into a variable inside the HMR JS response already includes the sourcemap for the CSS, so there is really no need to add the same sourcemap at the end of the HMR JS file too.

This is what the fix relies on: by not only returning the new HMR JS code, but an empty dummy source map as well, it forces the source maps collected in the context so far to be ignored when the source maps are combined. The empty sourcemap masks the others, so no sitemap is generated at the end so the response is sent to the browser as it is, without additional source map attached to the end, what is done for most responses otherwise.

The issue in theory is there both when css.devSourcemap is set to true or false. Only that when it was set to true vite-plugin-vue2 managed to generate a proper sourcemap, which allowed the browser to "see" the original Vue SFC instead of the HMR JS file. But when the css.devSourcemap was false the generated sourcemap masked the non-css lines of the SFC by \n-s, making debugging invisible.

And finally why the sourcemap is not needed at all in the HMR JS file carrying the css payload? Because another file is already loaded by the URL /src/components/HelloWorld.vue which carries the compiled Vue render function and which has a proper source map allowing the browser to display the original SFC source code in the debugger even if the other request does not carry a sourcemap. (Note that the source map for the css is wrapped in a variable, so that cannot be "seen" by the browser until HMR magic does not restores the css code from it and updates the client code with it.

So how come it worked in some browsers and not in others? It is because some browsers ignored the sourcemap from the css request and relied on the other one provided in the other request. After all these requests are for the same file, only differ in query parameters, and there's no standard approach what to do if multiple request claim to provide mappings for a given source. Chrome tries to apply all of them. Firefox processes both sourcemaps and shows two versions of the same source, one based on each. And I assume Safari simply ignores the later one.

BenceSzalai added a commit to BenceSzalai/vite that referenced this pull request Nov 3, 2022
Compatibility was broken with fix vitejs#9914 but also we don't need and don't want to add dummy sourcemaps to HMR JS requests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat: css p3-minor-bug An edge case that only affects very specific usage (priority)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Sourcemap failure on Chrome for Vue 2 components with CSS
3 participants