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

Imported components used with <component :is=""> ignored in production #6

Open
arpadgabor opened this issue Dec 18, 2020 · 8 comments
Assignees
Labels
bug Something isn't working

Comments

@arpadgabor
Copy link

I'm using a custom component to render all my icons:

<template>
  <component :is="name" :weight="weight" />
</template>

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

import {
  PhCaretUp as Up,
} from 'phosphor-vue'

export default defineComponent({
  name: 'Icon',
  props: {
    name: { type: String, required: true },
    weight: { default: 'regular' },
  },
  components: {
    Up,
  },
})
</script>

It's all fine in development, but the production bundle ignores all icons. I've just switched from another icon pack that does not cause this (but the bundle size is huge) and right now this problem is pretty annoying.

I've also tried registering the global component in main.ts, to no avail.

Any suggestions are welcome.

@rektdeckard
Copy link
Member

I'm noticing that even regular use of icons with v4.1.3 are not rendering in production builds. Gonna take a look this afternoon. @brlodi maybe you can weigh in on this?

@rektdeckard rektdeckard self-assigned this Dec 18, 2020
@rektdeckard rektdeckard added the bug Something isn't working label Dec 18, 2020
@brlodi
Copy link

brlodi commented Dec 19, 2020

I’ll take a look this afternoon.

@brlodi
Copy link

brlodi commented Dec 19, 2020

The gist of the problem seems to be that the way the SFCs are being built by Rollup, the template is added as a side-effect, e.g. (the same structure exists in the bundled files, but it's easier to read the ESM version):

// dist/esm/components/PhActivity.vue.js
import component from './PhActivity.vue_vue&type=script&lang.js';
export { default } from './PhActivity.vue_vue&type=script&lang.js';
import { render } from './PhActivity.vue_vue&type=template&id=7b9995bc&lang.js';

component.render = render;

The problem is the library is marked as entirely side-effect free (that was my mistake) and so Vue CLI/Webpack is stripping out everything except the pass-through re-export when the consumer builds the project for production. The templates-turned-render-functions are just being entirely omitted, and trying to render a Vue component with no render function defined creates the empty HTML comment nodes you can see in the browser.

I'll need to do some testing to figure out the right combo of Rollup settings and sideEffects to keep everything tree-shaking without over-shaking. In the meantime, simply removing the "sideEffects": false in the Phosphor-Vue package.json will fix the missing icon problem, but it will also totally disable any meaningful tree-shaking. It's up to you @rektdeckard on whether to use that nuclear option for now.

Side-note, this appears to be a change in the Vue SFC compiler in Vue 3, and something I missed in testing. That's on me.

@brlodi
Copy link

brlodi commented Dec 19, 2020

Upon further digging, I believe that removing the erroneous "sideEffects": false is all that we need to do. Unfortunately I can't then reintroduce tree-shaking the "right" way, because based on vuejs/rollup-plugin-vue/issues/401 it seems like it might be currently impossible to publish a tree-shakable Vue 3 component library—considering the author of that issue report is as far as I can tell the preeminent authority on Vue library bundling.

@RyanPrentiss
Copy link

Using Vue3 and having the same issue -- icons are missing from production build. I tried removing the "sideEffects": false from the phosphor-vue package.json as mentioned above, however no change. I am implementing as <ph-instagram-logo />.

@brlodi
Copy link

brlodi commented Apr 15, 2021

Just wanted to check in and say I'm still watching this, but a proper fix with working tree-shaking is blocked upstream (actually in the Vue 3 core rather than the Rollup plugin, see vuejs/core#2860).

It's frustrating that Vue 3 launched with full tree-shaking advertised as a first-class feature, but seven months in it's still half-broken when it comes to anything more complex than the sample apps 😞

@dnlsndr
Copy link
Collaborator

dnlsndr commented Feb 4, 2023

@brlodi I've found that if you build a library with the preserveModules option set to true in Rollup, vue is able to treeshake the components. So it seems vue has trouble treeshaking as soon as we bundle all components into one dist file. This is implemented for the next major version release in the next branch.

@Delaylaph
Copy link

I have the same issue even in dev mode using nuxt 3.9. To fix this, I use an array with the components themselves instead of their names. And it's work fine.

<template>
  <div v-for="icon in icons">
    <component :is="icon" size="36"></component>
  </div>
</template>

<script setup>
import { PhFloppyDisk, PhMoonStars, PhListPlus } from "@phosphor-icons/vue";

let icons = [
  PhFloppyDisk,
  PhListPlus,
  PhMoonStars,
];
</script>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants