Less.js: Функция data-uri использует путь вызова data-uri, а не строку с путем к файлу в.

Созданный на 8 июл. 2015  ·  37Комментарии  ·  Источник: less/less.js

из 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 .

Я приветствую отзывы о том, является ли это критическим изменением (требующим серьезного обновления) или исправлением ошибки.

Самый полезный комментарий

Хм...

ОК. Тогда как насчет функции 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 чтобы проиллюстрировать нетерпеливую и ленивую оценку / разрешение.

Все 37 Комментарий

Я приветствую отзывы о том, является ли это критическим изменением (требующим серьезного обновления) или исправлением ошибки.

К вашему сведению: вы можете элегантно реализовать это без нарушения обратной совместимости очень простым способом.

В настоящее время функция 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/ . Если это не так, это ошибка, потому что миксины не должны работать так. Я не думаю, что это «критическое изменение», а исправление ошибки.

Тем не менее ... Я не думаю, что возникнет проблема с решением вроде:

  1. Попытка разрешить относительно вызывающего абонента.
  2. Попытка разрешиться относительно миксина.

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, соответствующего вызову функции.
Т.е.

https://github.com/less/less.js/blob/4e903e8254cc20fec80fccd35794fb797949e653/lib/less/tree/call.js#L47

Если я правильно читаю код, информация о файле соответствует информации о том месте, где был объявлен вызов функции, а не о файле, в котором оценивается вызов функции.

Это означает, что можно использовать эту информацию о файле для «нетерпеливого» преобразователя 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 в его иерархии.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги