Управление активами
Если вы следовали руководствам с самого начала, у вас теперь есть небольшой проект, который показывает "Привет webpack". Теперь давайте попробуем включить другие активы, такие как изображения, чтобы увидеть, как с ними можно работать.
До webpack разработчики front-end использовали такие инструменты, как grunt и gulp, для обработки этих активов и перемещения их из их /src папки в их /dist или /build директорию. Такой же подход использовался для модулей JavaScript, но инструменты, подобные webpack, будут **динамически объединять** все зависимости (создавая то, что известно как граф зависимостей). Это отлично, потому что каждый модуль теперь явно указывает свои зависимости, и мы избежим объединения модулей, которые не используются.
Одна из самых интересных функций webpack заключается в том, что вы также можете включать любые другие типы файлов, помимо JavaScript, для которых существует загрузчик или встроенная поддержка модулей активов. Это означает, что те же преимущества, что перечислены выше для JavaScript (например, явные зависимости), могут быть применены ко всему, что используется при создании веб-сайта или веб-приложения. Давайте начнем с CSS, так как вы, возможно, уже знакомы с этой настройкой.
Настройка
Давайте внесем небольшое изменение в наш проект перед началом:
dist/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
- <title>Getting Started</title>
+ <title>Asset Management</title>
</head>
<body>
- <script src="main.js"></script>
+ <script src="bundle.js"></script>
</body>
</html> webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
- filename: 'main.js',
+ filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
}; Загрузка CSS
Для того, чтобы import файл CSS изнутри модуля JavaScript, вам нужно установить и добавить style-loader и css-loader в вашу module конфигурацию:
npm install --save-dev style-loader css-loader
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
+ module: {
+ rules: [
+ {
+ test: /\.css$/i,
+ use: ['style-loader', 'css-loader'],
+ },
+ ],
+ },
}; Загрузчики модулей могут быть объединены в цепочку. Каждый загрузчик в цепочке применяет преобразования к обработанному ресурсу. Цепочка выполняется в обратном порядке. Первый загрузчик передает свой результат (ресурс с примененными преобразованиями) следующему и так далее. В конечном итоге webpack ожидает, что последний загрузчик в цепочке вернет JavaScript.
Вышеупомянутый порядок загрузчиков должен быть сохранен: 'style-loader' должен быть первым, а затем 'css-loader'. Если этот порядок не соблюден, webpack, вероятно, выдаст ошибки.
Это позволяет вам import './style.css' в файл, который зависит от этого стилирования. Теперь, когда этот модуль будет запущен, тег <style> со строковым представлением CSS будет вставлен в <head> вашего HTML-файла.
Давайте попробуем это, добавив новый style.css файл в наш проект и импортировав его в наш index.js:
project
webpack-demo
|- package.json
|- package-lock.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
+ |- style.css
|- index.js
|- /node_modules src/style.css
.hello {
color: red;
} src/index.js
import _ from 'lodash';
+import './style.css';
function component() {
const element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+ element.classList.add('hello');
return element;
}
document.body.appendChild(component()); Теперь запустите команду сборки:
$ npm run build
...
[webpack-cli] Compilation finished
asset bundle.js 72.6 KiB [emitted] [minimized] (name: main) 1 related asset
runtime modules 1000 bytes 5 modules
orphan modules 326 bytes [orphan] 1 module
cacheable modules 539 KiB
modules by path ./node_modules/ 538 KiB
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js 6.67 KiB [built] [code generated]
./node_modules/css-loader/dist/runtime/api.js 1.57 KiB [built] [code generated]
modules by path ./src/ 965 bytes
./src/index.js + 1 modules 639 bytes [built] [code generated]
./node_modules/css-loader/dist/cjs.js!./src/style.css 326 bytes [built] [code generated]
webpack 5.4.0 compiled successfully in 2231 ms Откройте dist/index.html в вашем браузере, и вы должны увидеть, что Hello webpack теперь стилизован красным цветом. Чтобы увидеть, что сделал webpack, проинспектируйте страницу (не просматривайте исходный код страницы, так как он не покажет результат, потому что тег <style> динамически создается JavaScript) и посмотрите теги заголовка страницы. Он должен содержать блок стиля, который мы импортировали в index.js.
Обратите внимание, что вы можете, и в большинстве случаев должны, минимизировать CSS для лучшего времени загрузки в производстве. Кроме того, существуют загрузчики практически для любого типа CSS, который вы можете себе представить – postcss, sass и less, чтобы назвать несколько.
Загрузка изображений
Теперь мы подключаем CSS, но что насчёт изображений, таких как фоны и иконки? Начиная с webpack 5, используя встроенные модули активов, мы можем легко включить их в нашу систему:
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
+ {
+ test: /\.(png|svg|jpg|jpeg|gif)$/i,
+ type: 'asset/resource',
+ },
],
},
}; Теперь, когда вы import MyImage from './my-image.png', это изображение будет обработано и добавлено в вашу output директорию и переменная MyImage будет содержать окончательный URL этого изображения после обработки. При использовании css-loader, как показано выше, аналогичный процесс произойдёт с url('./my-image.png') внутри вашего CSS. Загрузчик распознает, что это локальный файл, и заменит './my-image.png' путь окончательным путём к изображению в вашей output директории. html-loader обрабатывает <img src="./my-image.png" /> аналогичным образом.
Давайте добавим изображение в наш проект и посмотрим, как это работает, вы можете использовать любое изображение:
project
webpack-demo
|- package.json
|- package-lock.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
+ |- icon.png
|- style.css
|- index.js
|- /node_modules src/index.js
import _ from 'lodash';
import './style.css';
+import Icon from './icon.png';
function component() {
const element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.classList.add('hello');
+ // Add the image to our existing div.
+ const myIcon = new Image();
+ myIcon.src = Icon;
+
+ element.appendChild(myIcon);
+
return element;
}
document.body.appendChild(component()); src/style.css
.hello {
color: red;
+ background: url('./icon.png');
} Давайте создадим новую сборку и откроем файл index.html:
$ npm run build
...
[webpack-cli] Compilation finished
assets by status 9.88 KiB [cached] 1 asset
asset bundle.js 73.4 KiB [emitted] [minimized] (name: main) 1 related asset
runtime modules 1.82 KiB 6 modules
orphan modules 326 bytes [orphan] 1 module
cacheable modules 540 KiB (javascript) 9.88 KiB (asset)
modules by path ./node_modules/ 539 KiB
modules by path ./node_modules/css-loader/dist/runtime/*.js 2.38 KiB
./node_modules/css-loader/dist/runtime/api.js 1.57 KiB [built] [code generated]
./node_modules/css-loader/dist/runtime/getUrl.js 830 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js 6.67 KiB [built] [code generated]
modules by path ./src/ 1.45 KiB (javascript) 9.88 KiB (asset)
./src/index.js + 1 modules 794 bytes [built] [code generated]
./src/icon.png 42 bytes (javascript) 9.88 KiB (asset) [built] [code generated]
./node_modules/css-loader/dist/cjs.js!./src/style.css 648 bytes [built] [code generated]
webpack 5.4.0 compiled successfully in 1972 ms Если всё прошло успешно, вы должны увидеть свою иконку в качестве повторяющегося фона, а также элемент img рядом с текстом Hello webpack. Если вы проинспектируете этот элемент, вы увидите, что фактическое имя файла изменилось на что-то вроде 29822eaa871e8eadeaa4.png. Это означает, что webpack нашёл наш файл в папке src и обработало его!
Загрузка шрифтов
А как насчёт других активов, таких как шрифты? Модули активов возьмут любой файл, который вы загрузите через них, и выведут его в директорию сборки. Это означает, что мы можем использовать их для любых типов файлов, включая шрифты. Обновим наш webpack.config.js для обработки файлов шрифтов:
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
+ {
+ test: /\.(woff|woff2|eot|ttf|otf)$/i,
+ type: 'asset/resource',
+ },
],
},
}; Добавьте некоторые файлы шрифтов в свой проект:
project
webpack-demo
|- package.json
|- package-lock.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
+ |- my-font.woff
+ |- my-font.woff2
|- icon.png
|- style.css
|- index.js
|- /node_modules С настроенным загрузчиком и шрифтами на месте, вы можете включить их с помощью объявления @font-face. Локальный url(...) директива будет обработана webpack, как и с изображением:
src/style.css
+@font-face {
+ font-family: 'MyFont';
+ src: url('./my-font.woff2') format('woff2'),
+ url('./my-font.woff') format('woff');
+ font-weight: 600;
+ font-style: normal;
+}
+
.hello {
color: red;
+ font-family: 'MyFont';
background: url('./icon.png');
} Теперь запустите новую сборку и посмотрим, как webpack обработает наши шрифты:
$ npm run build
...
[webpack-cli] Compilation finished
assets by status 9.88 KiB [cached] 1 asset
assets by info 33.2 KiB [immutable]
asset 55055dbfc7c6a83f60ba.woff 18.8 KiB [emitted] [immutable] [from: src/my-font.woff] (auxiliary name: main)
asset 8f717b802eaab4d7fb94.woff2 14.5 KiB [emitted] [immutable] [from: src/my-font.woff2] (auxiliary name: main)
asset bundle.js 73.7 KiB [emitted] [minimized] (name: main) 1 related asset
runtime modules 1.82 KiB 6 modules
orphan modules 326 bytes [orphan] 1 module
cacheable modules 541 KiB (javascript) 43.1 KiB (asset)
javascript modules 541 KiB
modules by path ./node_modules/ 539 KiB
modules by path ./node_modules/css-loader/dist/runtime/*.js 2.38 KiB 2 modules
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js 6.67 KiB [built] [code generated]
modules by path ./src/ 1.98 KiB
./src/index.js + 1 modules 794 bytes [built] [code generated]
./node_modules/css-loader/dist/cjs.js!./src/style.css 1.21 KiB [built] [code generated]
asset modules 126 bytes (javascript) 43.1 KiB (asset)
./src/icon.png 42 bytes (javascript) 9.88 KiB (asset) [built] [code generated]
./src/my-font.woff2 42 bytes (javascript) 14.5 KiB (asset) [built] [code generated]
./src/my-font.woff 42 bytes (javascript) 18.8 KiB (asset) [built] [code generated]
webpack 5.4.0 compiled successfully in 2142 ms Откройте dist/index.html снова и посмотрите, изменился ли текст Hello webpack на новый шрифт. При успешной обработке вы увидите изменения.
Загрузка данных
Ещё одним полезным активом, который можно загрузить, являются данные, такие как файлы JSON, CSV, TSV и XML. Поддержка JSON встроена, аналогично NodeJS, поэтому import Data from './data.json' будет работать по умолчанию. Для импорта CSV, TSV и XML можно использовать csv-loader и xml-loader. Давайте обработаем загрузку всех трёх:
npm install --save-dev csv-loader xml-loader
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
+ {
+ test: /\.(csv|tsv)$/i,
+ use: ['csv-loader'],
+ },
+ {
+ test: /\.xml$/i,
+ use: ['xml-loader'],
+ },
],
},
}; Добавьте файлы данных в свой проект:
project
webpack-demo
|- package.json
|- package-lock.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
+ |- data.xml
+ |- data.csv
|- my-font.woff
|- my-font.woff2
|- icon.png
|- style.css
|- index.js
|- /node_modules src/data.xml
<?xml version="1.0" encoding="UTF-8"?> <note> <to>Mary</to> <from>John</from> <heading>Reminder</heading> <body>Call Cindy on Tuesday</body> </note>
src/data.csv
to,from,heading,body Mary,John,Reminder,Call Cindy on Tuesday Zoe,Bill,Reminder,Buy orange juice Autumn,Lindsey,Letter,I miss you
Теперь вы можете import любой из этих четырёх типов данных (JSON, CSV, TSV, XML), и переменная Data, которую вы импортируете, будет содержать разобранный JSON для использования:
src/index.js
import _ from 'lodash';
import './style.css';
import Icon from './icon.png';
+import Data from './data.xml';
+import Notes from './data.csv';
function component() {
const element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.classList.add('hello');
// Add the image to our existing div.
const myIcon = new Image();
myIcon.src = Icon;
element.appendChild(myIcon);
+ console.log(Data);
+ console.log(Notes);
+
return element;
}
document.body.appendChild(component()); Перезапустите команду npm run build и откройте dist/index.html. Если вы посмотрите в консоль ваших инструментов разработчика, вы должны увидеть, как импортированные данные выводятся в консоль!
// No warning
import data from './data.json';
// Warning shown, this is not allowed by the spec.
import { foo } from './data.json'; Настроить парсер JSON-модулей
Можно импортировать любые toml, yaml или json5 файлы как JSON-модули, используя пользовательский парсер вместо конкретного загрузчика webpack.
Предположим, у вас есть файлы data.toml, data.yaml и data.json5 в папке src.
src/data.toml
title = "TOML Example" [owner] name = "Tom Preston-Werner" organization = "GitHub" bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." dob = 1979-05-27T07:32:00Z
src/data.yaml
title: YAML Example
owner:
name: Tom Preston-Werner
organization: GitHub
bio: |-
GitHub Cofounder & CEO
Likes tater tots and beer.
dob: 1979-05-27T07:32:00.000Z src/data.json5
{
// comment
title: 'JSON5 Example',
owner: {
name: 'Tom Preston-Werner',
organization: 'GitHub',
bio: 'GitHub Cofounder & CEO\n\
Likes tater tots and beer.',
dob: '1979-05-27T07:32:00.000Z',
},
}
Сначала установите пакеты toml, yamljs и json5.
npm install toml yamljs json5 --save-dev
И настройте их в вашей конфигурации webpack:
webpack.config.js
const path = require('path');
+const toml = require('toml');
+const yaml = require('yamljs');
+const json5 = require('json5');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
{
test: /\.(csv|tsv)$/i,
use: ['csv-loader'],
},
{
test: /\.xml$/i,
use: ['xml-loader'],
},
+ {
+ test: /\.toml$/i,
+ type: 'json',
+ parser: {
+ parse: toml.parse,
+ },
+ },
+ {
+ test: /\.yaml$/i,
+ type: 'json',
+ parser: {
+ parse: yaml.parse,
+ },
+ },
+ {
+ test: /\.json5$/i,
+ type: 'json',
+ parser: {
+ parse: json5.parse,
+ },
+ },
],
},
}; src/index.js
import _ from 'lodash';
import './style.css';
import Icon from './icon.png';
import Data from './data.xml';
import Notes from './data.csv';
+import toml from './data.toml';
+import yaml from './data.yaml';
+import json from './data.json5';
+
+console.log(toml.title); // output `TOML Example`
+console.log(toml.owner.name); // output `Tom Preston-Werner`
+
+console.log(yaml.title); // output `YAML Example`
+console.log(yaml.owner.name); // output `Tom Preston-Werner`
+
+console.log(json.title); // output `JSON5 Example`
+console.log(json.owner.name); // output `Tom Preston-Werner`
function component() {
const element = document.createElement('div');
// Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.classList.add('hello');
// Add the image to our existing div.
const myIcon = new Image();
myIcon.src = Icon;
element.appendChild(myIcon);
console.log(Data);
console.log(Notes);
return element;
}
document.body.appendChild(component()); Перезапустите команду npm run build и откройте dist/index.html. Вы должны увидеть, как импортированные данные выводятся в консоль.
Глобальные активы
Самая крутая часть всего вышеупомянутого заключается в том, что загрузка активов таким образом позволяет группировать модули и активы более интуитивно. Вместо того, чтобы полагаться на глобальную директорию /assets, содержащую всё, вы можете группировать активы с кодом, который их использует. Например, полезной может быть такая структура:
- |- /assets + |– /components + | |– /my-component + | | |– index.jsx + | | |– index.css + | | |– icon.svg + | | |– img.png
Эта настройка делает ваш код гораздо более переносимым, так как всё тесно связанное теперь находится вместе. Допустим, вы хотите использовать /my-component в другом проекте, скопируйте или переместите его в директорию /components там. Если вы установили все внешние зависимости и ваша конфигурация содержит те же загрузчики, вы должны быть готовы к работе.
Однако, предположим, что вы придерживаетесь старых способов или у вас есть некоторые активы, которые используются несколькими компонентами (представлениями, шаблонами, модулями и т. д.). По-прежнему возможно хранить эти активы в базовом каталоге и даже использовать алиасы, чтобы сделать их проще import.
Заключение
В следующих руководствах мы не будем использовать все различные активы, которые использовались в этом руководстве, поэтому давайте очистим проект, чтобы быть готовыми к следующей части руководств Управление выводом:
project
webpack-demo
|- package.json
|- package-lock.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
- |- data.csv
- |- data.json5
- |- data.toml
- |- data.xml
- |- data.yaml
- |- icon.png
- |- my-font.woff
- |- my-font.woff2
- |- style.css
|- index.js
|- /node_modules webpack.config.js
const path = require('path');
-const toml = require('toml');
-const yaml = require('yamljs');
-const json5 = require('json5');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
- module: {
- rules: [
- {
- test: /\.css$/i,
- use: ['style-loader', 'css-loader'],
- },
- {
- test: /\.(png|svg|jpg|jpeg|gif)$/i,
- type: 'asset/resource',
- },
- {
- test: /\.(woff|woff2|eot|ttf|otf)$/i,
- type: 'asset/resource',
- },
- {
- test: /\.(csv|tsv)$/i,
- use: ['csv-loader'],
- },
- {
- test: /\.xml$/i,
- use: ['xml-loader'],
- },
- {
- test: /\.toml$/i,
- type: 'json',
- parser: {
- parse: toml.parse,
- },
- },
- {
- test: /\.yaml$/i,
- type: 'json',
- parser: {
- parse: yaml.parse,
- },
- },
- {
- test: /\.json5$/i,
- type: 'json',
- parser: {
- parse: json5.parse,
- },
- },
- ],
- },
}; src/index.js
import _ from 'lodash';
-import './style.css';
-import Icon from './icon.png';
-import Data from './data.xml';
-import Notes from './data.csv';
-import toml from './data.toml';
-import yaml from './data.yaml';
-import json from './data.json5';
-
-console.log(toml.title); // output `TOML Example`
-console.log(toml.owner.name); // output `Tom Preston-Werner`
-
-console.log(yaml.title); // output `YAML Example`
-console.log(yaml.owner.name); // output `Tom Preston-Werner`
-
-console.log(json.title); // output `JSON5 Example`
-console.log(json.owner.name); // output `Tom Preston-Werner`
function component() {
const element = document.createElement('div');
- // Lodash, now imported by this script
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
- element.classList.add('hello');
-
- // Add the image to our existing div.
- const myIcon = new Image();
- myIcon.src = Icon;
-
- element.appendChild(myIcon);
-
- console.log(Data);
- console.log(Notes);
return element;
}
document.body.appendChild(component()); И удалите зависимости, которые мы добавили ранее:
npm uninstall css-loader csv-loader json5 style-loader toml xml-loader yamljs
Следующее руководство
Перейдём к Управлению выводом
Дополнительные материалы
- Загрузка шрифтов на SurviveJS
© JS Foundation and other contributors
Licensed under the Creative Commons Attribution License 4.0.
https://webpack.js.org/guides/asset-management