【问题标题】:Javascript in LESS appears hobbled: workaround?LESS 中的 Javascript 似乎步履蹒跚:解决方法?
【发布时间】:2016-12-26 08:36:05
【问题描述】:

我发现 LESS 有一个笨拙的 JavaScript 评估器,至少我使用它的方式是这样,即在将 *.less 文件上传到 Web 服务器之前在客户端上将它们编译成 *.css。

我知道编译可能更经常在服务器端完成,但为了性能和简单性,我们只希望服务器上的 CSS 文件。我正在 Fedora Linux 上编译 LESS 文件,并将 lessc ruby​​ gem 安装到节点包管理器中,如 these instructions

编译器运行良好,但据我所知,JavaScript 表达式评估非常有限。我相信这也适用于基于 this posting 的服务器端 JavaScript 表达式评估,这表明 JavaScript 引擎如何插入 LESS 环境的不确定性。

我只能使用简单的逗号分隔表达式,如下所示:

@bar: `
"ignored-string-expression"
,
5
`;
div.test-thing { content: ~"@{bar}"; }

编译成:

div.test-thing {
  content: 5;
}

当我尝试定义一个函数时,编译器会出错(表达式中的分号是否被反斜杠转义):

[719] anjaneya% cat testfunc.less
@bar: `function foo() {return 5}; foo()`;
div.test-thing { content: ~"@{bar}"; }

[720] anjaneya% lessc testfunc.less
SyntaxError: JavaScript evaluation error: `function foo() {return 5}; foo()` ...

似乎也没有任何循环方式,即使您尝试像上面的“忽略字符串表达式”一样欺骗它来评估循环,例如:

@foo: `x = 0,
for (var n = 0; n <= 10; n++) { x++; },
x
`;
div.test-thing { content: ~"@{bar}"; }

上面写着:

ParseError: Syntax Error on line 1 ...

何必呢? 为了能够编译这个 LESS:

@svgSource: '<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"><linearGradient id="g" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="@{start}" /><stop offset="1" stop-color="@{end}" /></linearGradient><rect x="0" y="0" width="100%" height="100%" fill="url(#g)" /></svg>';

进入这个 CSS:

background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZyIgeDE9IjAiIHkxPSIwIiB4Mj0iMCIgeTI9IjEiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzU3OWRkYiIgLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMwMDAwMjIiIC8+PC9saW5lYXJHcmFkaWVudD48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2cpIiAvPjwvc3ZnPg==);

使用program like this,算法是否在 JavaScript、PHP、Perl、UNIX shell 或其他任何方式中实现。这种处理可以在没有函数定义但没有循环的情况下完成,没有函数你甚至不能有递归。

鉴于函数和循环都是复合语句,可能不会被评估为表达式(它不是 LISP),这可能是失败的基础......它并不是真正的完整 JavaScript 解释器。所以我希望真正了解 LESS 编译器的人会:

  • 澄清上面的限制,这样我就可以便携地使用 JavaScript 和 LESS 来完成这项任务
  • 说明如何解决此问题(例如,使用“shell 转义”或任何可以迭代处理字符串的评估环境)和/或
  • 说一下如何用这种文本处理能力来扩展 LESS 编译器,就像“真正的”JavaScript 引擎一样。

