Skip to content

Proposed a new article about using pure PHP libraries with Assetic #5166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jun 27, 2015
Merged
152 changes: 152 additions & 0 deletions cookbook/frontend/assetic_php.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
.. index::
single: Front-end; Assetic, Bootstrap

Combining, Compiling and Minimizing Web Assets with PHP Libraries
=================================================================

The official Symfony Best Practices recommend to use Assetic to
:doc:`manage web assets </best_practices/web-assets>`, unless you are
comfortable with JavaScript-based frontend tools.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

front-end


Even if those JavaScript-based solutions are the most suitable ones from a
technical point of view, using pure PHP alternative libraries can be useful in
some scenarios:

* If you can't install or use ``npm`` and the other JavaScript solutions;
* If you prefer to limit the amount of different technologies used in your
applications;
* If you want to simplify application deployment.

In this article you'll learn how to combine and minimize CSS and JavaScript files
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this article, you'll learn [...]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I honestly don't think this way, but I am eager to learn, what is the reasoning for this comma?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's to allow this kind of crazy word order in the sentence. Without comma, you would do "You'll learn how to combine and minimize CSS and JS files in this article" (time and location are always located at the end of the sentence). This is perfectly fine when you're speaking to someone, but when reading, it's common to put the location in front of the sentence. When doing that, you must add a comma before you start the sentence: "In this article, you'll learn [...]"

(funny, in this comment I used the "prepended construction" (don't know if that's the official naming) 3 times)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you please show me which of these cases is http://grammar.ccc.commnet.edu/grammar/commas.htm ? I am trying to contest this appreciation constructively 👴

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's 3:

Use a comma to set off introductory elements, as in "Running toward third base, he suddenly realized how stupid he looked."

It is permissible to omit the comma after a brief introductory element if the omission does not result in confusion or hesitancy in reading. If there is ever any doubt, use the comma, as it is always correct. If you would like some additional guidelines on using a comma after introductory elements, click HERE.

So, yes. You are correct that the comma can be omitted, but it can introduce confusion. As the docs are read by many non-natives, it's good to avoid anything that could introduce confusion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well you agreed which is good. So it is not "it must" but it is optional. If we make this into a rule just to be always right is ok. I personally think this interlude is so short that flows immediately to the point, no need for refrain or pause. I also doubt this introduces any confusion. But 💚 🚥 light if you always want to be right. It is just i am concerned on the damage to the language over time with enforcing something that is optional indeed. But yeah let's go in agreement to put the comma 👴 The lesson I learned here is not always try to be right. 😊 because it could make it wrong.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the discussion. I'll put the comma then :)

and how to compile Sass SCSS files using PHP only libraries with Assetic.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm no front-end expert, but is Sass SCSS the state-of-the-art technology? What about alternatives like LESS?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some alternatives, but I believe Sass is used the most and has the biggest community behind it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, I would say "Sass files". There is no need to make this overcomplicated (and using uppercase words breaks up the read flow, reducing the reading experience a bit).


Installing the Third-Party Compression Libraries
------------------------------------------------

Assetic includes a lot of ready-to-use filters but it doesn't include their
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] filters, but it [...]

associated libraries. Therefore, before enabling the filters used in this article
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] in this article, you must [...]

you must install two libraries. Open a command console, browse to your project
directory and execute the following commands:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's very important to not make this article just a step-by-step solution for one problem (Sass and minifying), but make it ready to use for other libraries as well.

This mostly means that we should try to not say "Do this", but instead explain what "this" is and how we've come up with "this". In this case, it means explaining how one can find these package names. How does one know it has to install exactly these packages?


.. code-block:: bash

