из https://github.com/less/less.js/issues/2541, но я видел это в проектах
// mixins.less
.background(@image) {
background-image: data-uri(@image);
}
// app/content/button.less
button {
.background("images/btn.jpg");
}
Я ожидал бы, что изображение будет получено из app/content/images/btn.jpg
но оно будет получено из images/btn.jpg
.
Я приветствую отзывы о том, является ли это критическим изменением (требующим серьезного обновления) или исправлением ошибки.
Я приветствую отзывы о том, является ли это критическим изменением (требующим серьезного обновления) или исправлением ошибки.
К вашему сведению: вы можете элегантно реализовать это без нарушения обратной совместимости очень простым способом.
В настоящее время функция data-uri()
принимает узел дерева Quoted
содержащий строку в качестве пути к файлу, и разрешает его внутренне как URL-адрес относительно местоположения файла, содержащего вызов функции. Вы можете перегрузить функцию data-uri
чтобы она также принимала узел дерева Url
содержащий фактический URL. Таким образом, URL-адрес должен нормализоваться относительно места, где вызывается функция url()
CSS, и больше не должен нормализоваться внутри функции data-uri()
Less.
Например
// app/content/button.less
button {
.background(url("images/btn.jpg"));
}
@rjgotten
Для меня это больше похоже на обходной путь, чем на исправление. На следующей итерации они _попытаются избежать многословия, переместив url
в миксин, и проблема возникнет снова. Другая проблема заключается в том, что, взяв исходный вариант использования, из которого возникла эта проблема (# 2541), его часто используют следующим образом:
// mixins.less
.background(@image) {
background-image: data-uri("@{image}.jpg");
}
// app/content/button.less
button {
.background("images/btn");
}
(Например, для миксина font-face это обычно несколько расширений woff
, ttf
, eot
, eot?#iefix
и т. Д., Добавленных к одному и тому же имени файла. ). И таким образом нельзя и предыдущий url
.
@ семь фаз-макс
Тогда я действительно не думаю, что есть подходящий период решения. Вам нужен способ определения контекста, в котором должен разрешаться относительный URL. Либо вы берете этот контекст из информации о файле, который определяет строковое значение, входящее в функцию data-uri()
, либо вы делаете точку отсечения более явной с помощью функции url()
и Url
узел дерева.
Если вы хотите поддерживать подстановку переменных пути, тогда все быстро усложняется, потому что вам нужно выяснить, как нужно нормализовать различные части пути.
Например, как нормализовать что-то вроде:
// mixins.less
.background(@image) {
background-image: data-uri("../../@{image}.jpg");
}
// app/content/button.less
button {
.background("../images/btn");
}
Как бы вы совместили относительное разрешение URL и комбинацию этих двух путей, основанную на подстановке токенов?
Я полагаю, что один из вариантов - разрешить только файл, определяющий строку, которая заменяется токеном-заменителем, когда токен-заменитель находится во главе конечного значения URL-адреса, переходящего в url()
или data-uri()
function и игнорируйте такие случаи, как приведенный выше. Это кажется наиболее логичным.
Другим решением может быть введение некоторых функций обработки пути для объединения путей или добавления / удаления / редактирования расширений файлов (возможно, аналогично тому, как функция unit()
работает для измерений?) И сделать вещи более явными.
Например
// mixins.less
.background(@image) {
background-image: data-uri(extension(<strong i="21">@image</strong>, "jpg"));
}
// app/content/button.less
button {
.background(url("./images/btn"));
}
Для вашего первого примера никакой специальной нормализации не требуется, "../../@{image}.jpg"
расширяется до "../../../images/btn.jpg"
как написано (а затем до data-uri
для обработки пути).
И второй пример - это просто ... наложение функции для обхода функции для обхода обратной совместимости с ... с чем именно? _Неверные_ пути к файлам при вызове миксина, определенного в другом файле?
В конце концов, если предполагается, что он будет работать «как ожидалось» _только_ с .background(url("images/btn.jpg"));
, чем это отличается от простого написания .background(data-uri("images/btn.jpg"));
напрямую без каких-либо изменений? :)
Другими словами, я имею в виду, что если это должно быть исправлено, то оно должно быть исправлено прямо с помощью data-uri
независимо от того, насколько это может быть нарушено. (Честно говоря, я не знаю, какая стратегия была бы лучше: а. Дождаться большего количества отчетов / запросов по этому поводу, а затем (если их достаточно) изменить или б. Изменить его раньше, чтобы минимизировать возможное разрушающее воздействие).
Другими словами, если предположить, что url
и data-uri
изначально были разработаны как взаимозаменяемые (т.е. data-uri
- это просто специальная версия url
(и компилируется в CSS url
в конце)), было бы довольно болезненно описывать, почему именно ulr
ведет себя «вот так» (с такими параметрами), а data-uri
ведет себя «так» (с варианты, подобные этому), и для получения определенного поведения вам понадобится комбо data-uri(url())
, ограниченное " data-uri
внутри миксина и url
_out_ его с --relative-urls: on
"<- Бхрррр ... :)
Для меня это больше похоже на обходной путь, чем на исправление. При дальнейшей итерации они попытаются избежать многословия, переместив url в миксин, и проблема возникнет снова.
Да я согласен.
Я медленно пытаюсь нарастить, приложив немного больше усилий к меньшему для выпуска v3, и просто исправляю это.
Я думал о том, чтобы разработать все возможные пути к файлам и попробовать их один за другим - хотя это немного неприятно, если есть несколько файлов в разных местах ... Я думаю, что согласен, что это невозможно полностью исправить навсегда, но, по крайней мере, мы можем исправить нормальный случай.
Возможно, функция resolve()
может помочь передать разрешенный URL-адрес функциям (но тогда, если это не полный путь, который не будет работать, и полный путь будет работать, когда это будет исправлено ...)
Простите, что быстро записываю мысли.
Это всего лишь краткое примечание, но у нас будет такая же проблема с импортом с использованием интерполяции переменных.
импорт с использованием интерполяции переменных.
Это и интересно, и тревожно.
Это действительно поддерживаемый вариант использования или счастливое совпадение?
@rjgotten Поддерживается, но несколько ограничена. Он отслеживался в # 410
Это работает:
<strong i="8">@variable</strong>: "path.less";
<strong i="9">@import</strong> "@{variable}";
Это не так:
.mixin(@variable) {
<strong i="13">@import</strong> "@{variable}";
}
Изменить: изменено, чтобы ссылка работала.
Я не уверен, что хочу поддерживать переменные @import
в миксинах.
Вся эта штука с импортом переменных немного волшебна и может создать некоторый нелогичный код ... так что я бы предпочел отговорить это.
Много обсуждений обходного пути, может быть, просто решить настоящую проблему? Разве не ясно, что data-uri должен относиться к обрабатываемому файлу.
Прямо сейчас у меня есть файл, который импортирует ссылку с другого пути, и он все еще жалуется на data-uri. По крайней мере, это, должно быть, ошибка? Я имею в виду, что если я импортирую по ссылке, он не должен пытаться переписать пути относительно текущего файла.
@Ciantic
Я имею в виду, что если я импортирую по ссылке, он не должен пытаться переписать пути относительно текущего файла.
На чем именно? При чем здесь reference
?
Прямо сейчас у меня есть файл, который импортирует ссылку с другого пути, и он все еще жалуется на data-uri.
Похоже, что это противоположно проблеме, описанной выше. Не могли бы вы предоставить более подробную информацию? (например, пути к импортируемым, импортированным файлам и файлам данных и т. д.).
styles.less
.something {
background: data-uri("some.svg");
}
sub / test.less
<strong i="11">@import</strong> (reference) "../style.less";
.test {
color: green;
}
Он компилирует style.less, но не test.less, потому что пытается использовать data-uri относительно test.less.
Зачем ссылочный импорт пытается переписать пути, на мой взгляд, при использовании ссылок это не обязательно.
Я ожидаю, что data-uri будет следовать правилам перезаписи URL в опциях. Конечно .... трудно сказать, что это на самом деле означает с data-uri.
В общем, data-uri должен разрешаться относительно "вызывающего файла .less". Таким образом, в случае миксина, он должен разрешаться относительно того, где вызывается миксин, а не относительно местоположения миксина. Миксин «подмешивает» эти операторы, а затем разрешает их. Итак, @lukeapage, я думаю, ваша интерпретация верна:
// app/content/button.less
button {
.background("images/btn.jpg");
}
Он должен искать btn.jpg по адресу app/content/images/
. Если это не так, это ошибка, потому что миксины не должны работать так. Я не думаю, что это «критическое изменение», а исправление ошибки.
Тем не менее ... Я не думаю, что возникнет проблема с решением вроде:
Node.js пытается разрешить несколько путей. Если порядок разрешения проблемы четко задокументирован, вы можете управлять своими ожиданиями. И это означало бы, что если бы кто-то основал свое поведение №2 .less to do, оно все равно сработало бы почти во всех, если не во всех случаях.
@ Мэтью-Дин
В общем, data-uri должен разрешаться относительно "вызывающего файла .less". Таким образом, в случае миксина, он должен разрешаться относительно того, где вызывается миксин, а не относительно местоположения миксина. Миксин «подмешивает» эти операторы, а затем разрешает их.
Вы никогда не сможете заставить эту работу работать так, чтобы это было в целом правильным для всех вариантов использования.
Например, как бы вы поддержали параметризованные URL-адреса, т. Е. URL-адреса с заменяющими токенами, которые должны быть сопоставлены с некоторой известной базовой папкой с заполненными только заменяющими токенами? В этом случае требуется восстановление файла вызываемого, а не файла вызывающего абонента.
У меня было небольшое прозрение о том, как исправить это прозрачно, без явного использования url()
на сайте вызова, который @ seven-phase-max справедливо назвал плохой идеей (потому что кто-то в конечном итоге _попытается_ реорганизуйте его в вызов миксина и сломайте вещи):
При создании буквальных узлов Quoted
сохраните информацию об их файлах. Распространение этой информации с помощью присвоений переменных, вызовов миксинов и т. Д. Любое значение Quoted
происходящее из файла вызывающего абонента, при обработке url()
или data-uri()
будет разрешено для этого файла вызывающего абонента. . Но значение Quoted
которое является частью некоторой внутренней логики миксина, все же разрешается относительно локального файла миксина.
Благодаря этому все работает должным образом, за исключением сценария со строками подстановки, например:
// mixins.less
.background(@image) {
background-image: data-uri("@{image}.jpg");
}
// app/content/button.less
button {
.background("images/btn");
}
Есть уловка, которую вы также можете исправить, чтобы исправить это: при заполнении токенов подстановки, если токен находится в самом начале строки подстановки, тогда результирующая строка должна наследовать информацию о файле из заполненного токена, а не этого строки подстановки.
Если намерение собственного автора миксина состоит в том, чтобы разрешить такие пути относительно файла миксина, он все равно может заставить это работать, используя, например, "./@{image}.jpg"
в качестве шаблона. Это эффективно перекладывает бремя ответственности с вызывающего абонента, что вам и нужно.
// _mixins.less
.sprite(@image) {
background: data-uri("../images/sprites/@{image}.png") no-repeat;
}
// main.less
div {
.sprite('logo');
}
выход:
div {
background: url(data:image/png;base64,...) no-repeat;
}
Вау, это очень старый ... мои два цента, так как эта проблема затрагивает и меня.
Как насчет добавления опции к функции url или создания новой функции, которая решит URL как абсолютный. Таким образом, независимо от того, где установлен миксин, он будет работать с абсолютными путями и не будет места для ошибок.
Как насчет добавления опции к функции url или создания новой функции, которая решит URL как абсолютный. Таким образом, независимо от того, где установлен миксин, он будет работать с абсолютными путями и не будет места для ошибок.
Проблема здесь не в абсолютных и относительных путях. Речь шла о родственнике против сайта звонка против родственника против сайта объявления. Совсем другая проблема.
Возможно, проблема эволюционировала, но первоначальный комментарий и заголовок относятся к data-uri, разрешающему путь по отношению к файлу, из которого он был вызван, что в сочетании с миксином, размещенным в другом месте, может неправильно разрешить путь. Что ж, это проблема, с которой я столкнулся.
Так где же в этом решении учитываются абсолютные пути?
Предполагая, что data-uri принимает абсолютные пути и существует гипотетическая функция absolute-url
, следующий код будет работать независимо от того, где размещен миксин.
// mixins.less
.background(@image) {
background-image: data-uri(@image);
}
// app/content/button.less
button {
.background(absolute-url("images/btn.jpg"));
}
@ miljan-aleksic Под "абсолютным" вы подразумеваете относительно файла по адресу data-uri
? Если так, вероятно, термин «абсолютный» - неправильный.
Похоже, что функциональная оболочка для URL-адреса, позволяющая сделать любой URL-адрес относительным к файлу, является хорошим подходом. Или дополнительный аргумент для url ().
@ matthew-dean, под абсолютным я подразумеваю полный путь к файлу, например: /users/myuser/projects/lessproject/icon.svg
.
Я не понимаю вашего подхода, поскольку я не понимаю, как url () может создать относительный путь к файлу местоположения data-uri, не зная об этом.
Похоже, что функциональная оболочка для URL-адреса, позволяющая сделать любой URL-адрес относительным к файлу, является хорошим подходом. Или дополнительный аргумент для url ().
Как ни странно; это почти то, что я предлагал несколько лет назад. ;-)
под абсолютным я подразумеваю полный путь к файлу, например: /users/myuser/projects/lessproject/icon.svg.
Похоже, что с absolute вы имеете в виду эту absolute-url
function _pre-resolves_ относительный путь, переданный ей к полному пути вывода, в зависимости от местоположения файла, в котором вызывается функция absolute-url
, относительно места, куда будет помещен скомпилированный выходной файл CSS.
Т.е. вы оба имеете в виду одно и то же. Как и я в то время.
это полный путь вывода, основанный на расположении файла, в котором вызывается функция absolute-url, относительно места, куда будет помещен скомпилированный выходной файл CSS.
Например, перезапись URL-адресов или корневого пути все равно будет применяться, но на основе местоположения определения? Это немного отличается от исходного примера @lukeapage , в котором говорилось не об URL-адресах относительно вывода, а об URL-адресах _ во время компиляции_; например, расположение data-uri()
.
Так что эту проблему немного сложно отследить, потому что люди писали о похожих, но не совсем идентичных проблемах. То есть, изменение относительного _ источника_, вероятно, потребует совершенно другого решения, чем изменение относительного _output_. Или, возможно, нет; это зависит от логики пути; но мы должны понимать, что data-uri не производит никакого пути в качестве вывода.
Может нам понадобится что-то вроде resolve()
? Я не знаю, просто плевать, но url(resolve(file(), "my/path"))
? Я предполагаю, что это то, что @ miljan-aleksic имел в виду под absolute()
, поскольку он разрешался в абсолютный URL. Но он все равно должен принимать входные данные (например, file()
, чтобы разрешить против). В противном случае вы могли бы сделать что-то вроде file-resolve()
чтобы обозначить эту логику в одной функции, но наличие resolve()
и file()
качестве двух функций может быть полезно по отдельности.
Сложная часть всего этого - это все варианты перезаписи URL-адресов, которых теперь стало больше после слияния PR, которое добавило поддержку модуля. (https://github.com/less/less.js/pull/3248). Итак, если он возвращает URL-адрес, относящийся к файлу, можно ли его переписать? Я предполагаю, что да, но нам нужно внести ясность.
Да, resolve () и file () точно определяют то, что я пытался объяснить. Я надеюсь, что мы сможем увидеть это в ближайшем будущем.
@ miljan-aleksic Хорошо, тогда в этом есть смысл.
На самом деле file()
не совсем правильно, поскольку это вернет имя файла, которое, как я полагаю, будет больше похоже на dir()
. И, вероятно, это должна быть переменная константа для каждого файла.
Как насчет:
data-uri(resolve(<strong i="10">@DIR</strong>, "my/path"))
Итак, добавлены две вещи: 1) функция resolve () для объединения путей, 2) константа @DIR
(и @FILE
?), Вводимая в каждый файл при оценке. Единственная сложная вещь в этом - это проверка того, что эти внедренные вары не переопределяют и не объединяются с другими варами в корне, но это должно быть довольно просто проверить. Или они должны быть строчными, например @arguments
? В этом случае я бы предложил @directory
и @filename
чтобы избежать конфликтов. Какой вариант наименее удобен?
Может нам понадобится что-то вроде
resolve()
?
^ Бинго. Именно так.
Какой вариант наименее удобен?
Я бы выбрал вариант Node.js-y: __dirname
Он существует уже давно и хорошо известен. Использование того же имени для одной и той же концепции в Less может быть хорошей идеей.
Я бы выбрал вариант Node.js-y: __dirname
Эээ ... это не соответствует ключевому слову Less / CSS, переменной Less или семантике функции. Мы должны сделать лучше, чем это. @__dirname
возможно, но подчеркивания все еще немного странные для языка. Это совсем не подходит.
подчеркивание все еще немного странно для языка. Это совсем не подходит.
Двойное подчеркивание в начале используется для обозначения «чего-то, что предоставляет система» на многих языках, особенно когда речь идет о таких вещах, как внутренние переменные. Так что не на своем месте здесь что-то вроде того.
Конечно; если вам это не нравится, вы всегда можете использовать производную, например @dirname
или @dir-name
.
Однако, подумав об этом еще раз, зачем нам вообще _ нужен_ текущий путь к файлу, представленный как переменная? Разве это нельзя вплести в концептуальную функцию resolve()
?
Разве это нельзя вплести в саму концептуальную функцию resolve ()?
И мы вернулись к моему предложению, только с другим именем функции. Мне все еще нравится больше всего, даже лучше, как resolve ().
И мы вернулись к моему предложению, только с другим именем функции.
Вроде, как бы, что-то вроде.
Я понимаю, что afaik нет необходимости передавать URL / путь к файлу, содержащему вызов функции resolve()
, так как это местоположение должно быть _известно_ функции.
this
внутри функции относится к экземпляру FunctionCaller
, который имеет свойство currentFileInfo
.
Это свойство инициализируется информацией о файле узла Call
AST, соответствующего вызову функции.
Т.е.
Если я правильно читаю код, информация о файле соответствует информации о том месте, где был объявлен вызов функции, а не о файле, в котором оценивается вызов функции.
Это означает, что можно использовать эту информацию о файле для «нетерпеливого» преобразователя URL. Он будет действовать так, как ожидалось, даже если вызов функции будет помещен в миксин, который импортируется и оценивается в контексте другого файла. А именно: с разрешением, закрепленным за файлом, в котором определен миксин.
Однако, подумав об этом еще раз, зачем нам вообще нужен текущий путь к файлу, отображаемый как переменная? Разве это нельзя вплести в саму концептуальную функцию resolve ()?
Если мы уверены, что никому не нужен текущий файл или общая функция преобразователя ... возможно ... дело в явной локальной переменной, которая дает понять, что это не универсальная функция, и что функция не будет оцениваться как любая другая функция. Это моя настоящая проблема, это семантика. Независимо от того, как вы его называете, если у вас нет специального «маркера» для «текущего файла», тогда это не похоже на любую другую функцию, которая разрешает то же самое на основе входных данных. Другими словами, это функция, которая разрешается в соответствии с невидимыми входными данными, и это меня беспокоит. Однако, если функция является чем-то предельно явным, например current-file-resolve()
, возможно, это достаточно ясно. В противном случае вы просто запутаете людей, почему вызов миксина не разрешил specialfunction()
соответствии с файлом, в котором он был вызван, а не файлом, в котором был определен миксин.
Итак, нет, локальная переменная технически не нужна _, но значение / вывод / поведение должны быть ясны из семантики.
Хм...
ОК. Тогда как насчет функции resolve-url(url, [base])
- с необязательной функцией base
; по умолчанию используется каталог файла, в котором вызов функции записан / объявлен / определен. Затем есть функция declared-dir()
которая просто извлекает this.fileInfo
и захватывает путь, если авторы захотят вытащить путь явно; хотите взять путь из другого файла; или необходимо использовать это как часть какой-либо другой функции, не связанной с разрешением URL.
Т.е. вызов полной формы (без неявной базы) будет выглядеть примерно так:
resolve-url("../foo", declared-dir())
... и будет эквивалентно простому выполнению
resolve-url("../foo")
... что является нетерпеливым эквивалентом ленивого
url("../foo")
Таким образом, не нужно вводить «автоматически» вводимые переменные. Думаю, это можно было бы реализовать просто как набор функций плагина. И единственная основная механика, которая нам нужна, - это способ пометить URL-адреса как «уже разрешенные», чтобы можно было заблокировать выполнение логики преобразователя по умолчанию для URL-адресов, исходящих из функции resolve-url
.
Семантика должна быть разъяснена в документации курса. И эта документация может явно сравнивать url
с resolve-url
чтобы проиллюстрировать нетерпеливую и ленивую оценку / разрешение.
На всякий случай идея «введенных переменных» все равно не сработает (без дополнительных хаков), потому что импортированные файлы имеют ту же область видимости.
<strong i="7">@__dir</strong>: "whatever";
// *everywhere* it's the only <strong i="8">@__dir</strong> value = the path of "c"
<strong i="9">@import</strong> "a";
<strong i="10">@import</strong> "b";
<strong i="11">@import</strong> "c";
Говоря о реализации на основе функций, я думаю (но не могу быть уверен), что все еще можно получить путь к файлу, в котором функция вызывается, где-нибудь в его this.context.?
или this.context.frames[?]
или так.
эмммм, значит, у нас нет лучшего способа решить эту проблему?
@heynext
эмммм, значит, у нас нет лучшего способа решить эту проблему?
Боюсь, из-за ленивых вычислений эту проблему очень трудно решить.
@ семь фаз-макс
Говоря о реализации на основе функций, я думаю (но не уверен), что все еще можно получить путь к файлу, в котором функция вызывается, где-нибудь в егоthis.context.?
илиthis.context.frames[?]
или так.
Да, вы должны найти узел Call
в его иерархии.
Самый полезный комментарий
Хм...
ОК. Тогда как насчет функции
resolve-url(url, [base])
- с необязательной функциейbase
; по умолчанию используется каталог файла, в котором вызов функции записан / объявлен / определен. Затем есть функцияdeclared-dir()
которая просто извлекаетthis.fileInfo
и захватывает путь, если авторы захотят вытащить путь явно; хотите взять путь из другого файла; или необходимо использовать это как часть какой-либо другой функции, не связанной с разрешением URL.Т.е. вызов полной формы (без неявной базы) будет выглядеть примерно так:
... и будет эквивалентно простому выполнению
... что является нетерпеливым эквивалентом ленивого
Таким образом, не нужно вводить «автоматически» вводимые переменные. Думаю, это можно было бы реализовать просто как набор функций плагина. И единственная основная механика, которая нам нужна, - это способ пометить URL-адреса как «уже разрешенные», чтобы можно было заблокировать выполнение логики преобразователя по умолчанию для URL-адресов, исходящих из функции
resolve-url
.Семантика должна быть разъяснена в документации курса. И эта документация может явно сравнивать
url
сresolve-url
чтобы проиллюстрировать нетерпеливую и ленивую оценку / разрешение.