问题
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).
回答1:
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!
来源:https://stackoverflow.com/questions/16033947/using-twig-as-an-assetic-filter-for-javascript-in-symfony2