Тип source в системе Asset Modules, появившейся в
Webpack 5, предназначен для импорта содержимого файла в виде обычной
строки. В отличие от типов asset/resource или
asset/inline, здесь Webpack не генерирует отдельный файл и
не преобразует данные в Base64. Вместо этого содержимое ресурса
встраивается в JavaScript-бандл как текст.
Такой подход особенно полезен при работе с:
.txt файлами;Тип source заменяет старый raw-loader,
который широко использовался в Webpack 4 и более ранних версиях.
asset/sourceПри использовании asset/source Webpack читает содержимое
файла во время сборки и превращает его в строковый литерал внутри
итогового JavaScript-кода.
Например, файл:
Hello Webpack
после импорта превращается примерно в:
export default "Hello Webpack";
Файл не копируется в dist, не получает хэш и не
становится отдельным HTTP-ресурсом.
src/
├── index.js
└── message.txt
message.txtWebpack умеет импортировать текстовые файлы.
module.exports = {
module: {
rules: [
{
test: /\.txt$/i,
type: 'asset/source'
}
]
}
};
import message fr om './message.txt';
console.log(message);
Webpack умеет импортировать текстовые файлы.
Webpack:
module.rules.asset/source.В итоговой сборке файл отсутствует как физический ресурс.
asset/resourceСоздаёт отдельный файл.
import file from './data.txt';
Результат:
"/assets/data.a1b2c3.txt"
asset/inlineПреобразует содержимое в Data URL.
data:text/plain;base64,...
asset/sourceВозвращает чистую строку.
"Текст файла"
raw-loaderДо появления Webpack 5 текстовые ресурсы обычно обрабатывались через
raw-loader.
npm install raw-loader --save-dev
module.exports = {
module: {
rules: [
{
test: /\.txt$/,
use: 'raw-loader'
}
]
}
};
module.exports = {
module: {
rules: [
{
test: /\.txt$/,
type: 'asset/source'
}
]
}
};
Преимущества нового механизма:
Одно из наиболее популярных применений — загрузка Markdown как строки.
module.exports = {
module: {
rules: [
{
test: /\.md$/,
type: 'asset/source'
}
]
}
};
article.md# Заголовок
Текст статьи.
import markdown from './article.md';
console.log(markdown);
Часто строка Markdown затем передаётся в библиотеку преобразования HTML.
import markdown from './article.md';
import { marked } from 'marked';
const html = marked(markdown);
document.body.innerHTML = html;
Webpack здесь используется только для получения содержимого файла.
SVG можно импортировать не как URL, а как строку.
{
test: /\.svg$/i,
type: 'asset/source'
}
<svg viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40"/>
</svg>
import svg from './icon.svg';
console.log(svg);
import icon from './icon.svg';
document.body.innerHTML = icon;
Такой подход позволяет:
{
test: /\.html$/i,
type: 'asset/source'
}
import template from './card.html';
document.body.innerHTML = template;
<div class="card">
{{title}}
</div>
import template from './card.html';
const result = template.replace('{{title}}', 'Webpack');
console.log(result);
Тип source активно используется в серверных
проектах.
SEL ECT * FROM users WH ERE active = 1;
import query fr om './users.sql';
console.log(query);
В WebGL-проектах asset/source используется особенно
часто.
{
test: /\.(glsl|vert|frag)$/i,
type: 'asset/source'
}
import fragmentShader from './shader.frag';
console.log(fragmentShader);
precision mediump float;
void main() {
gl_FragColor = vec4(1.0);
}
{
test: /\.xml$/i,
type: 'asset/source'
}
import xml from './data.xml';
const parser = new DOMParser();
const doc = parser.parseFromString(xml, 'application/xml');
console.log(doc);
{
test: /\.csv$/i,
type: 'asset/source'
}
import csv from './users.csv';
console.log(csv);
const rows = csv
.split('\n')
.map(row => row.split(','));
console.log(rows);
Обычно JSON импортируется как объект:
import data from './data.json';
Но иногда требуется именно исходный текст JSON.
{
test: /\.json$/i,
type: 'asset/source'
}
import rawJson from './data.json';
console.log(typeof rawJson);
string
resourceQueryWebpack позволяет по-разному обрабатывать один и тот же тип файлов.
module.exports = {
module: {
rules: [
{
resourceQuery: /raw/,
type: 'asset/source'
},
{
test: /\.svg$/i,
type: 'asset/resource'
}
]
}
};
import iconUrl from './icon.svg';
import iconRaw from './icon.svg?raw';
console.log(iconUrl);
/assets/icon.svg
console.log(iconRaw);
<svg>...</svg>
oneOfmodule.exports = {
module: {
rules: [
{
test: /\.svg$/i,
oneOf: [
{
resourceQuery: /raw/,
type: 'asset/source'
},
{
type: 'asset/resource'
}
]
}
]
}
};
oneOfoneOf позволяет:
Webpack корректно обрабатывает Unicode-символы.
Привет мир
你好
こんにちは
import text from './hello.txt';
console.log(text);
Наиболее безопасный вариант — UTF-8.
Проблемы могут возникать при использовании:
Webpack ожидает стандартную UTF-8-кодировку.
asset/source встраивает содержимое прямо в
JavaScript.
Это означает:
Поэтому тип source подходит преимущественно для
небольших текстовых файлов.
asset/source использовать не стоитПлохие сценарии:
В подобных случаях лучше:
asset/resource;Текстовые ресурсы можно загружать лениво.
async function loadArticle() {
const article = await import('./article.md');
console.log(article.default);
}
Webpack создаёт отдельный chunk:
article.chunk.js
Внутри которого хранится строковое содержимое файла.
Если импортируемая строка не используется, Webpack может удалить её из итоговой сборки.
import text from './text.txt';
Если переменная нигде не применяется, модуль потенциально исключается из бандла.
TypeScript требует деклараций модулей.
global.d.tsdeclare module '*.txt' {
const content: string;
export default content;
}
declare module '*.md' {
const content: string;
export default content;
}
import article from './article.md';
export function Page() {
return (
<pre>{article}</pre>
);
}
import template from './template.html';
export default {
template
};
import content from './text.txt';
<p>{content}</p>
Webpack может собирать серверные приложения.
import query from './query.sql';
database.execute(query);
Webpack сериализует строку примерно так:
module.exports = "Hello World";
Спецсимволы автоматически экранируются:
\n
\t
\"
\\
source и
inlineasset/source"hello"
asset/inline"dat a:text/plain;base64,aGVsbG8="
inline создаёт Data URL.
source возвращает оригинальное содержимое.
Тип source можно комбинировать с пользовательскими
loader-цепочками.
{
test: /\.md$/,
use: [
'markdown-loader'
],
type: 'asset/source'
}
asset/source возвращает итог как строку.asset/source:
generator.filename;import template from './welcome-email.html';
import license from './LICENSE.txt';
import config from './default.conf';
import icon from './check.svg';
import shader from './shader.frag';
import post from './post.md';
type: 'source'
Правильно:
type: 'asset/source'
use: 'raw-loader',
type: 'asset/source'
Обычно raw-loader здесь уже не нужен.
Встраивание мегабайт текста резко увеличивает размер bundle.
Файл может импортироваться с повреждёнными символами.
Файл
↓
Webpack
↓
asset/source
↓
Строка JavaScript
↓
Встраивание в bundle