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

Vue build lib doubles css code #8819

Closed
7 tasks done
dany28 opened this issue Jun 27, 2022 · 5 comments
Closed
7 tasks done

Vue build lib doubles css code #8819

dany28 opened this issue Jun 27, 2022 · 5 comments
Labels
feat: css feat: library mode p3-minor-bug An edge case that only affects very specific usage (priority) regression The issue only appears after a new release

Comments

@dany28
Copy link

dany28 commented Jun 27, 2022

Describe the bug

I'm creating component library for using in non-vue application, simple component:

<template>
<h1>{{ message }}</h1>
</template>

<script lang="ts">
import {defineComponent, ref} from 'vue';

export default defineComponent({
    setup() {
        let message = ref('ok')
        return {
            message
        }
    }
})

</script>

<style>
h1 {
    color: red;
}
</style>

and vite.config.ts:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
const path = require('path');

export default defineConfig({
    build: {
        lib: {
            name: "Test",
            entry: path.resolve(__dirname, `src/views/Test/Test.vue`),
            formats: ['iife'],
            fileName: (format) => "[name].js",
        },
        rollupOptions: {
            external: ['vue'],
            output: { globals: { 'vue': 'Vue', } }
        }
    },
    plugins: [
        vue()
    ]
})

produces two files: Test.js and style.css, but in Test.js I have a copy of style.css content in variable which is never used:

var Test=function(e){"use strict";var p=(()=>`h1{color:red}`)(), .....

how can I prevent it ? I've tested every setting, every format (but I prefer iife), it is always inside JS. Maybe I can use it in component without load external css but how ?

Reproduction

https://github.com/dany28/vue3-library-test

System Info

System:
    OS: macOS 12.4
    CPU: (8) x64 Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz
    Memory: 68.78 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.13.2 - /usr/local/bin/node
    npm: 8.5.2 - /usr/local/bin/npm
  Browsers:
    Chrome: 102.0.5005.115
    Safari: 15.5
  npmPackages:
    @vitejs/plugin-vue: ^2.3.3 => 2.3.3 
    vite: ^2.9.12 => 2.9.12

Used Package Manager

npm

Logs

No response

Validations

@dany28
Copy link
Author

dany28 commented Jun 27, 2022

I've tested with simple build configuration for application build. CSS as still in JS code even if its very big !!!

After hours of searching bug, I've found code created CSS:
plugin: vite:css-post in file vite/packages/vite/src/node/plugins/css.ts starting line 416:

      let code: string
      if (modulesCode) {
        code = modulesCode
      } else {
        let content = css
        if (config.build.minify) {
          content = await minifyCSS(content, config)
        }
        // marking as pure to make it tree-shakable by minifier
        // but the module itself is still treated as a non tree-shakable module
        // because moduleSideEffects is 'no-treeshake'
        code = `export default /* #__PURE__ */ (() => ${JSON.stringify(
          content
        )})()`
      }

after change to

      let code: string
      if (modulesCode) {
        code = modulesCode
      } else {
        if (inlined) {
          let content = css
          if (config.build.minify) {
            content = await minifyCSS(content, config)
          }
          // marking as pure to make it tree-shakable by minifier
          // but the module itself is still treated as a non tree-shakable module
          // because moduleSideEffects is 'no-treeshake'
          code = `export default /* #__PURE__ */ (() => ${JSON.stringify(
            content
          )})()`
        } else {
          code = '';
        }

      }

still creates chunks to external css without creating unnecessary variable in result js code. And, of course makes script little bit faster because skipping minify and stringily of css content

@dany28
Copy link
Author

dany28 commented Jun 27, 2022

Ok, in 2.9.9 it works with this code:

            if (usedRE.test(id)) {
                if (modulesCode) {
                    code = modulesCode;
                }
                else {
                    let content = css;
                    if (config.build.minify) {
                        content = await minifyCSS(content, config);
                    }
                    code = `export default ${JSON.stringify(content)}`;
                }
            }
            else {
                code = `export default ''`;
            }

but export default '' creates variable, just empty string does nothing in code

@sapphi-red sapphi-red added feat: css feat: library mode regression The issue only appears after a new release p3-minor-bug An edge case that only affects very specific usage (priority) labels Jun 28, 2022
@sawmurai
Copy link

sawmurai commented Jun 29, 2022

const stripCssFromJsPlugin = () => {
  return {
    name: 'no-css',

    async transform(_code, id) {
      if (/\.sc?ss$/.test(id)) {
        return 'export default ""';
      }
    }
  }
};

This rollup (not vite) plugin can maybe be used as a workaround, to remove the generated modules that only contain css, until the issue is fixed. This completely ignores tree-shaking, so it might break your code. Please test carefully :)

About the actual bug: is it possible that the /* #__PURE__ */ comment is somehow ignored by esbuild? or that its stripped away before the minifier runs?

Edit:
Using build.minify = "terser" fixes the issue as well: No css ending up in the js file

@sapphi-red
Copy link
Member

Thanks for digging it down.

Ok, in 2.9.9 it works with this code:

Yes this is affected by #8471 which included from v2.9.10.

About the actual bug: is it possible that the /* #__PURE__ */ comment is somehow ignored by esbuild? or that its stripped away before the minifier runs?

Yes. For esm builds, esbuild works well. But for iife and umd builds, it turns out to be ignored (evanw/esbuild#639). Terser works because it handles this case too.

I have created a PR (evanw/esbuild#2360) to esbuild to fix this, but I might revert #8471 for v2.

This was referenced Jul 1, 2022
@sapphi-red
Copy link
Member

Closing as it is fixed by #8874 (v2) and #8896 (v3).

@github-actions github-actions bot locked and limited conversation to collaborators Jul 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feat: css feat: library mode p3-minor-bug An edge case that only affects very specific usage (priority) regression The issue only appears after a new release
Projects
None yet
Development

No branches or pull requests

3 participants