Search code examples
webpackvuejs3require

Importing a Vue3 components library that uses require(...).default for assets works in some apps, but not others


I'm working with multiple apps in Vue3, and we've built a reuse-able components library that we can import into all of our other apps. Some of the components in the library have <img> tags that use a dynamic :src attribute, determined by a computed property that returns require("../whatever.svg").default. Other <img> tags have a static src. What I've noticed is that when I import the library into some of our apps, all the images appear correctly, while in others, the dynamically sourced images don't appear. If I update the library to use require("../whatever.svg") without the .default, and then re-import the library, the results are reversed. In the apps where the dynamic images had been working, they no longer appear, and in the apps where the dynamic images didn't load, they now appear correctly. As far as I know, all our apps have basically identical setups and webpack configurations, so I have no idea why this would be happening. Here are examples of what I'm working with:

Reuse-able Component in Library -

<template>
  <img class="filter-icon" :src="filterIconPath" alt="Filter Icon" />
</template>

<script setup>
import { computed } from "vue";

const props = defineProps({
  active: Boolean,
  disabled: Boolean
});

const filterIconPath = computed(() => {
  if (props.active) {
    if (props.disabled) {
      return require("../assets/icons/FilterDarkGreyLarge.svg").default;
    } else {
      return require("../assets/icons/FilterLightLarge.svg").default;
    }
  } else {
    if (props.disabled) {
      return require("../assets/icons/FilterLightGreyLarge.svg").default;
    }
    return require("../assets/icons/FilterDarkLarge.svg").default;
  }
});
</script>

This component works correctly and the images load in most of our apps, however the one I'm working on now can't load the image. Here is the vue.config.js file for that app:

process.env.VUE_APP_VERSION = require("./package.json").version;

module.exports = {
  chainWebpack: (config) => {
    config.plugin("html").tap((args) => {
      args[0].title = "MyApp";
      return args;
    });
    config.module
      .rule("graphql")
      .test(/\.graphql|\.gql$/)
      .use("raw-loader")
      .loader("raw-loader")
      .end();
    config.module
      .rule("vue")
      .use("vue-loader")
      .loader("vue-loader")
      .tap((options) => {
        options.transpileOptions = {
          transforms: {
            dangerousTaggedTemplateString: true,
          },
        };
        return options;
      });
  },

  css: {
    loaderOptions: {
      sass: {
        additionalData: `
              @use "sass:math";
              @import "node_modules/my-components/src/scss/_variables.scss";
              @import "node_modules/my-components/src/scss/_mixins.scss";
              @import "node_modules/my-components/src/scss/_forgeColors.scss";
              @import "node_modules/my-components/src/scss/_forgeButtons.scss";
              @import "@/scss/_variables.scss";
              @import "@/scss/_mixins.scss";
            `,
      },
    },
  },
  transpileDependencies: [],
};

This file identical except for the app title to the vue.config.js files of our other apps where the require(...).default images are working correctly.

I'm not doing anything fancy to import the component, it's an npm package we add in package.json. Inside the app, I use

<script setup>
import ForgeFilterButton from "my-components/src/components/FilterButton.vue";
</script>

and then use the component in the template like normal. When I run the app locally, the component loads with all of its styling, but the image doesn't appear. If I go back to the library, and remove .default, then re-import the library and run it again, the image appears correctly. I'm totally stumped as to why this may be happening, and I'm hoping I can find a solution other than maintaining two versions of our library, one with .default and one without.


Solution

  • The issue ended up being the webpack version. Some of our apps had gotten bumped to a higher version, while others hadn't. Updating to the latest version on all apps fixed this issue.