Spec-Zone.ru › webpack 5

Модули активов

Модули активов позволяют использовать файлы активов (шрифты, значки и т. д.) без настройки дополнительных загрузчиков.

До webpack 5 было принято использовать:

  • raw-loader для импорта файла в виде строки
  • url-loader для встраивания файла в бандл как URI данных
  • file-loader для вывода файла в выходную директорию

Типы модулей активов заменяют все эти загрузчики, добавив 4 новых типа модулей:

  • asset/resource выводит отдельный файл и экспортирует URL. Раньше это было достижимо с помощью file-loader.
  • asset/inline экспортирует URI данных актива. Раньше это было достижимо с помощью url-loader.
  • asset/source экспортирует исходный код актива. Раньше это было достижимо с помощью raw-loader.
  • asset автоматически выбирает между экспортом URI данных и выводом отдельного файла. Раньше это было достижимо с помощью url-loader с ограничением размера актива.

При использовании старых загрузчиков активов (например, file-loader/url-loader/raw-loader) вместе с модулями активов в webpack 5, вы можете захотеть остановить обработку ваших активов модулями активов, так как это может привести к дублированию активов. Это можно сделать, установив тип модуля актива в 'javascript/auto'.

webpack.config.js

module.exports = {
  module: {
   rules: [
      {
        test: /\.(png|jpg|gif)$/i,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192,
            }
          },
        ],
+       type: 'javascript/auto'
      },
   ]
  },
}

Чтобы исключить активы, полученные из новых вызовов URL, из загрузчиков активов, добавьте dependency: { not: ['url'] } в конфигурацию загрузчика.

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpg|gif)$/i,
+       dependency: { not: ['url'] },
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192,
            },
          },
        ],
      },
    ],
  }
}

Путь к общедоступным ресурсам

По умолчанию, в скрытом режиме, тип asset выполняет __webpack_public_path__ + import.meta. Это означает, что установка output.publicPath в вашей конфигурации позволит вам переопределить URL, из которого asset загружает.

Переопределение на лету

Если вы установите __webpack_public_path__ в коде, чтобы не сломать логику загрузки asset, необходимо убедиться, что вы запускаете его как первый код в вашем приложении и не используете функцию для этого. Пример - файл под названием publicPath.js с содержимым

__webpack_public_path__ = 'https://cdn.url.com';

А затем в вашем webpack.config.js обновите поле entry следующим образом:

module.exports = {
  entry: ['./publicPath.js', './App.js'],
};

В качестве альтернативы, вы можете сделать следующее в вашем App.js без изменения конфигурации webpack. Единственный недостаток заключается в том, что вам нужно навязать порядок, и это может столкнуться с некоторыми инструментами проверки кода.

import './publicPath.js';

Ресурсные активы

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
+ module: {
+   rules: [
+     {
+       test: /\.png/,
+       type: 'asset/resource'
+     }
+   ]
+ },
};

src/index.js

import mainImage from './images/main.png';

img.src = mainImage; // '/dist/151cfcfa1bd74779aadb.png'

Все .png файлы будут выводиться в выходную директорию, а их пути будут внедрены в бандлы. Кроме того, вы можете настроить outputPath и publicPath для них.

Настройка имени выходного файла

По умолчанию, модули asset/resource выводят файлы с именем [hash][ext][query] в выходную директорию.

Вы можете изменить эту шаблон, установив output.assetModuleFilename в вашей конфигурации webpack:

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
+   assetModuleFilename: 'images/[hash][ext][query]'
  },
  module: {
    rules: [
      {
        test: /\.png/,
        type: 'asset/resource'
      }
    ]
  },
};

Еще один случай для настройки имени выходного файла - вывести определенные активы в указанную директорию:

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
+   assetModuleFilename: 'images/[hash][ext][query]'
  },
  module: {
    rules: [
      {
        test: /\.png/,
        type: 'asset/resource'
-     }
+     },
+     {
+       test: /\.html/,
+       type: 'asset/resource',
+       generator: {
+         filename: 'static/[hash][ext][query]'
+       }
+     }
    ]
  },
};

С этой конфигурацией все html файлы будут выводиться в директорию static внутри выходной директории.

Rule.generator.filename аналогично output.assetModuleFilename и работает только с модулями типа asset и asset/resource.

Встраивание активов

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
-   assetModuleFilename: 'images/[hash][ext][query]'
  },
  module: {
    rules: [
      {
-       test: /\.png/,
-       type: 'asset/resource'
+       test: /\.svg/,
+       type: 'asset/inline'
-     },
+     }
-     {
-       test: /\.html/,
-       type: 'asset/resource',
-       generator: {
-         filename: 'static/[hash][ext][query]'
-       }
-     }
    ]
  }
};

src/index.js

- import mainImage from './images/main.png';
+ import metroMap from './images/metro.svg';

- img.src = mainImage; // '/dist/151cfcfa1bd74779aadb.png'
+ block.style.background = `url(${metroMap})`; // url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDo...vc3ZnPgo=)

