Nette a Grunt

Jak snadno minifikovat js a css soubory pomoci Gruntu v Nette projektu

Proc toto spojeni?

Protoze kazdy chce mit jen jeden javascript soubor a jeden css soubor. V dobe mobilniho internetu kde se kazdy request pocita nechceme hlavicky nasich stranek co vypadaji nejak takhle (v lepsim pripade)

Chceme jen jeden minifikovany soubor pro javascript a jeden minifikovany soubor pro css. A jelikoz na tyto ukoly se mi velmi dobre osvedcil Grunt a jeho kanonada pluginu, predstavim vam jednoduche reseni jak si tento proces automatizovat.

Co budem potrebovat

Cistou “instalaci” Nette sandboxu https://github.com/nette/sandbox a fungujici Grunt http://gruntjs.com.

Grunt je JavaScript task runner, defakto neco jako Make ci Ant ale napsane v JavaScriptu. Existuje pro nej spousta zajimavych pluginu/tasku ktere jsou uzitecne ve frontendovem vyvoji (ale nejen i v nem) viz gruntjs.com/plugins.

Jak zprovoznit grunt-cli:

Grunt pohani node.js tudiz je treba mit nainstalovan node.js s package managerem npm (nodejs.org)

nasledne do globalniho prostoru nainstalujeme grunt-cli npm install -g grunt-cli

pokud vse dobre dopadlo melo by se po zadani grunt –version objevit neco podobneho

V adresari ProjectGrunt si zprovoznime fungujici Nette Sandbox. Idealne pomoci composer prikazu

composer create-project nette/sandbox ProjectGrunt

nasledne si zkontrolujeme obsah slozky

a po nastaveni webserveru a nastaveni log a temp (chmod -R a+rw temp log) bychom meli videt funguji stranku. ( nefunguje? Postupujte podle Quick startu)

Jdeme na to

do hlavniho adresare pridame soubor package.json ve kterem specifikujeme npm zavislosti pro nas grunt skript

{
  "name": "ProjectGrunt",
  "version": "1.0.0",
  "devDependencies": {
    "grunt": "~0.4.4",
    "grunt-usemin": "~2.1.0",
    "grunt-contrib-concat": "~0.3.0",
    "grunt-contrib-uglify": "~0.4.0",
    "grunt-contrib-cssmin": "~0.9.0",
    "grunt-nette-basepath": "~0.2.0"
  }
}

grunt – rikame ze chceme pouzivat Grunt ve verzi 0.4.4

grunt-usemin – plugin pro prochazeni html souboru a dohledavani js a css souboru k dalsimu zpracovani

grunt-contrib-concat – plugin pro spojovani vice souboru do jednoho

grunt-contrib-uglify – plugin pro minifikaci javascript souboru

grunt-contrib-cssmin – plugin pro minifikaci css souboru

grunt-nette-basepath – plugin pro odstraneni latte promene {$basePath}

Instalaci provedeme prikazem npm install

A nasledne do hlavniho adresare pridame jeste Gruntfile.coffee (muzete pouzit i Gruntfile.js ale z vlastni zkusenosti doporucuji Coffee, prece jen je tam o poznani mene zavorek, stredniku a vseho mozneho :-) )

module.exports = (grunt) ->
  grunt.initConfig
    useminPrepare:
      html: ['app/templates/@layout.latte']
      options:
        dest: '.'

    netteBasePath:
      basePath: 'www'
      options:
        removeFromPath: ['app/templates/']

  # These plugins provide necessary tasks.
  grunt.loadNpmTasks 'grunt-contrib-concat'
  grunt.loadNpmTasks 'grunt-contrib-uglify'
  grunt.loadNpmTasks 'grunt-contrib-cssmin'
  grunt.loadNpmTasks 'grunt-usemin'
  grunt.loadNpmTasks 'grunt-nette-basepath'

  # Default task.
  grunt.registerTask 'default', [
    'useminPrepare'
    'netteBasePath'
    'concat'
    'uglify'
    'cssmin'
  ]

Zde je definicie jake tasky se maji nacist. Jak se chova hlavni task (to je ten co se spusti prikazem grunt) a konfigurace pro task useminPrepare a netteBasePath. Vice informaci jak funguje usemin plugin najdete na https://github.com/…grunt-usemin

