在 Symfony2 中使用 Twig 作为 JavaScript 的资产过滤器

2022-01-22 00:00:00 javascript symfony twig assetic

有没有办法将 Twig 用作资产过滤器?

Is there a way to use Twig as an Assetic filter?

我想做的是让 Twig 将我的 JavaScript 文件解析为 Twig 模板,然后将它们传递给 Assetic,以便它们在生产中组合并缩小.

What I want to do is have Twig parse my JavaScript files as Twig templates, and then pass them to Assetic so that they get combined and minified in production.

你可能在想我为什么首先要这样做,所以让我跳到一个例子.

You might be scratching your head thinking why I would want to do this in the first place, so let me jump to an example.

我正在用 JavaScript 制作游戏引擎,我需要有多个类"的两个版本.一个版本供用户使用,另一个版本供编辑器使用.这些类之一的示例是单例 World.

I am making a game engine in JavaScript and I need to have two versions of several 'classes'. One version for the user and another for the editor. An example of one of these classes would be the singleton World.

此类的用户版本可能如下所示:

The user version of this class might look like this:

var World = function()
{
    // bunch of 'private' variables and functions inside closure
    var _initialised = false;
    var _worldData;
    ...

    // public functions
    this.init = function(){...}
    this.update = function(){...}
    ...
}

此类的编辑器版本可能如下所示:

The editor version of this class might look this:

var World = function()
{
    // bunch of 'private' variables and functions inside closure
    var _initialised = false;
    var _worldData;
    ...

    // bunch of new private variables and functions for editing
    var _editorserver;
    ...

    // public functions
    this.init = function(){...}
    this.update = function(){...}
    ...

    // public functions that edit the world
    this.addEntity = function(){...}
    this.removeEntity = function(){...}
    ...
}

使用经典的 OO 继承,我们可以将 World 定义为一个类,然后用另一个类 EditableWorld 扩展它.然而,使用 JavaScript 中的原型继承只会继承公共函数,如果您甚至尝试扩展现有实例,您将无法访问闭包内的变量和函数.

With classical OO inheritance we could define World as one class and then extend it with another class EditableWorld. However with Prototypal inheritance in JavaScript only the public functions would be inherited and if you even tried to extend the existing instance you would not be able to access the variables and functions inside the closure.

Twig 来救援了!

使用 Twig,我们可以将多个块添加到文件中的任何类,然后创建另一个文件,使用一些扩展名定义相同的类,然后包含 那个 文件.

With Twig we could add several blocks to any class in a file, and then create another file defining the same class with some extensions and then include that file.

让我们再次将我们的基础 World 类视为 Twig 模板.

So let's look at our base World class again as a Twig template.

// world.js.twig
var World = function()
{
    // bunch of 'private' variables and functions inside closure
    var _initialised = false;
    var _worldData;
    ...

    {% block extended_privates %}{% endblock %}

    // public functions
    this.init = function(){...}
    this.update = function(){...}
    ...

    {% block extended_publics %}{% endblock %}
}

还有我们的扩展版本.

// editableworld.js.twig
{% extends "EngineBundle::world.js.twig" %}
var World = function()
{
    // bunch of 'private' variables and functions inside closure
    var _initialised = false;
    var _worldData;
    ...

    {% block extended_privates %}
    // bunch of new private variables and functions for editing
    var _editorserver;
    ...
    {% endblock %}

    // public functions
    this.init = function(){...}
    this.update = function(){...}
    ...

    {% block extended_publics %}
    // public functions that edit the world
    this.addEntity = function(){...}
    this.removeEntity = function(){...}
    ...
    {% endblock %}
}

<小时>

现在问题来了:我如何让 Assetic 使用 Twig 作为过滤器,以便我可以执行以下操作:


Now here's the rub: how do you I get Assetic to use Twig as a filter so that I can do something like this:

// user version of twig template
// gameengine.html.twig

{% javascripts filter="js_twig_filter"
"@EngineBundle/Resources/public/js/world.js.twig"
%}
<script src="{{ asset_url }}" type="text/javascript"></script>
{% endjavascripts %}

// editor version of twig template
// gameeditor.html.twig

{% javascripts filter="js_twig_filter"
"@EngineBundle/Resources/public/js/editableworld.js.twig"
%}
<script src="{{ asset_url }}" type="text/javascript"></script>
{% endjavascripts %}

您可能想到的一个直接解决方案是完全放弃闭包,只将我的所有变量和函数公开,并在应该是私有的前面加上下划线.但是对我来说,这不是一个有效的解决方案,因为我不仅仅是在创建一个库.游戏引擎需要从最终用户关闭所有内部结构,以阻止所有想要篡改正在运行的引擎的确定用户(并且对于那些用户,我有服务器验证以确保来自受感染客户端的非法操作不要通过服务器发送给其他客户端).

One immediate solution that might come to your head is to forgo closures altogether and just make all my variables and functions public and just prefix the ones that should have been private with an underscore. However for me this isn't a valid solution as I'm not merely creating a library. The game engine needs to close off all of it's internals from the end user to stop all but determined users who would want to tamper with the running engine (and for those users I have server validation in place to make sure illegal actions from the compromised clients don't get sent to other clients via the server).

感谢您的支持,我希望有人可以帮助我(在我想到这个可能的解决方案之前,我已经把头撞在墙上几天了,现在正在尝试其他想法).

Thanks for sticking around and I hope someone can help me (I've been banging my head against the wall for a few days now trying alternative ideas before I thought of this possible solution).

推荐答案

您需要先渲染(在控制器中)所有 *.js.twig 文件并将它们保存为 *.js 文件(使用 file_put_contents() 函数在资源树的某处).然后将 *.js 文件加载到您的资产过滤器中.

You need to render (in the controller) all the *.js.twig files first and save them as *.js files (using file_put_contents() function somewhere in the Resources tree). Then load the *.js files into your assetic filters.

此外,您还有很多优雅地支持 JavaScript 中的 OOP 的库/语言/帮助程序(例如 CoffeeScript、Backbone.js、Underscore.js 等)

Besides, you have a lot of libraries/languages/helpers that support OOP in JavaScript elegantly (like CoffeeScript, Backbone.js, Underscore.js, etc.)

祝你好运!

相关文章