Symfony Assetic如何通过Node-Sass实现Sass过滤器?

7

我在使用node-sass替代ruby的sass过滤器时遇到了问题。以下是我在config.yml文件中的配置:

assetic:
    debug:          "%kernel.debug%"

    use_controller: false
    bundles:        [ ]

    write-to:       "%kernel.root_dir%/../web/assets"
    read_from:      "%kernel.root_dir%/../web/assets"

    node:        "%%PROGRAMFILES%%\nodejs\\node.exe"
    node_paths: ["%%USERPROFILE%%\\AppData\\Roaming\\npm\\node_modules"]
    sass:        "%%USERPROFILE%%\\AppData\\Roaming\\npm\\node-sass"
    ruby: null

    filters:
        cssrewrite: ~
        scss:
            output-style: compressed
            apply_to: "\.(scss|sass|css)%"

尽管这会触发正确的node-sass命令,但我不确定配置是否正确。如果我删除ruby:null,它将尝试运行完全错误的C:\ Program Files ... \ path \ to \ ruby.exe%%USERPROFILE%%\\ AppData \\ Roaming \\ npm \\ node-sass 。但是,使用ruby:null也无法解决问题,因为它设置了错误的参数(即--load-path而不是--include-path),这也会混淆事情。
有人知道如何使用node而不是ruby来设置sass过滤器吗?
1个回答

6
我很乐意为所有遇到同样问题的人分享我的解决方案。看起来BaseSassFilter只适用于ruby版本。因此,我决定创建自己的过滤器。以下是我的类:
<?php

namespace App\YourBundle\Assetic\Filter;

use Assetic\Asset\AssetInterface;
use Assetic\Exception\FilterException;
use Assetic\Filter\Sass\BaseSassFilter;
use Assetic\Filter\Sass\SassFilter;

/**
 * This class is based on Assetic\Filter\Sass\SassFilter and is slightly modified to work with node-sass instead of Ruby.
 */

class NodeSassFilter extends BaseSassFilter
{

    const STYLE_NESTED     = 'nested';
    const STYLE_EXPANDED   = 'expanded';
    const STYLE_COMPACT    = 'compact';
    const STYLE_COMPRESSED = 'compressed';

    private $sassPath;
    private $scss;
    private $style;
    private $quiet;
    private $cacheLocation;

    public function __construct($sassPath = '/usr/bin/node-sass')
    {
        $this->sassPath = $sassPath;
        $this->cacheLocation = realpath(sys_get_temp_dir());
    }

    public function setScss($scss)
    {
        $this->scss = $scss;
    }

    public function setStyle($style)
    {
        $this->style = $style;
    }

    public function setQuiet($quiet)
    {
        $this->quiet = $quiet;
    }

    public function filterLoad(AssetInterface $asset)
    {
        $sassProcessArgs = array($this->sassPath);

        $pb = $this->createProcessBuilder($sassProcessArgs);

        if ($dir = $asset->getSourceDirectory()) {
            $pb->add('--include-path')->add($dir);
        }

        if ($this->style) {
            $pb->add('--output-style')->add($this->style);
        }

        if ($this->quiet) {
            $pb->add('--quiet');
        }

        // input
        $pb->add($input = tempnam(sys_get_temp_dir(), 'assetic_sass'));
        file_put_contents($input, $asset->getContent());

        $proc = $pb->getProcess();
        $code = $proc->run();
        unlink($input);

        if (0 !== $code) {
            throw FilterException::fromProcess($proc)->setInput($asset->getContent());
        }

        $asset->setContent($proc->getOutput());
    }

    public function filterDump(AssetInterface $asset)
    {
    }
}

然后,在你的config.yml文件中,添加以下内容:
assetic:
    filters:
        nodesass:
            bin: "%sass.bin%"
            resource: '%kernel.root_dir%/config/filters/nodesass.xml'
            style: compressed
            apply_to: "\.scss%"

app/config/filters/nodesass.xml 中,您需要添加以下 XML 代码:
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

    <parameters>
        <parameter key="assetic.filter.nodesass.class">App\YourBundle\Assetic\Filter\NodeSassFilter</parameter>
        <parameter key="assetic.filter.nodesass.bin">%assetic.sass.bin%</parameter>
        <parameter key="assetic.filter.nodesass.timeout">240</parameter>
        <parameter key="assetic.filter.nodesass.style">null</parameter>
        <parameter key="assetic.filter.nodesass.load_paths" type="collection" />
    </parameters>

    <services>
        <service id="assetic.filter.nodesass" class="%assetic.filter.nodesass.class%">
            <tag name="assetic.filter" alias="nodesass" />
            <argument>%assetic.filter.nodesass.bin%</argument>
            <call method="setTimeout"><argument>%assetic.filter.nodesass.timeout%</argument></call>
            <call method="setStyle"><argument>%assetic.filter.nodesass.style%</argument></call>
            <call method="setLoadPaths"><argument>%assetic.filter.nodesass.load_paths%</argument></call>
        </service>
    </services>

</container>

现在这样做应该可以让事情运转起来。


干得好。这应该放在Assetic存储库中,我也主要通过Node而不是Ruby管理资产。 - gremo
我会检查最新版本中是否已经修复了这个问题,如果是的话,我会在有时间的时候提交PR。 :) - tftd
好的,无论如何感谢 - 我花了几个小时来搞清楚load-path(ruby sass)与load-imports(node-sass)之间的区别...最终才意识到sass过滤器应该与ruby一起使用 :) - gremo
1
我创建了一个名为node-sass filter的github.com/kriswallsmith/assetic/pull/767,它的工作方式与你的相似。看起来它运行良好。 - gremo
希望 @gremo 的 PR 很快被合并! - mblaettermann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接