AssetMapper: простое и современное управление CSS и JS
Дата обновления перевода 2024-07-25
AssetMapper: простое и современное управление CSS и JS
Компонент AssetMapper позволяет писать современные JavaScript и CSS без сложностей
использования бандлера. Браузеры уже поддерживают многие современные функции JavaScript
вроде утверждения import
и классов ES6. А протокол HTTP/2 означает, что объединение
ваших ресурсов для уменьшения количества HTTP-соединений больше не является насущной
необходимостью. Этот компонент является легким слоем, который помогает выдавать ваши
файлы непосредственно браузеру.
Компонент AssetMapper имеет две основные функции:
- Маппирование и версионирование ресурсов : Все файлы внутри
assets/
доступны публично и являются версионированными. Например, вы можете сослаться наassets/styles/app.css
в шаблоне с{{ asset('styles/app.css') }}
. Финальный URL будет содержать хеш версии, вроде/assets/styles/app-3c16d9220694c0e56d8648f25e6035e9.css
. - Importmaps : Нативная функция браузера, которая облегчает использование
утверждения JavaScript
import
(например,import { Modal } from 'bootstrap
) без системы построения. Это поддерживается во всех браузерах (благодаря shim) и является стандартом W3C.
Установка
Чтобы установить компонент AssetMapper, выполнте:
1
$ composer require symfony/asset-mapper symfony/asset symfony/twig-pack
В дополнение к symfony/asset-mapper
, это также гарантирует, что у вас доступны
Компонент Asset и Twig.
Если вы используете Symfony Flex , вы закончили! Рецепт только что добавил следующие файлы:
assets/app.js
Ваш главный файл JavaScript;assets/styles/app.css
Ваш главный файл CSS;config/packages/asset_mapper.yaml
То, где вы определяете ваш ресурс "paths";importmap.php
Ваш файл конфигурации importmap.
Он также обновил файл templates/base.html.twig
:
1 2 3
{% block javascripts %}
+ {% block importmap %}{{ importmap('app') }}{% endblock %}
{% endblock %}
Если вы не используете Flex, вам нужно будет создать и обновить эти файлы вручную. Смотрите последний рецепт asset-mapper, чтобы узнать точное содержание этих файлов.
Маппирование и ссылание на ресурсы
Компонент AssetMapper работает путём определения каталогов/путей ресурсов, которые вы хотите
сделать публичными. Эти ресурсы затем версионируются и на них легко сослаться. Благодаря файлу
asset_mapper.yaml
, ваше приложение запускается с одним маппированым путём: каталогом assets/
.
Если вы создадите файл assets/images/duck.png
, вы можете сослаться на него в шаблоне с помощью:
1
<img src="{{ asset('images/duck.png') }}">
Путь - images/duck.png
- относительный к вашему маппируемому каталогу (assets/
). Это
известно как логический путь к вашему ресурсу.
Если вы посмотрите на HTML в вашей странице, URL будет чем-то вроде:
/assets/images/duck-3c16d9220694c0e56d8648f25e6035e9.png
. Если вы обновите этот
файл, часть версии URL изменится автоматически!
Подача ресурсов в разработке против производства
В окружении dev
, URL - /assets/images/duck-3c16d9220694c0e56d8648f25e6035e9.png
-
обрабатывается и возвращается вашим приложением Symfony.
Для окружения prod
, до развёртывания, вы должны выполнить:
1
$ php bin/console asset-map:compile
Это физически скопирует все файлы из ваших маппированных каталогов в public/assets/
,
чтобы они выдавались напрямую вашим веб-сервером. Смотрите Развёртывание ,
чтобы узнать больше.
Tip
Если вам нужно скопировать скомпилированные ресурсы в другое место (например, загрузить их
в S3), создайте сервис, реализующий Symfony
и установите его идентификатор сервиса (или псевдоним) как asset_mapper.local_public_assets_filesystem
(чтобы заменить встроенный сервис).
Отладка: как увидеть все маппированные ресурсы
Чтобы увидеть все маппированные ресурсы в вашем приложении, выполните:
1
$ php bin/console debug:asset-map
Это отобразит вам все маппированые пути и ресурсы внутри каждого из них:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Пути AssetMapper
----------------
--------- ------------------------------
Путь Префикс с пространством имён
--------- ------------------------------
assets
Маппированные ресурсы
---------------------
------------------ ----------------------------------------------------
Логический путь Путь файловой системы
------------------ ----------------------------------------------------
app.js assets/app.js
styles/app.css assets/styles/app.css
images/duck.png assets/images/duck.png
"Логический путь" - это путь, который следует использовать при ссылании на ресурс, например, из шаблона.
Importmaps и написание JavaScript
Все современные браузеры поддерживают утверждение import JavaScript и современные функции ES6, вроде классов. Поэтому этот код "просто работает":
1 2 3 4 5
// assets/app.js
import Duck from './duck.js';
const duck = new Duck('Waddles');
duck.quack();
1 2 3 4 5 6 7 8 9
// assets/duck.js
export default class {
constructor(name) {
this.name = name;
}
quack() {
console.log(`${this.name} says: Quack!`);
}
}
Благодаря функции Twig {{ importmap() }}
, о которой вы узнаете в этом разделе,
файл assets/app.js
загружается и выполняется браузером.
Tip
При импорте относительных файлов обязательно добавляйте расширение .js
.
В отличие от Node, в окружении браузера расширение является обязательным.
Импорт сторонних пакетов JavaScript
Предположим, вы хотите использовать пакет npm, например bootstrap. Технически, это можно сделать, импортировав его полный URL-адрес, например, из CDN:
1
import { Alert } from 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/+esm';
Но ой! Необходимость добавления этого URL-адреса - это боль! Вместо этого мы можем добавить
его в нашу "importmap" с помощью команды importmap:require
. Эту команду можно
использовать для загрузки любого пакета npm:
1
$ php bin/console importmap:require bootstrap
Это добавляет пакет bootstrap
к вашему файлу importmap.php
:
1 2 3 4 5 6 7 8
// importmap.php
return [
// ...
'bootstrap' => [
'url' => 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/+esm',
],
];
Note
Иногда пакет - например, bootstrap
- имеет одну или несколько зависимостей,
например, @popperjs/core
. Команда importmap:require
добавит как основной пакет, так и его зависимости. Если пакет включает основной CSS-файл,
он также будет добавлен (см. Работа со сторонним CSS ).
Note
Если вы получаете ошибку 404, возможно, возникла проблема с пакетом JavaScript,
которая не позволяет ему обслуживаться CDN jsDelivr
. Например, в
в пакете могут отсутствовать такие свойства, как main
или module
в
файле конфигурации package.json. Попробуйте связаться с сопровождающим пакета и
попросить его исправить эти проблемы.
Теперь вы можете импортировать пакет bootstrap
как обычно:
1 2
import { Alert } from 'bootstrap';
// ...
Все пакеты в importmap.php
загружаются в каталог assets/vendor/
,
который должен игнорироваться git (рецепт Flex добавляет его в .gitignore
для вас).
Чтобы загрузить файлы на других компьютерах,
если некоторые из них отсутствуют, нужно выполнить следующую команду:
1
$ php bin/console importmap:install
Вы можете обновить сторонние пакеты до их актуальных версий, выполнив команду:
1 2 3 4 5 6 7 8
# перечисляет устаревшие пакеты и отображает их последние версии
$ php bin/console importmap:outdated
# обновляет все устаревшие пакеты
$ php bin/console importmap:update
# вы такожм можете выполнять команды только для заданного списка пакетов
$ php bin/console importmap:update bootstrap lodash
$ php bin/console importmap:outdated bootstrap lodash
Как работает importmap?
Как этот файл importmap.php
позволяет вам импортировать bootstrap
? Это происходит
благодаря функции Twig {{ importmap() }}
в base.html.twig
, которая
выводит importmap:
1 2 3 4 5 6 7
<script type="importmap">{
"imports": {
"app": "/assets/app-4e986c1a2318dd050b1d47db8d856278.js",
"/assets/duck.js": "/assets/duck-1b7a64b3b3d31219c262cf72521a5267.js",
"bootstrap": "https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/+esm"
}
}</script>
Импортируемые карты - это встроенная функция браузера. Они работают во всех браузерах благодаря файлу "shim", который автоматически включается компонентом AssetMapper (все современные браузеры поддерживают их нативно).
Когда вы импортируете bootstrap
из вашего JavaScript, браузер просмотрит importmap
и
увидит, что он должен получить пакет из URL.
Но откуда взялась запись импорта /assets/duck.js
? Отличный вопрос!
Файл assets/app.js
выше импортирует ./duck.js
. Когда вы импортируете файл с помощью
относительного пути, ваш браузер ищет этот файл относительно того, что импортирует его. Таким
образом, он будет искать /assets/duck.js
. Этот URL был бы правильным, за исключением того,
что файл duck.js
является версионированным. К счастью, компонент AssetMapper видит этот импорт
и добавляет маппирование из /assets/duck.js
к правильному, версионированному имени файла. Результат:
импорт ./duck.js
просто работает!
Функция importmap()
также выводит ES module shim
, чтобы
более старые браузеры понимали importmaps
(см. конфигурацию polyfill ).
Точка входа "app" и предварительная загрузка
"Точка входа" - это основной файл JavaScript, который загружает браузер, и ваше приложение по умолчанию начинается с одного из них:
1 2 3 4 5 6 7 8
// importmap.php
return [
'app' => [
'path' => './assets/app.js',
'entrypoint' => true,
],
// ...
];
В дополнение к карте импорта, { importmap('app') }}
в
base.html.twig
выводит несколько других вещей, в том числе:
1
<script type="module">import 'app';</script>
Эта строка говорит браузеру загрузить запись карты импорта app
, что приводит к выполнению
кода в файле assets/app.js
.
Функция importmap()
также выводит набор «предварительных загрузок»:
1 2
<link rel="modulepreload" href="/assets/app-4e986c1a2318dd050b1d47db8d856278.js">
<link rel="modulepreload" href="/assets/duck-1b7a64b3b3d31219c262cf72521a5267.js">
Это оптимизация производительности, о которой вы можете узнать ниже в Производительность: Добавление предварительной загрузки .
Импорт конкретных файлов из стороннего пакета
Иногда вам потребуется импортировать конкретный файл из пакета. Например, допустим, вы интегрируете highlight.js и хотите импортировать только ядро и определенный язык:
1 2 3 4 5
import hljs from 'highlight.js/lib/core';
import javascript from 'highlight.js/lib/languages/javascript';
hljs.registerLanguage('javascript', javascript);
hljs.highlightAll();
В этом случае добавление пакета highlight.js
в ваш файл importmap.php
не
сработает: что бы вы ни импортировали - например, highlight.js/lib/core
- должно
точно совпадать с записью в файле importmap.php
.
Вместо этого используйте importmap:require
и передайте ему точные пути, которые вам
нужны. Этот пример также показывает, как можно требовать несколько пакетов одновременно:
1
$ php bin/console importmap:require highlight.js/lib/core highlight.js/lib/languages/javascript
Глобальные переменные вроде jQuery
Возможно, вы привыкли полагаться на глобальные переменные, вроде переменной
$
в jQuery:
1 2 3 4 5
// assets/app.js
import 'jquery';
// app.js или любой другой файл
$('.something').hide(); // НЕ БУДЕТ РАБОТАТЬ!
Но в модульном окружении (например, в AssetMapper), когда вы импортируете библиотеку типа
jquery
, она не создаёт глобальную переменную. Вместо этого, вам следует импортировать
её и установить как переменную в каждом файле, где она вам нужна:
1 2
import $ from 'jquery';
$('.something').hide();
Вы даже можете сделать это из тега встроенного скрипта:
1 2 3 4
<script type="module">
import $ from 'jquery';
$('.something').hide();
</script>
Если вам нужно сделать что-то глобальной переменной, сделайте это вручную
изнутри app.js
:
1 2 3
import $ from 'jquery';
// речі у "window" стають глобальними змінними
window.$ = $;
Работа с CSS
CSS можно добавить на страницу, импортировав его из файла JavaScript. По умолчанию
assets/app.js
уже импортирует assets/styles/app.css
:
1 2 3 4
// assets/app.js
import '../styles/app.css';
// ...
Когда вы вызываете importmap('app')
в base.html.twig
, AssetMapper анализирует
assets/app.js
(и все JavaScript-файлы, которые он импортирует) в поисках утверждений import
для CSS-файлов. Итоговая коллекция CSS-файлов выводится на
на страницу в виде тегов link
в том порядке, в котором они были импортированы.
Note
Импорт CSS-файла не поддерживается встроенными
JavaScript модулями. AssetMapper делает это, добавляя специальную карту импорта
для каждого CSS-файла. Эти специальные записи валидны, но ничего не делают.
AssetMapper добавляет тег <link>
для каждого CSS-файла, но когда JavaScript
выполняет утверждение import
, ничего дополнительного не происходит.
Работа со сторонним CSS
Иногда пакет JavaScript содержит один или несколько файлов CSS. Например,
пакет bootstrap
содержит файл dist/css/bootstrap.min.css.
Вы можете требовать CSS-файлы так же, как и файлы JavaScript:
1
$ php bin/console importmap:require bootstrap/dist/css/bootstrap.min.css
Чтобы включить его на страницу, импортируйте его из файла JavaScript:
1 2 3 4
// assets/app.js
import 'bootstrap/dist/css/bootstrap.min.css';
// ...
Tip
Некоторые пакеты, например bootstrap
, рекламируют, что содержат файл CSS.
В этих случаях, когда вы importmap:require bootstrap
, файл CSS также добавляется в файл importmap.php
,
для удобства. Если какой-то пакет не рекламирует свой CSS-файл в свойстве style
файла конфигурации package.json, попробуйте связаться с сопровождающим пакета и
попросить его добавить это свойство.
Пути внутри CSS-файлов
Внутри CSS вы можете ссылаться на другие файлы, используя обычную функцию CSS url()
.
и относительного пути к целевому файлу:
1 2 3 4 5
/* assets/styles/app.css */
.quack {
/* file lives at assets/images/duck.png */
background-image: url('../images/duck.png');
}
Путь в финальном файле app.css
будет автоматически включать версионированный URL
для duck.png
:
1 2 3 4
/* public/assets/styles/app-3c16d9220694c0e56d8648f25e6035e9.css */
.quack {
background-image: url('../images/duck-3c16d9220694c0e56d8648f25e6035e9.png');
}
Использование Tailwind CSS
Чтобы использовать CSS-фреймворк Tailwind с компонентом AssetMapper, ознакомьтесь с
symfonycasts/tailwind-bundle
Использование Sass
Чтобы использовать Sass вместе с компонентом AssetMapper, ознакомьтесь с symfonycasts/sass-bundle.
Ленивый импорт CSS из файла JavaScript
Если у вас есть CSS, который вы хотите загрузить лениво, вы можете сделать это с помощью обычного, «динамического» синтаксиса импорта:
1 2 3 4
// assets/any-file.js
import('./lazy.css');
// ...
В этом случае lazy.css
будет загружен асинхронно, а затем добавлен на
страницу. Если вы используете динамический импорт для ленивой загрузки файла JavaScript
и этот файл импортирует CSS-файл (используя нединамический синтаксис import'
), этот CSS-файл
также будет загружен асинхронно.
Проблемы и отладка
Есть несколько распространённых проблем и ошибок с которыми вы можете столкнуться.
Отсутствует запись importmap
Одна из самых распространённых ошибок будет выходить из консоли вашего браузера и будет примерно такой:
Failed to resolve module specifier " bootstrap". Relative references must start with either "/", "./", or "../".
Или:
The specifier "bootstrap" was a bare specifier, but was not remapped to anything. Relative module specifiers must start with "./", "../" or "/".
Это означает, что где-то в вашем JavaScript вы импортируете сторонний пакет, например,
import 'bootstrap'
. Браузер пытается найти этот пакет в вашем файле importmap
,
но его там нет.
Почти всегда это можно исправить, добавив его в ваш importmap
:
1
$ php bin/console importmap:require bootstrap
Note
Некоторые браузеры, такие как Firefox, показывают где находится этот код "импорта", тогда как другие, например, Chrome, пока это не показывают.
404 Не найдено для файла JavaScript, CSS или изображения
Иногда файл JavaScript, который вы импортируете (например, import './duck.js'
) или файл
CSS/изображения, на который вы ссылаетесь, не будет найден, и вы увидите ошибку 404 в консоли
вашего браузера. Вы также заметите, что в URL 404 отсутствует хеш версии в имени файла (например,
404 к /assets/duck.js
вместо пути вроде /assets/duck.1b7a64b3b3d31219c262cf72521a5267.js
).
Обычно это происходит потому, что путь указан неправильно. Если вы ссылаетесь на файл непосредственно в шаблоне Twig:
1
<img src="{{ asset('images/duck.png') }}">
Тогда путь, который вы передаёте asset()
должен быть "логическим путем" к файлу.
Используйте команду debug:asset-map
, чтобы увидеть все валидные логические пути
в вашем приложении.
Скорее всего, вы импортируете неработающий ресурс из файла CSS (например
@import url('other.css')
) или файла JavaScript:
1 2
// assets/controllers/farm-controller.js
import '../farm/chicken.js';
При этом путь должен быть относительным к файлу, который его импортирует (а в JavaScript-файлах
он должен начинаться с ./
или ../
). В этом случае ../farm/chicken.js
будет
указывать на assets/farm/chicken.js
. Чтобы просмотреть список всех невалидных импортированных
данных в вашем приложении, выполните:
1 2
$ php bin/console cache:clear
$ php bin/console debug:asset-map
Любой невалидный импорт будет показан в виде предупреждений в верхней части экрана
(убедитесь, что у вас установлен symfony/monolog-bundle
):
1 2
WARNING [asset_mapper] Unable to find asset "../images/ducks.png" referenced in "assets/styles/app.css".
WARNING [asset_mapper] Unable to find asset "./ducks.js" imported from "assets/app.js".
Предупреждение об отсутствующем ресурсе в комментируемом коде
Компонент AssetMapper ищет в ваших файлах JavaScript строки import
, чтобы он мог
автоматически добавить их в вашу карту импорта . Это делается
через регулярное выражение и работает очень хорошо, хотя и не идеально. Если вы закомментируете импорт,
он всё равно будет найден и добавлен в вашу карту импорта. Это ничему не навредит, но может
быть неожиданностью.
Если импортированный путь не будет найден, вы увидите предупреждение при создании этого ресурса, которое вы можете проигнорировать.
Развертывание с компонентом AssetMapper
Когда вы будете готовы к развёртыванию, "скомпилируйте" свои ресурсы во время развёртывания:
1
$ php bin/console asset-map:compile
Готово! Это запишет все ваши ресурсы в каталог public/assets/
, вместе с несколькими JSON-файлами,
чтобы importmap
можно было отобразить молниеносно быстро.
Но чтобы гарантировать, что ваш сайт производительный, убедитесь, что ваш веб-сервер (или прокси) использует HTTP/2, сжимает ваши ресурсы и устанавливает долговременные заголовки Expires для них. Смотрите Оптимизация для более подробной информации.
Оптимизация продуктивности
Чтобы ваш сайт на основе AssetMapper работал без сбоев, вам нужно сделать несколько вещей. Если вы хотите сократить путь, вы можете воспользоваться таким сервисом, как Cloudflare, который автоматически сделает большинство из этих действий за вас:
- Используйте HTTP/2: Ваш веб-сервер должен работать по протоколу HTTP/2 (или HTTP/3), чтобы браузер мог загружать ресурсы параллельно. HTTP/2 автоматически включён в Caddy и может быть активирован в Nginx и Apache. Или проксируйте ваш сайт через сервис, например, Cloudflare, который автоматически включит HTTP/2 для вас.
- Сжимайте свои ресурсы: Ваш веб-сервер должен сжимать (например, с помощью gzip) ваши ресурсы (JavaScript, CSS, изображения) перед отправкой их браузеру. Эта функция автоматически включается в Caddy и может быть активирована в Nginx и Apache. Или же проксируйте ваш сайт через сервис вроде Cloudflare, который автоматически будет сжимать ваши ресурсы за вас. В Cloudflare вы также можете включить auto minify для дальнейшего сжатия ваших ресурсов (например, удаления пробелов и комментариев из файлов JavaScript и CSS).
- Установите длительный срок действия кеша: Ваш веб-сервер должен установить долгоживущий
HTTP-заголовок
Cache-Control
для ваших ресурсов. Поскольку компонент AssetMapper включает хеш версии в имени файла каждого ресурса, вы можете смело установитьmax-age
на очень большой срок (например, 1 год). Это не является автоматическим ни в одном веб-сервере, но это можно легко включить.
После того, как вы выполнили эти действия, вы можете использовать такой инструмент, как Lighthouse для проверки производительности вашего сайта!
Продуктивность: добавление предварительной загрузки
Одна из распространённых проблем, про которую может сообщить LightHouse, следующая:
Avoid Chaining Critical Requests
Несколько элементов в этом списке - это нормально. Но если этот список длинный или некоторые элементы находятся на глубине многих уровней, то вам это нужно исправить с помощью "предварительной загрузки". Чтобы понять проблему, представьте, что у вас такая настройка:
assets/app.js
импортирует./duck.js
assets/duck.js
импортируетbootstrap
Когда браузер загружает страницу, происходит следующее:
- Браузер загружает
assets/app.js
; - Потом он видит импорт
./duck.js
и загружаетassets/duck.js
; - Потом он видит импорт
bootstrap
и загружаетassets/bootstrap.js
.
Вместо того, чтобы загрузить все 3 файла параллельно, браузер вынужден загружать их по очереди по мере их обнаружения. Это негативно влияет на производительность.
AssetMapper избегает этой проблемы, выводя «предзагрузочные» теги link
.
Логика работает следующим образом:
A) Когда вы вызываете importmap('app'')
в вашем шаблоне, компонент AssetMapper
просматривает файл assets/app.js
и находит все файлы JavaScript
которые он импортирует, или файлы, которые импортируют эти файлы, и т. д.
В) Затем он выводит тег link
для каждого из этих файлов с атрибутом rel="preload"
.
Это указывает браузеру на необходимость немедленно начать загрузку этих файлов,
даже если он еще не видел утверждения import
для них.
Кроме того, если в вашем приложении имеется Компонент WebLink,
Symfony добавит в ответ заголовок Link
для предварительной загрузки CSS-файлов.
Часто задаваемые вопросы
Объединяет ли компонент AssetMapper ресурсы?
Нет! Но это потому, что в этом больше нет необходимости!
В прошлом было принято объединять ресурсы, чтобы уменьшить количество HTTP-запросов, которые
были сделаны. Благодаря развитию веб-серверов, таких как HTTP/2, обычно не проблема
держать ваши ресурсы отдельно и позволить браузеру загружать их параллельно. На самом деле,
если вы держите их отдельно, когда вы обновляете один ресурс, браузер может продолжать
использовать кешированную версию всех остальных ваших ресурсов.
Смотрите Оптимизация для получения более подробной информации.
Минимизирует ли компонент AssetMapper ресурсы?
Нет! Минимизация или сжатие ресурсов важна, но может быть выполнена вашим веб-сервером или с помощью сервиса вроде Cloudflare. Смотрите Оптимизация для более подробной информации.
Готов ли компонент AssetMapper к производству? Он производительный?
Да! Очень! Компонент AssetMapper использует достижения в технологиях браузеров (например
importmaps и нативную поддержку import
) и веб-серверов (например, HTTP/2, который позволяет
ресурсам загружаться параллельно). Смотрите другие вопросы о минимизации и комбинировании
и Оптимизацию для более подробной информации.
Сайт https://ux.symfony.com работает на компоненте AssetMapper и имеет 99% оценку от Google Lighthouse.
Работает ли компонент AssetMapper со всеми браузерами?
Да! Такие функции, как importmaps и утверждение import
поддерживаются
во всех современных браузерах, но компонент AssetMapper поставляется с ES-модулем shim
для поддержки importmap
в старых браузерах. Итак, он работает везде (см. примечание
ниже).
В вашем собственном коде, если вы полагаетесь на современные возможности функций JavaScript ES6, например, синтаксис классов, это поддерживается во всех браузерах, кроме самых старых. Если вам необходимо поддерживать очень старые браузеры, вам следует использовать такой инструмент, как Encore вместо компонента AssetMapper.
Note
Утверждение import не может быть полизаполненным или шимминговым, чтобы работать во всех браузерах. Однако только старейшие браузеры не поддерживают его - в основном IE 11 (который больше не поддерживается Microsoft и имеет менее 0.4% глобального использования).
Функция importmap
настраивается для работы во всех браузерах с помощью
компонента AssetMapper. Однако, шим не работает с "динамическим" импортом:
1 2 3 4 5 6 7
// это работает
import { add } from './math.js';
// это не будет работать в старейших браузерах
import('./math.js').then(({ add }) => {
// ...
});
Если вы хотите использовать динамический импорт и вам нужна поддержка определённых старых браузеров
(https://caniuse.com/import-maps), вы можете воспользоваться функцией importShim()
из
shim: https://www.npmjs.com/package/es-module-shims#user-content-polyfill-edge-case-dynamic-import
Могу ли я использовать это с Sass или Tailwind?
Конечно! Смотрите Использование Tailwind CSS или Использование Sass .
Могу ли я использовать это с TypeScript?
Конечно! Смотрите Использование TypeScript .
Могу ли я использовать это с JSX или Vue?
Наверное, нет. А если вы пишете приложение на React, Svelte или другом фронтенд-фреймворке, вам, вероятно, будет лучше использовать их инструменты напрямую.
JSX можно скомпилировать непосредственно в нативный JavaScript-файл, но если вы используете много JSX, вам, вероятно, захочется использовать инструмент вроде Encore . Смотрите Документацию UX React для более подробной информации об использовании с компонентом AssetMapper.
Vue-файлы могут быть написаны на нативном JavaScript, и они будут работать с
компонентом AssetMapper. Но вы не можете писать однофайловые компоненты (то есть файлы
.vue
) с помощью компонента, поскольку они должны быть использованы в системе сборки.
Обратитесь к Документации UX Vue.js для более подробной информации об использовании с
с компонентом AssetMapper.
Использование TypeScript
Чтобы использовать TypeScript с компонентом AssetMapper, ознакомьтесь с sensiolabs/typescript-bundle.
Сторонние пакеты и пользовательские пути ресурсов
Ко всем пакетам, которые имеют каталог Resources/public/
или public/
, будет
автоматически добавлен этот каталог как "путь ресурсов" с помощью пространства имён:
bundles/<BundleName>
. Например, если вы используете BabdevPagerfantaBundle
и выполните команду debug:asset-map
, вы увидите ресурс, логический путь к которому
будет bundles/babdevpagerfanta/css/pagerfanta.css
.
Это означает, что вы можете отображать эти ресурсы в своих шаблонах с помощью функции
asset()
:
1
<link rel="stylesheet" href="{{ asset('bundles/babdevpagerfanta/css/pagerfanta.css') }}">
На самом деле, этот путь - bundles/babdevpagerfanta/css/pagerfanta.css
- уже
работает в приложениях без компонента AssetMapper, поскольку команда assets:install
копирует ресурсы из пакетов в public/bundles/
. Однако, когда компонент AssetMapper включён,
файл pagerfanta.css
будет автоматически версионирован! В результате будет выведено что-то вроде:
1
<link rel="stylesheet" href="/assets/bundles/babdevpagerfanta/css/pagerfanta-ea64fc9c55f8394e696554f8aeb81a8e.css">
Переопределение сторонних ресурсов
Если вы хотите переопределить сторонний ресурс, вы можете сделать это, создав файл
в вашем каталоге assets/
с тем же именем. Например, если вы хотите переопределить
файл pagerfanta.css
, создайте файл по адресу assets/bundles/babdevpagerfanta/css/pagerfanta.css
.
Этот файл будет использоваться вместо оригинального файла.
Note
Если пакет отображает свои собственные ресурсы, но они используют не пакет по умолчанию пакет ресурсов , то компонент AssetMapper не будет использоваться. Это происходит, например, с EasyAdminBundle.
Импорт ресурсов вне каталога assets/
Вы можете импортировать ресурсы, которые находятся вне вашего пути к ресурсам
(т.е. каталога assets/
). Например:
1 2 3 4
/* assets/styles/app.css */
/* вы можете достичь ресурсов выше/ */
@import url('../../vendor/babdev/pagerfanta-bundle/Resources/public/css/pagerfanta.css');
Однако если вы получите ошибку, подобную этой:
В записи "app" карты импорта содержится путь "vendor/some/package/assets/foo.js" но, похоже, его нет ни в одном из ваших путей к ресурсам.
Это означает, что вы указываете на валидный файл, но этого файла нет ни в одном из ваших
путей к ресурсам. Вы можете исправить это, добавив путь к вашему файлу asset_mapper.yaml
:
1 2 3 4 5 6
# config/packages/asset_mapper.yaml
framework:
asset_mapper:
paths:
- assets/
- vendor/some/package/assets
Затем попробуйте ещё раз выполнить команду.
Опции конфигурации
Вы можете увидеть все доступные опции конфигурации и некоторую информацию, выполнив:
1
$ php bin/console config:dump framework asset_mapper
Некоторые из самых важных опций описаны ниже.
framework.asset_mapper.paths
Эта конфигурация содержит все каталоги, которые будут просканированы на наличие ресурсов. Это может быть простым списком:
1 2 3 4 5
framework:
asset_mapper:
paths:
- assets/
- vendor/some/package/assets
Вы можете предоставить каждому пути "пространство имён", которое будет использовано в карте ресурсов:
1 2 3 4 5
framework:
asset_mapper:
paths:
assets/: ''
vendor/some/package/assets/: 'some-package'
В этом случае "логический путь" ко всем файлам в каталоге vendor/some/package/assets/
будет дополнен префиксом some-package
- например, some-package/foo.js
.
framework.asset_mapper.excluded_patterns
Это список глобальных паттернов, которые будут исключены из карты ресурсов:
1 2 3 4
framework:
asset_mapper:
excluded_patterns:
- '*/*.scss'
Вы можете использовать команду debug:asset-map
, чтобы проверить, что ожидаемые вами
файлы включены в карту ресурсов.
framework.asset_mapper.exclude_dotfiles
Нужно ли исключать из маппера ресурсов все файлы, начинающиеся с .
. Этот
полезно, если вы хотите избежать утечки чувствительных файлов, таких как .env
или
.gitignore
в файлах, опубликованных маппером ресурсов.
1 2 3
framework:
asset_mapper:
exclude_dotfiles: true
Эта опция включена по умолчанию.
framework.asset_mapper.importmap_polyfill
Сконфигурируйте полизаполнение для старых браузеров. По умолчанию модуль ES shim загружается через CDN (т.е. значение по умолчанию для этой настройки - `es-module-shims`):
1 2 3 4 5 6 7 8 9
framework:
asset_mapper:
# установите эту опцию как false, чтобы отключить shim полностью
# (ваше приложение website/web не будет работать в старых браузерах)
importmap_polyfill: false
# вы также можете использовать пользовательское полизаполнение, добавив его к вашему файлу importmap.php
# и установив эту опцию как ключ этого файла в файле importmap.php
# importmap_polyfill: 'custom_polyfill'
Tip
Вы можете указать AssetMapper загружать ES модуль shim локально,
используя следующую команду, без изменения вашей конфигурации:
1
$ php bin/console importmap:require es-module-shims
framework.asset_mapper.importmap_script_attributes
Это список атрибутов, которые будут добавлены к тегам <script>
, отображённых функцией
Twig {{ importmap() }}}
:
1 2 3 4
framework:
asset_mapper:
importmap_script_attributes:
crossorigin: 'anonymous'
CSS и JavaScript для конкретных страниц
Иногда вы можете решить разместить файлы CSS или JavaScript только на определенных
страницах. Для JavaScript простым способом является загрузка файла с помощью динамического импорта:
1 2 3 4 5 6 7
const someCondition = '...';
if (someCondition) {
import('./some-file.js');
// or use async/await
// const something = await import('./some-file.js');
}
Another option is to create a separate entrypoint . For
example, create a checkout.js
file that contains whatever JavaScript and
CSS you need:
1 2 3 4
// assets/checkout.js
import './checkout.css';
// ...
Затем добавьте это в файл importmap.php
и отметьте его как точку входа:
1 2 3 4 5 6 7 8 9
// importmap.php
return [
// точка входа 'app' ...
'checkout' => [
'path' => './assets/checkout.js',
'entrypoint' => true,
],
];
Наконец, на странице, которой нужен этот JavaScript, вызовите importmap()
и передайте
как app
, так и checkout
:
1 2 3 4 5 6 7 8 9 10
{# templates/products/checkout.html.twig #}
{#
Переопределите блок "importmap" из base.html.twig.
Если у вас нет этого блока, добавьте его вокруг вызова {{ importmap('app') }}.
#}
{% block importmap %}
{# НЕ вызывайте parent() #}
{{ importmap(['app', 'checkout']) }}
{% endblock %}
При передаче как app
, так и checkout
, функция importmap()
выведет importmap
, а также добавит тег <script type=«module»>
, который
загружает файл app.js
и файл checkout.js
. Важно
не вызывать parent()
в блоке importmap
. Каждая страница может иметь только
иметь одну карту импорта, поэтому importmap()
должен быть вызван ровно один раз.
Если по какой-то причине вы хотите выполнить только checkout.js
а не app.js
, передайте в importmap()
только checkout
.
Система кеширования компонента AssetMapper в разработке
Во время разработки вашего приложения в режиме отладки, компонент AssetMapper будет вычислять содержание каждого файла ресурсов и кешировать его. Каждый раз, когда этот файл изменяется, компонент автоматически перевычислит содержание.
Система также учитывает "зависимости": Если app.css
содержит @import url('other.css')
,
то содержание файла app.css
также будет перевычисляться каждый раз, когда будет меняться other.css
.
Это связано с тем, что хеш версии other.css
изменится... что приведёт к изменению конечного содержания
app.css
, поскольку он содержит в себе финальное имя файла other.css
.
По большей части эта система просто работает. Но если у вас есть файл, который не перевычисляется, когда вы этого ожидаете, вы можете выполнить:
1
$ php bin/console cache:clear
Это заставит компонент AssetMapper перевычислить содержание всех файлов.
Проводите аудиты безопасности ваших зависимостей
Подобно npm
, компонент AssetMapper поставляется в комплекте с командой,
которая проверяет уязвимости безопасности в зависимостях вашего приложения:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
$ php bin/console importmap:audit
---------- -------------------------------------------------- --------- ------- ------------ -----------------------------------------------------
Тяжесть Название Пакет Версия Исправлено в Больше информации
---------- -------------------------------------------------- --------- ------- ------------ -----------------------------------------------------
Средняя Уязвимость межсайтового скриптинга в jQuery jquery 3.3.1 3.5.0 https://api.github.com/advisories/GHSA-257q-pV89-V3xv
Серьезная Загрязнение прототипов в JSON5 через метод разбора json5 1.0.0 1.0.2 https://api.github.com/advisories/GHSA-9c47-m6qq-7p4h
Средняя semver уязвима к отказу в обслуживании RegExp semver 4.3.0 5.7.2 https://api.github.com/advisories/GHSA-c2qf-rxjj-qqgw
Критичная Прототип загрязнения в minimist minimist 1.1.3 1.2.6 https://api.github.com/advisories/GHSA-xvch-5gv4-984h
Средняя Зависимости ESLint уязвимы minimist 1.1.3 1.2.2 https://api.github.com/advisories/GHSA-7fhm-mqm4-2wp7
Средняя Bootstrap уязвим для межсайтового скриптинга bootstrap 4.1.3 4.3.1 https://api.github.com/advisories/GHSA-9v3M-8fp8-mi99
---------- -------------------------------------------------- --------- ------- ------------ -----------------------------------------------------
7 пакетов найдено: 7 аудировано / 0 пропущено
6 уязвимостей найдено: 1 критичная / 1 серьезная / 4 средних
Команда вернет код выхода 0
, если уязвимость не найдена, или
код выхода 1
в противном случае. Это означает, что вы можете легко интегрировать эту
команду в свой CI, чтобы получать предупреждение при обнаружении новой уязвимости.
Tip
Команда принимает опцию --format
для выбора формата вывода между
txt
и json
.