V nasem pripade si jeste overime konfiguraci pro netteBasePath kde rikame ze basePath se nachazi v adresari www a z duvodu jak funguje useminPrepare potrebujeme odsranit jeste zanoreni app/templates ktere k souborum plugin pridava.

pro platformu windows je mozne ze bude nutna drobna uprava konfigurace na

removeFromPath: ['app\\templates\\']

(o problemu vim a casem ho snad vyresim)

Spustime minifikaci

Ted kdyz mame vse tak uz by nam melo jit spustit grunt , ale v tuto chvili skoncime s chybou jelikoz usemin plugin nenasel zadne bloky k minifikaci.

Tak si tam ty bloky pridame :) V souboru @layout.latte najdeme a obalime klasicke nacitani css a js

<!-- build:css {$basePath}/css/screen.min.css -->
<link rel="stylesheet" media="screen,projection,tv" href="{$basePath}/css/screen.css">
<!-- endbuild -->
<!-- build:css {$basePath}/css/print.min.css -->
<link rel="stylesheet" media="print" href="{$basePath}/css/print.css">
<!-- endbuild -->

a

<!-- build:js {$basePath}/js/app.min.js -->
<script src="{$basePath}/js/jquery.js"></script>
<script src="{$basePath}/js/netteForms.js"></script>
<script src="{$basePath}/js/main.js"></script>
<!-- endbuild -->

a ted by spustenim grunt mel najit nase definovane soubory v blocich a postarat se o ne.

Super, v adresari se nam objevil minifikovane verze, co ted s nima?

Prepinani verzi v latte

Pro vyvoj budeme chtit neminifikovane vicesouborove reseni a pro nasazeni na produkci budeme chtit zobrazovat minifikovanou verzi.

Jak toho docilit. Ja si definoval v neon.configu promenou ktera mi rika jakou verzi chci pouzit pripadne mam i jeji verzove pojmenovani (kvuli cache)

config.neon

#
# SECURITY WARNING: it is CRITICAL that this file & directory are NOT accessible directly via a web browser!
#
# If you don't protect this directory from direct web access, anybody will be able to see your passwords.
# https://nette.org/security-warning
#
parameters:
    site: # <---
        develMode: false # <---
        version: blackhawk # <---

php:
    date.timezone: Europe/Prague
    # zlib.output_compression: yes


nette:
    application:
        errorPresenter: Error
        mapping:
            *: App\*Module\Presenters\*Presenter

    session:
        expiration: 14 days


services:
    - App\Model\UserManager
    - App\RouterFactory
    router: @App\RouterFactory::createRouter

Drobna uprava v basepresenteru aby se o techto parametrech dozvedela sablona, asi to neni nejcistsi reseni ale pro tento priklad nam to staci a nebudeme si to komplikovat.

BasePresenter.php

/**
 * Base presenter for all application presenters.
 */
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
    public function beforeRender()
    {
        parent::beforeRender();

        $this->template->production = !$this->context->parameters['site']['develMode'];
        $this->template->version = $this->context->parameters['site']['version'];
    }
}

a nasledna uprava v sablone @layout.latte

{if $production}
    <link rel="stylesheet" media="print" href="{$basePath}/css/screen.min.css?{$version}">
    <link rel="stylesheet" media="print" href="{$basePath}/css/print.min.css?{$version}">
{else}
    <!-- build:css {$basePath}/css/screen.min.css -->
    <link rel="stylesheet" media="screen,projection,tv" href="{$basePath}/css/screen.css">
    <!-- endbuild -->
    <!-- build:css {$basePath}/css/print.min.css -->
    <link rel="stylesheet" media="print" href="{$basePath}/css/print.css">
    <!-- endbuild -->
{/if}

a

{if $production}
    <script src="{$basePath}/js/app.min.js?{$version}"></script>
{else}
    <!-- build:js {$basePath}/js/app.min.js -->
    <script src="{$basePath}/js/jquery.js"></script>
    <script src="{$basePath}/js/netteForms.js"></script>
    <script src="{$basePath}/js/main.js"></script>
    <!-- endbuild -->
{/if}

a ted uz by nase aplikace mela pouzivat minifikovane verze.

Cely projekt najdete na https://github.com/…/Nette-Grunt