Love Frontend
Статья опубликована: 16.07.2018

Как подключить всю папку svg изображений в webpack

Данная статья содержит развёрнутый ответ на вопрос: "Как в webpack подключить всю папку svg, картинок, изображений, png, jpg и т.д."

Это относится именно к тем случаям, когда ресурсы подключаются не в стилях CSS, а именно вставляются в шаблон. Например во Vue в таком случае вы будете использовать такую конструкцию:


<div v-html="svgIcon"></div>

Где svgIcon - это переменная содержащая разметку SVG изображения. (Обычно для этих целей используется svg-inline-loader для webpack).

Так вот, вероятнее всего вы делаете так:


import SVG1 from './assets/images/svg1'
import SVG2 from './assets/images/svg2'
import SVG3 from './assets/images/svg3'
...

data () {
  return {
    items: [
      {
        name: 'kuku',
        icon: SVG1
      },
      {
        name: 'blabla',
        icon: SVG2
      },
      {
        name: 'good',
        icon: SVG3
      },
    ]
  }
}


И предположим в шаблоне вы выводите SVG следующим образом:


<div v-for="item in items" v-html="item.icon"></div>


Данная конструкция выведет все иконки у каждого item'а

Да, конечно вы сами чуствуете, что можно сделать более элегантно. К тому же если у вас много ресурсов, то файл компонента просто превратится в полотно.

Тут нам на помощь придёт такая чудная фича webpack - require.context.

В нашем случае нужно будет использовать её так:


const SVG = require.context('../assets/svg/menu', true, /\.svg$/)


первый параметр - путь до файлов, второе булево значение говорит функции, что нужно пройти папки рекурсивно и третий параметр шаблон регулярного выражения для взятия нужных ресурсов. В нашем случае все svg файлы.

Обратите внимание, что данная функция возвращает другую функцию. Да, нам нужно будет вызывать нашу константу SVG с нужным нам названием изображения, чтобы его получить из массива. Сам массив собранных svg вы можете увидеть вызвав метод keys() у возвращённой функции. То есть SVG.keys().

Но нам же нужно написать функцию, которая подставит название svg иконки, она будет выглядеть так:


const getSVG = nameOfLogo => SVG(`./${nameOfLogo}.svg`)

Теперь код выглядит так:


const SVG = require.context('../assets/svg/menu', true, /\.svg$/)
const getSVG = nameOfLogo => SVG(`./${nameOfLogo}.svg`)

module exports = {
  data () {
    return {
      items: [
        {
          name: 'kuku',
          icon: getSVG('svg1')
        },
        {
          name: 'blabla',
          icon: getSVG('svg2')
        },
        {
          name: 'good',
          icon: getSVG('svg3')
        },
      ]
    }
  }
}


Больше нет импорта каждой svg отдельно.

Но это ещё не всё, на последок можно ещё более упростить всю конструкцию и убрать повторяющиеся свойства объектов item.

Можно сделать так:


data () {
  return {
    items: [
        ['kuku', 'svg1'],
        ['blabla', 'svg2'],
        ['good', 'svg3']
      ].map(i => ({ name: i[0], icon: getSVG(i[1])}))
    ]
  }
}

Последнее не является обязательным и возможно кого-то запутает, однако я люблю использовать такой подход, чтобы не дублировать названия свойств в объектах. Например при статичном меню написанном на фронте, предпочитаю делать именно так.

Kamil Ocean