$ composer require leafo/scssphp
$ composer require patchwork/jsqueeze:"~1.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make it ~1.0.7 better? or something like lesser than 2.0.0

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we want to limit something to be "less than 2.0.0" I think that the ~1.0 constraint is more intuitive.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually is more correct, not intuitive, because it will include 1.2 etc. Though is very unlikely. So ignore please and proceed 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was about to suggest using the 2.0 version, but actually Assetic is compatible with both 1.x and 2.x only in the dev version. I haven't released this in a stable version yet.


It's very important to maintain the ``~1.0`` version constraint for the ``jsqueeze``
dependency because the most recent stable version is not compatible with Assetic.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be handled by Assetic, introducing a conflict rule in their composer.json.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dev version of Assetic is compatible with both 1.x and 2.x actually


Organizing Your Web Asset Files
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, @wouterj correct me that your (lowercased) is the correct spelling (it's a closed-class word).

-------------------------------

This example shows the very common scenario of using the Bootstrap framework, the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-1 for adding "very common". It's starting to look like Symfony is sponsered by Bootstrap :) (if that is actually what happend, I would prefer to have the logo on the site rather than using it constant in the docs).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've replaced very common by common.

jQuery library, the FontAwesome icon fonts and some regular CSS and JavaScript
application files (called ``main.css`` and ``main.js``). The recommended directory
structure for this set-up is the following:

.. code-block:: text

web/assets/
├── css
│   ├── main.css
│   └── code-highlight.css
├── js
│   ├── bootstrap.js
│   ├── jquery.js
│   └── main.js
└── scss
├── bootstrap
│   ├── _alerts.scss
│   ├── ...
│   ├── _variables.scss
│   ├── _wells.scss
│   └── mixins
│   ├── _alerts.scss
│   ├── ...
│   └── _vendor-prefixes.scss
├── bootstrap.scss
├── font-awesome
│   ├── _animated.scss
│   ├── ...
│   └── _variables.scss
└── font-awesome.scss
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reasoning behind storing the raw files (*.scss and not-minified JavaScript files) under web/assets?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

big -1 for that. It's also against the best practices btw. Imo, uncompiled files should live in app/Resources/public and only the compiled onces in web/.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, well maybe best practice document says so for newcomers. Also not following best practices does not mean wrong as it seems you are conveying with the -1. Mind that since we are opening the doors at different possibilities from where the assets come from we cannot limit them, be it bundles yes, be it other packages who knows where they are, puli, or other cases will depend on which php package is used to pull the assets no?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My -1 was for putting them in the public files (web/). My personal opinion is to put them in app/Resources/public.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit lost with your latest suggestion:

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Files that should be compiled using Assetic should be in /app/Resources/ right?


Combining and Minimizing CSS Files and Compiling SCSS Files
-----------------------------------------------------------

First, configure a new ``scssphp`` Assetic filter as follows:

.. code-block:: yaml

# app/config/config.yml
assetic:
filters:
scssphp:
formatter: "Leafo\\ScssPhp\\Formatter\\Compressed"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

escaping the \ isn't needed and as it reduces readability, we always try to avoid it in the docs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you use the double-quoted syntax, it is.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, you need the single quoted syntax, don't you? As double quotes can cause problems when \S, \F or \C are valid sequences? (there are a couple of uppercase sequence names)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wouterj it is fine here as the backslash is escaped. The parser will read \\ (as \) and then F, not \F

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use single quotes so that we don't need to escape backslashes.

# ...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have to show XML and PHP too:

<!-- app/config/config.xml -->
<?xml version="1.0" charset="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:assetic="http://symfony.com/schema/dic/assetic">

    <assetic:config>
        <filter name="scssphp" formatter="Leafo\ScssPhp\Formatter\Compressed" />
        <!-- ... -->
    </assetic:config>
</container>
// app/config/config.php
$container->loadFromExtension('assetic', array(
    'filters' => array(
         'scssphp' => array(
             'formatter' => 'Leafo\ScssPhp\Formatter\Compressed',
         ),
         // ...
    ),
));


The value of the ``formatter`` option is the fully qualified class name of the
formatter used by the filter to produce the compiled CSS file. Using the
compressed formatter allows to minimize the resulting file, no matter if the
original files are regular CSS files or SCSS files.

Then, update the code of your Twig template to add the ``{% stylesheets %}`` tag
defined by Assetic:

.. code-block:: html+jinja

<!DOCTYPE html>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably a good idea to add a filename comment to the top of the template.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated it to display {# app/Resources/views/base.html.twig #} Is that the common practice in the Symfony docs when referring to the base/layout template?

<html>
<head>
<!-- ... -->

{% stylesheets filter="scssphp" output="css/app.css"
"assets/scss/bootstrap.scss"
"assets/scss/font-awesome.scss"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a reference about managing FontAwesome using Bower here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's a good idea, because this article is about using PHP only libraries. But once the Bower article written by @wouterj is published, we can indeed add a link to it in the introduction of this article (where we say "JS is the best for this"). I think taht would make a lot of sense. Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for adding a note. My point is that it should be clear that managing (minimize, compile) web assets with PHP is possible, but checking in "assets/scss/font-awesome.scss" in the VCS is not needed if a package manager like Bower is used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 interesting point, yeah maybe a # this is required when done PHP exclusive compilation of assets

"assets/css/*.css"
%}
<link rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}

This simple configuration compiles the SCSS files into regular CSS files, combines
all of them, minimizes the contents and saves the output in the ``web/css/app.css``
file, which is the one that is served to your visitors.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huston, we've a big sentence again :)

What do you think about: "This simple configuration compiles, combines and minifies the SCSS files into a regular CSS file that's put in web/css/app.css."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your version is much better. Thanks!


Combining and Minimizing JavaScript Files
-----------------------------------------

First, configure a new ``jsqueeze`` Assetic filter as follows:

.. code-block:: yaml

# app/config/config.yml
assetic:
filters:
jsqueeze: ~
# ...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should show other formats:

<!-- app/config/config.xml -->
<?xml version="1.0" charset="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:assetic="http://symfony.com/schema/dic/assetic">

    <assetic:config>
        <filter name="jsqueeze" />
        <!-- ... -->
    </assetic:config>
</container>
// app/config/config.php
$container->loadFromExtension('assetic', array(
    'filters' => array(
         'jsqueeze' => null,
         // ...
    ),
));

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for providing these alternative formats.


Then, update the code of your Twig template to add the ``{% javascripts %}`` tag
defined by Assetic:

.. code-block:: html+jinja

<!-- ... -->

{% javascripts filter="?jsqueeze" output="js/app.js"
"assets/js/jquery.js"
"assets/js/bootstrap.js"
"assets/js/main.js"
%}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}

</body>
</html>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should show the PHP syntax too


This simple configuration combines all the JavaScript files, minimizes the contents
and saves the output in the ``web/js/app.js`` file, which is the one that is
served to your visitors.

The leading ``?`` character in the ``jsqueeze`` filter name indicates that it must
be applied only when the ``debug`` mode is disabled in the application, which
usually occurs in the production environment.
7 changes: 7 additions & 0 deletions cookbook/frontend/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Form
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be Front-End

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will be done by my PR and can be removed from this PR, to avoid merge conflicts

====

.. toctree::
:maxdepth: 2

assetic_php
1 change: 1 addition & 0 deletions cookbook/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The Cookbook
email/index
event_dispatcher/index
form/index
frontend/index
logging/index
profiler/index
request/index
Expand Down
5 changes: 5 additions & 0 deletions cookbook/map.rst.inc
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@
* (validation) :doc:`/cookbook/validation/custom_constraint`
* (doctrine) :doc:`/cookbook/doctrine/file_uploads`


* :doc:`/cookbook/frontend/index`

* :doc:`/cookbook/frontend/assetic_php`

* :doc:`/cookbook/logging/index`

* :doc:`/cookbook/logging/monolog`
Expand Down