【问题讨论】:

  • 我不知道如何修复 LESS 编译器,但是生成 SVG 背景的想法是天才!
  • 你很友善@Duopixel - 准备好圆点按钮和糖果条纹菜单。如果 LESS 支持失败,我将不得不添加一个第二阶段编译器,这是一个从站点构建 Makefile 运行的脚本,用于将来自 LESS mixin(如 pseudo-gradient: #COLOR1 #COLOR2)的假样式转换为相应的 base64 编码的 SVG 背景属性。任何需要字符串处理的 CSS 功能太复杂而无法用 LESS 处理,都可以在第二阶段编译器中处理。
  • 光荣发现:Node.js中LESS包的JavaScript引擎支持escape()函数。因此,LESS 代码看起来像:background: ~`"url(data:image/svg+xml," + escape(@{svgSource}) + ")"`;。这意味着具有可变特征的 SVG 图像可以被编码为具有 LESS 的数据 URI;除非您确实需要 base64 编码或其他更复杂的字符串处理,否则无需其他预处理器。
  • 不错!但未编码的svg 仅受 Webkit 支持。请问后台:~"url(data:image/svg+xml;base64," + new Buffer(@{svgSource}).toString('base64') + ")";工作吗?
  • 我仔细检查了 IE9 的限制,因为我的转义或 URI 编码(不是 base64 编码)SVG 背景在 IE9 中完美运行,只有我第一次更改。根据Data URI scheme,数据 URI 的唯一 IE9 限制是字符串大小。我认为您所指的区别是the other browsers support literal SVG。无论如何,轮到我对 Buffer.toString 的完美运行感到惊讶了!

标签: javascript css node.js svg less


【解决方案1】:

data-uri() 函数现在内置在 LESS 中:

http://lesscss.org/functions/#misc-functions-data-uri

会有帮助吗?

【讨论】:

    【解决方案2】:

    我认为您正在寻找的是 BUNCH 的混合体,其中包含在 LESS 中使用 javascript 的一些令人沮丧的小事。

    1. 所有 javascript 都必须在一行上。 (我......甚至不......随便。)
    2. 所有 javascript 都必须返回某些内容,否则您会收到完全无用的错误“无法读取未定义的属性‘值’”
    3. 所有 javascript 必须是一个语句。这来自最初的用例,他们认为你会做类似@foo 的事情:~'something.javascript.is.good.at({@bar});'

    数字 1 是格式化,2 只是意味着你需要返回一些东西,即使你不使用它,但数字 3 让很多人措手不及。要绕过它,只需让你“一件事”成为一个自动执行的匿名函数。

    例如:

    (function(){
        do.some.cool.stuff(); 
        other.cool.things();
        return('Fry');
    })();
    

    因此,LESS 解析器看到了这一点(确保所有内容都在一行中,而不是我编写的方式!),将其捆绑到 javascript 领域作为单次执行,读取返回值,并在一天中调用它。

    如果你想看到它的实际效果,我最近写了 LESS mixin 来制作 RGBA 1x1 pixels for background fills 等使用所有这些疯狂的东西。

    希望有帮助!

    【讨论】:

      【解决方案3】:

      我知道这篇文章已经有几年的历史了,但是嵌入在 LESS 中的 javascript 非常方便,所以我想发布一些提示:

       //All javascript must 
       // a. be on the rhs of an assignment   e.g.  @x:` var x = @{val}+7`;
       // b. must evaluate to a value
       // c. cannot be terminated by a ';'
       //
       // To get around this, multiline code can be packed into an IIFE......
      
       @val:7;
      
       @loop:`(function(val){
         var sum=0;
         for(var i=0; i<val; i++){sum+=i;}
         return sum;
       } )(@{val})`;
      
       .test{
         content:@loop;  // content: 21;
       }
      
       // console.log writes directly to the beginning of the output file
       @x:`console.log('/*...... loop = @{loop}.......*/')`;  //   /*...... loop =    21.......*/
      
       // you can use the global variable.  Here we attach a library module to it.....
       @x:`global.myLib={}`;
      
       // Then add a method to the module..............
       @btoa:`myLib.btoa=function(str){
         var buffer = new Buffer((str).toString(), 'binary');
         return buffer.toString('base64');
       }`;
      
       // And invoke the method to encode some text............................
       @sometext:'LESS is more (more or less)';
      
       .test2{
          content:`myLib.btoa(@{sometext})`;// content: "TEVTUyBpcyBtb3JlIChtb3JlIG9yIGxlc3Mp";
       }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-06-05
        • 2021-08-14
        • 2015-10-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-31
        • 2021-05-08
        相关资源
        最近更新 更多