Сборник рассказов не загружает SVG в компонентах проекта Vue - PullRequest
2 голосов
/ 10 июля 2019

Я создал проект Vue с vue-cli и установил storybook позже через npm install --save-dev storybook в качестве зависимости, чтобы показать мои созданные компоненты.

Конфигурация сборника рассказов выглядит следующим образом:

const path = require('path')

module.exports = async ({ config, mode }) => {
  config.module.rules.push(
    {
      test: /\.svg$/,
      use: ['vue-svg-loader']
    },
    {
      test: /\.scss$/,
      use: [
        'style-loader',
        'css-loader',
        {
          loader: 'sass-loader',
          options: {
            sourceMap: false,
            data: '@import "./src/assets/styles/main.scss";'
          }
        }
      ],
      include: path.resolve(__dirname, '../')
    }
  )

  return config
}

и история index.js вот так:

import Vue from 'vue';
import { storiesOf } from '@storybook/vue';
import Alert from '../src/components/buttons/Alert.vue';

storiesOf('Components', module)
  .add('Alert', () => ({
    components: { Alert },
    template: '<Alert />'
  }))

по какой-то причине при попытке загрузить компонент, который состоит из SVG, я получаю:

enter image description here

Сам компонент отображается, но та часть, где находится SVG, SVG не показывает.

Интересно, что он прекрасно работает при попытке отобразить компонент в основном приложении Vue. vue.config выглядит так:

module.exports = {
  css: {
    loaderOptions: {
      sass: {
        data: `@import "./src/assets/styles/main.scss";`
      }
    }
  },
  chainWebpack: config => {
    const svgRule = config.module.rule("svg");

    svgRule.uses.clear();

    svgRule.use("vue-svg-loader").loader("vue-svg-loader");
  }
};

Почему storybook не загружает svgs должным образом, в то время как основное приложение Vue может?

Редактировать: Я пошел дальше и просто использовал веб-пакеты file-loader, чтобы убедиться, что он не имеет ничего общего с vue-svg-loader:

{
  test: /\.(png|jpg|gif|svg)$/,
  use: [
    {
      loader: 'file-loader',
      options: {},
    },
  ],
},

но я получаю ту же ошибку. После попытки применить первый ответ для замены push() на правила с unshift() я получаю эту ошибку: Error in parsing SVG: Non-whitespace before first tag.

Edit2

Это одна из SVG, которую я пытаюсь загрузить:

<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="exclamation-triangle" class="svg-inline--fa fa-exclamation-triangle fa-w-18" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path fill="currentColor" d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"></path></svg>

Edit3 : * Alert.vue в projectroot/src/components/banners/Alert.vue, конфигурация веб-пакета Storybook в projectroot/.storybook/webpack.config.js

<template>
  <div v-if="show" :class="`alert_wrap ${model}`">
    <IconBase>
      <component :is="iconComponent" />
    </IconBase>
    <div class="alert_text">
      <p v-if="title">{{ title }}</p>
      <p>{{ msg }}</p>
    </div>
    <IconBase>
      <TimesIcon @click="show = !show" aria-hidden="Close" />
    </IconBase>
  </div>
</template>

<script>
import IconBase from "../icons/IconBase.vue";
import CautionIcon from "../../assets/icons/exclamation-triangle-solid.svg";
import InfoIcon from "../../assets/icons/info-circle-solid.svg";
import SuccessIcon from "../../assets/icons/check-circle-solid.svg";
import TimesIcon from "../../assets/icons/times-solid.svg";

export default {
  name: "Alert",
  components: {
    CautionIcon,
    InfoIcon,
    SuccessIcon,
    TimesIcon,
    IconBase
  },
  props: {
    msg: {
      type: String,
      required: true
    },
    title: {
      type: String
    },
    model: {
      type: String,
      default: "info",
      validator(type) {
        return ["caution", "info", "success"].includes(type);
      }
    }
  },
  computed: {
    iconComponent() {
      return `${this.model}-icon`;
    }
  },
  data() {
    return {
      show: true
    };
  }
};
</script>

<style scoped lang="scss">
  /* some styles depending on the props passed */
</style>

Ответы [ 3 ]

3 голосов
/ 17 июля 2019

@ liximomo ответ почти правильный.Вы должны удалить файл svg из правила обработки file-loader, но условие поиска правила должно немного отличаться:

module.exports = ({ config }) => {

    let rule = config.module.rules.find(r =>
        // it can be another rule with file loader 
        // we should get only svg related
        r.test && r.test.toString().includes('svg') &&
        // file-loader might be resolved to js file path so "endsWith" is not reliable enough
        r.loader && r.loader.includes('file-loader')
    );
    rule.test = /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani)(\?.*)?$/;

    config.module.rules.push(
        {
            test: /\.svg$/,
            use: ['vue-svg-loader']
        }
    )

    // ...

    return config;
}

Другой способ импортировать SVG без изменения правил конфигурации Webpack - указать * 1006.* встроенный загрузчик, который может быть полезен, чтобы избежать ошибок, когда некоторые компоненты уже используют SVG в CSS или HTML как просто путь к файлу.Пример:

// disable all rules with !! and use just vue-svg-loader
import CautionIcon from "!!vue-svg-loader!../../assets/icons/exclamation-triangle-solid.svg";
1 голос
/ 16 июля 2019

Потому что storybook уже имеет file-loader для испускания вашего svg в качестве актива.Сначала мы должны исключить svg из file-loader.

// exclude svg from existing rule
config.module.rules = config.module.rules.map(rule => {
  if (rule.loader && rule.loader.endsWith('file-loader')) {
    return {
      ...rule,
      test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani)(\?.*)?$/,
    };
  }

  return rule;
});

// now we can add our svg loader
config.module.rules.push(
    {
      test: /\.svg$/,
      use: ['vue-svg-loader']
    },
    {
      test: /\.scss$/,
      use: [
        'style-loader',
        'css-loader',
        {
          loader: 'sass-loader',
          options: {
            sourceMap: false,
            data: '@import "./src/assets/styles/main.scss";'
          }
        }
      ],
      include: path.resolve(__dirname, '../')
    }
  )
0 голосов
/ 16 июля 2019

Используете ли вы кодировку UTF-8?

Ошибка у вас

Ошибка синтаксического анализа SVG: непропуск перед первым тегом

используется для связи с кодированием с использованием Byte-Order-Mark (BOM).

Unicode-символ "Zero width no-break space" в системах Windows автоматическое добавление к файлам utf-8

Если вы проверите файл в шестнадцатеричном редакторе, вы увидите виновника.

Вы можете вручную изменить кодировку на «без спецификации» или выполнить замену на что-то вроде замены ("\ ufeff", "") перед загрузкой файла.

Если вы использовали редактор, возможно, у вас есть конфигурация для конкретной кодировки "с спецификацией". Например в блокноте ++ N++ encoding

Код для добавления опции jsx

 loader: 'file-loader',
      options: {
        jsx: true,
      },
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...