Все .svg файлы будут внедрены в бандлы как URI данных.

Пользовательский генератор URI данных

По умолчанию, URI данных, выводимые webpack, представляют содержимое файла, закодированное с помощью алгоритма Base64.

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

webpack.config.js

const path = require('path');
+ const svgToMiniDataURI = require('mini-svg-data-uri');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.svg/,
        type: 'asset/inline',
+       generator: {
+         dataUrl: content => {
+           content = content.toString();
+           return svgToMiniDataURI(content);
+         }
+       }
      }
    ]
  },
};

Теперь все .svg файлы будут закодированы пакетом mini-svg-data-uri.

Исходные активы

webpack.config.js

const path = require('path');
- const svgToMiniDataURI = require('mini-svg-data-uri');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
-       test: /\.svg/,
-       type: 'asset/inline',
-       generator: {
-         dataUrl: content => {
-           content = content.toString();
-           return svgToMiniDataURI(content);
-         }
-       }
+       test: /\.txt/,
+       type: 'asset/source',
      }
    ]
  },
};

src/example.txt

Hello world

src/index.js

- import metroMap from './images/metro.svg';
+ import exampleText from './example.txt';

- block.style.background = `url(${metroMap}); // url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDo...vc3ZnPgo=)
+ block.textContent = exampleText; // 'Hello world'

Все .txt файлы будут внедрены в бандлы как есть.

URL-активы

При использовании new URL('./path/to/asset', import.meta.url), webpack также создает модуль актива.

src/index.js

const logo = new URL('./logo.svg', import.meta.url);

В зависимости от target в вашей конфигурации, webpack скомпилирует указанный код в другой результат:

// target: web
new URL(
  __webpack_public_path__ + 'logo.svg',
  document.baseURI || self.location.href
);

// target: webworker
new URL(__webpack_public_path__ + 'logo.svg', self.location);

// target: node, node-webkit, nwjs, electron-main, electron-renderer, electron-preload, async-node
new URL(
  __webpack_public_path__ + 'logo.svg',
  require('url').pathToFileUrl(__filename)
);

Начиная с webpack 5.38.0, Data URLs поддерживаются в new URL() также:

src/index.js

const url = new URL('data:,', import.meta.url);
console.log(url.href === 'data:,');
console.log(url.protocol === 'data:');
console.log(url.pathname === ',');

Общие типы активов

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
+       test: /\.txt/,
+       type: 'asset',
      }
    ]
  },
};

Теперь webpack автоматически выберет между resource и inline, следуя умолчанию: файл размером менее 8 КБ будет обработан как модуль типа inline, а иначе - как модуль типа resource.

Вы можете изменить это условие, задав Rule.parser.dataUrlCondition.maxSize опцию на уровне правила модуля в вашей конфигурации webpack:

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.txt/,
        type: 'asset',
+       parser: {
+         dataUrlCondition: {
+           maxSize: 4 * 1024 // 4kb
+         }
+       }
      }
    ]
  },
};

Также вы можете указать функцию для определения встраивания модуля или нет.

Замена синтаксиса Inline Loader

До модулей активов и Webpack 5, было возможно использовать синтаксис inline со старыми загрузчиками, упомянутыми выше.

Теперь рекомендуется удалить весь синтаксис inline loader и использовать условие resourceQuery для имитации функциональности синтаксиса inline.

Например, в случае замены raw-loader на тип asset/source:

- import myModule from 'raw-loader!my-module';
+ import myModule from 'my-module?raw';

и в конфигурации webpack:

module: {
    rules: [
    // ...
+     {
+       resourceQuery: /raw/,
+       type: 'asset/source',
+     }
    ]
  },

и если вы хотите исключить обработку сырых активов другими загрузчиками, используйте отрицательное условие:

module: {
    rules: [
    // ...
+     {
+       test: /\.m?js$/,
+       resourceQuery: { not: [/raw/] },
+       use: [ ... ]
+     },
      {
        resourceQuery: /raw/,
        type: 'asset/source',
      }
    ]
  },

или список oneOf правил. Здесь будет применено только первое совпавшее правило:

module: {
    rules: [
    // ...
+     { oneOf: [
        {
          resourceQuery: /raw/,
          type: 'asset/source',
        },
+       {
+         test: /\.m?js$/,
+         use: [ ... ]
+       },
+     ] }
    ]
  },

Отключение вывода активов

В таких случаях, как рендеринг на стороне сервера, вам может потребоваться отключить вывод активов, что возможно с помощью опции emit в Rule.generator:

module.exports = {
  // …
  module: {
    rules: [
      {
        test: /\.png$/i,
        type: 'asset/resource',
        generator: {
          emit: false,
        },
      },
    ],
  },
};

© JS Foundation and other contributors
Licensed under the Creative Commons Attribution License 4.0.
https://webpack.js.org/guides/asset-modules

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API