简体   繁体   中英

Using Twig as an Assetic filter for JavaScript in Symfony2

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

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.


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(){...}
    ...
}

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.

In comes Twig to the rescue!

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.

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 %}
}

And our extended version.

// 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 %}
}

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).

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.

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

Good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM