vuejs / rollup-plugin-vue

Roll .vue files
https://vuejs.github.io/rollup-plugin-vue
MIT License
843 stars 147 forks source link

Css parsing no longer works since 4.1.5 with postcss #207

Closed aldarund closed 5 years ago

aldarund commented 6 years ago

Expected behavior

Build not fails

Actual behavior

Build fails

[!] (babel plugin) SyntaxError: C:\Dev\PycharmProjects\vuetify-form-generator\src\components\display-form.vue?rollup-plugin-vue=styles.0.css: Leading decorators must be attached to a class declaration (2:11)

  1 |
> 2 | @font-face {
    |            ^
  3 |   font-family: "Quentin";
  4 |   src: url("./assets/fonts/Quentin.woff2") format("woff2"),
  5 |     url("./assets/fonts/Quentin.woff") format("woff");
src\components\display-form.vue?rollup-plugin-vue=styles.0.css (2:11)
SyntaxError: C:\Dev\PycharmProjects\vuetify-form-generator\src\components\display-form.vue?rollup-plugin-vue=styles.0.css: Leading decorators must be attached to a class declaration (2:11)

In 4.1.4 all works fine. In 4.1.5 and 4.2.0 - no.

Steps to reproduce the behavior

Here is my rollup config

plugins: [
      resolve({
        browser: true,
        jsnext: true,
        preferBuiltins: false,
        extensions: [".js", ".json", ".vue"]
      }),
      commonjs(),
      VuePlugin({
        compileTemplate: true,
        // styleToImports: true,
        css: false,
        template: {
          // styleToImports: true,
          isProduction: opts.env === "production",
          compilerOptions: { preserveWhitespace: false }
        }
      }),
      postcss({
        plugins: []
      }),
      json(),
      babel({
        exclude: "node_modules/**",
        runtimeHelpers: true
      }),
      filesize()
    ]
znck commented 6 years ago

If you set css: false, you have to use a rollup plugin to process styles.

aldarund commented 6 years ago

But it's there, postcss process it. And it was working before 4.1.5

znck commented 6 years ago

Okay. I'll look into it and get back to you.

htmlin commented 6 years ago

+1

scrollbar-ww commented 6 years ago

there's the code from 'rollup-plugin-postcss' :

    async transform(code, id) {
      let scoped
      if (hasQuery(id)) {
        const query = parseQuery(id)
        scoped = query.scoped
        id = stripQuery(id)
      }

      if (!filter(id) || !loaders.isSupported(id)) {
        return null
      }

the vue plugin extract style code, and put a id like 'xxx.vue?rollup-plugin-vue=styles.0.css',

the query string '?rollup-plugin-vue=styles.0.css' will be killed by the code above

id = stripQuery(id)

then, loaders.isSupported return false now...

objectivehtml commented 5 years ago

Ran into this issue as well. Postcss worked fine in v2.2. I updated to v4 latest and Postcss won't run CSS nano. I can roll back to rollup-plugin-vue v4.1.4 and it works, kinda. Would be good to get an official fix on this so I can update my dependencies in my Rollup boilerplate. Thanks for the plugin.

Without updating the vue rollup plugin, I get errors like this Your current PostCSS version is 6.0.23, but postcss-plugin-purgecss uses 7.0.5. Oder versions of the rollup-plugin-vue require "postcss": "^6.0.22" or lower.

objectivehtml commented 5 years ago

I spent a few hours digging around in the code for rollup-plugins-vue and rollup-plugins-postcss to figure out what PostCSS wouldn't work with the latest rollup-plugin-vue version. The post above was kinda vague. I've never dug into the code of any build tool, just always installed plugins. So forgive me if this isn't a complete solution. I was going crazy with this not working. Using the information @scrollbar-ww posted, I was able to get my css file to pass through postcss and cssnano.

The issue I found has to do with the resolved id using the extension .vue. Postcss doesn't have a loader for this specifically, so if I specify .vue in the postcss options, it tries to parse the entire vue file and I get an error. Without .vue, it doesn't get passed through postcss. There is also the fact that postcss strips the query string from the id, so that isn't reliable to use a key.

Original code from index.ts

resolveId(id, importer) {
  if (!isVuePartRequest(id)) return
  id = path.resolve(path.dirname(importer), id)
  const ref = parseVuePartRequest(id)
  if (ref) {
    const element = resolveVuePart(descriptors, ref)
    const src = (element as SFCBlock).src
    if (ref.meta.type !== 'styles' && typeof src === 'string') {
      if (src.startsWith('.')) {
        return path.resolve(path.dirname(ref.filename), src as string)
      } else {
        return require.resolve(src, { paths: [path.dirname(ref.filename)] })
      }
    }

    return id
  }
}

My changed code, notice the else if.

resolveId(id, importer) {
  if (!isVuePartRequest(id)) return
  id = path.resolve(path.dirname(importer), id)
  const ref = parseVuePartRequest(id)
  if (ref) {
    const element = resolveVuePart(descriptors, ref)
    const src = (element as SFCBlock).src
    if (ref.meta.type !== 'styles' && typeof src === 'string') {
      if (src.startsWith('.')) {
        return path.resolve(path.dirname(ref.filename), src as string)
      } else {
        return require.resolve(src, { paths: [path.dirname(ref.filename)] })
      }
    }
    else if(ref.meta.type === 'styles') {
        // Replace the .vue extension with a .vue.css so it can pass through
        // PostCSS.
        return id.replace('.vue', '.vue.css');
    }

    return id
  }
}

Here is my relevant rollup plugins config. Note, css() has to go last or else I get no output.

[
    vue({
        css: false,
        defaultLang: {
            style: 'scss'
        }
    }),
    postcss({
        extract: true,
        plugins: [
            cssnano()
        ]
    }),
    css()
]

Original CSS from SampleComponent.vue:

<style lang="scss">
.sample-component {
    background: rgb(200, 200, 200);

    .message {
        font-size: 1rem;
    }

    .asd {
        background: yellow;
    }
}
</style>

If I do not include extract: true to Postcss, then I get the following in my CSS file:

var css = ".sample-component{background:#c8c8c8}.sample-component .message{font-size:1rem}.sample-component .asd{background:#ff0}";
export default css;
import styleInject from '{MY_PROJECT_PATH_HERE}/node_modules/style-inject/dist/style-inject.es.js';
styleInject(css);

If I remove my changed code from rollup-plugin-vue my CSS output is unchanged by PostCSS.

.sample-component {
  background: #c8c8c8;
}
.sample-component .message {
    font-size: 1rem;
}
.sample-component .asd {
    background: yellow;
}

/*# sourceMappingURL=SampleComponent.vue.map */

With my change in place, my output is:

.sample-component{background:#c8c8c8}.sample-component .message{font-size:1rem}.sample-component .asd{background:#ff0}

I have no clue about the implications of this for LESS or other preprocessors, if that matters at all. Curious to get your take on this. It was driving my crazy, and I was originally just not going to mess with it, but curiosity and OCD got the better of me. Given this is free software, figured I would do what I could do debug this. Hopefully this helps. Let me know if you have any questions.

znck commented 5 years ago

In the latest release of rollup-plugin-postcss, it honors rollup-plugin-vue query param.