Trong bài viết này mình sẽ hướng dẫn các bạn quản lý việc nhúng thư viện CSS và JS hiệu quả hơn trong Laravel. Các thư viện sẽ chỉ được nhúng và sử dụng trong những trang cần dùng thư viện này. Điều này giúp cải thiện tốc độ của ứng dụng.

Đầu tiên hãy tạo file config chứa tất cả đường dẫn và tên của các thư viện sử dụng trên ứng dụng của chúng ta. Mình sẽ tạo file  app/config/assets.php đối với laravel 4 hoặc config/assets.php đối với laravel 5.


<?php
/**
* Created by Sang Nguyen.
* Date: 22/06/2015
* Time: 3:10 PM
*/

return [
'offline' => false, //  false => Sử dụng src local, true => sử dụng src cdn
'base' => [ // Các thư viện chính được sử dụng cho từng module
    'frontend' => [ // Giao diện phía người dùng
        'javascript' => ['jquery'],
        'stylesheets' => ['style'],
    ],
    'backend' => [ // Giao diện trang quản trị
        'javascript' => [
            'jquery',
            'bootstrap',
         ],
         'stylesheets' => [
             'bootstrap',
         ],
    ],
],
'resources' => [
    'javascript' => [
        'jquery' => [
             'use_cdn' => false,
             'location' => 'top',
             'src' => [
                  'local' => [
                      '/resources/javascript/jquery.min.js',
                  ],
                  'cdn' => [
                      'https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js',
                  ],
             ],
        ],
        'bootstrap' => [
             'use_cdn' => true,
             'location' => 'top',
             'src' => [
                  'local' => [
                     '/resources/javascript/bootstrap.min.js',
                  ],
                  'cdn' => [
                     'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js',
                  ],
             ],
        ],

     // End JS
     ],
     /* -- STYLESHEET ASSETS -- */
     'stylesheets' => [
         'style' => [
              'use_cdn' => false,
              'location' => 'top',
              'src' => [
                   'local' => [
                      '/resources/stylesheets/style.css',
                   ],
                   'cdn' => [],
               ],
         ],
         'bootstrap' => [
             'use_cdn' => true,
             'location' => 'top',
             'src' => [
                 'local' => [
                     '/resources/stylesheets/bootstrap.min.css',
                 ],
                 'cdn' => [
                     'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css',
                 ],
             ],
         ],

       ],
    ],
];

Nếu cấu hình là use_cdn => true thì hệ thống sẽ dùng src cdn còn nếu là false thì sẽ dùng src local. ‘location’ là vị trí nhúng thư viện, thông thường các tập tin css sẽ được nhúng trên phần head và js được nhúng ở footer để tăng tốc độ load trang.

Tiếp theo chúng ta sẽ tạo mới 1 thư viện để quản lý việc thêm và xóa các file css và js.

Truy cập vào trong thư mục app và tạo cấu trúc file thế này:


-- Components

---- Assets

------ Facade

--------- AssetsFacade.php

------ Assets.php

------ AssetsServiceProvider.php

Sau khi tạo xong cấu trúc, chúng ta sẽ bắt đầu xây dựng cho file Assets.php. Trong lớp này sẽ có các phương thức add, remove javascript/stylesheets và get toàn bộ resources.


<?php
namespace App\Components\Assets;

use Config;
use App;

/**
* Created by Sang Nguyen.
* Date: 22/06/2015
* Time: 2:25 PM
*/

class Assets
{
    protected $javascript = [];
    protected $stylesheets = [];
    public function __construct()
    {
    }

    /**
    * @param array $assets
    */
    public function addJavascript($assets)
    {
        if (is_array($assets)) {
            $this->javascript = array_merge($this->javascript, $assets);
        } else {
            $this->javascript[] = $assets;
        }
    }

    /**
    * @param array $assets
    */
    public function addStylesheets($assets)
    {
        if (is_array($assets)) {
           $this->stylesheets = array_merge($this->stylesheets, $assets);
        } else {
           $this->stylesheets[] = $assets;
        }
    }

    /**
    * @param array $assets
    */
    public function removeStylesheets($assets)
    {
        if (is_array($assets)) {
            foreach ($assets as $rem) {
                unset($this->stylesheets[array_search($rem, $this->stylesheets)]);
            }
        } else {
            unset($this->stylesheets[array_search($assets, $this->stylesheets)]);
        }
    }

    /**
    * @param array $assets
    */
    public function removeJavascript($assets)
    {
        if (is_array($assets)) {
             foreach ($assets as $rem) {
                unset($this->javascript[array_search($rem, $this->javascript)]);
        }
        } else {
             unset($this->javascript[array_search($assets, $this->javascript)]);
        }
    }

    /**
    *
    */
    public function getJavascript($module)
    {
        $scripts = [];

        $this->javascript = array_merge(
           Config::get('assets.base.'. $module. '.javascript'),
           $this->javascript);
        if (!empty($this->javascript)) {
            // get the final scripts need for page
            foreach (array_unique($this->javascript) as $js) {
                 if (Config::has('assets.resources.javascript.' . $js)) {
                     if (Config::get('assets.resources.javascript.' . $js . '.use_cdn') 
                         && !Config::get('assets.offline')) {
                         $src = Config::get('assets.resources.javascript.' . $js 
                                . '.src.cdn');
                     } else {
                           $src = Config::get('assets.resources.javascript.' . $js
                           . '.src.local');
                     }
                     if (is_array($src)) {
                          foreach ($src as $s) {
                               $scripts[] = $s;
                          }
                     } else {
                          $scripts[] = $src;
                     }
                 }
             }
         }

        return $scripts;
    }

    /**
    *
    */
    public function getStylesheets($module)
    {
        $stylesheets = [];

        $this->stylesheets = array_merge(
             Config::get('assets.base.'. $module. '.stylesheets'),
             $this->stylesheets);
        if (!empty($this->stylesheets)) {
            // get the final scripts need for page
            foreach (array_unique($this->stylesheets) as $style) {
                if (Config::has('assets.resources.stylesheets.' . $style)) {
                    if (Config::get('assets.resources.stylesheets.' . $style . '.use_cdn')
                        && !Config::get('assets.offline')) {
                         $src = Config::get('assets.resources.stylesheets.' . $style
                                 . '.src.cdn');
                    } else {
                         $src = Config::get('assets.resources.stylesheets.' . $style
                                . '.src.local');
                    }
                    if (is_array($src)) {
                        foreach ($src as $s) {
                           $stylesheets[] = $s;
                        }
                    } else {
                        $stylesheets[] = $src;
                    }
                 }
             }
         }

         return $stylesheets;
      }
   }

Tiếp theo, ta sẽ tạo facade cho lớp Assets. Hãy sửa tập tin Components/Assets/Facade/AssetsFacade.php thành như sau:


<?php
namespace App\Components\Assets\Facade;

/**
* Created by Sang Nguyen.
* Date: 06/22/2015
* Time: 3:31 PM
*/

use Illuminate\Support\Facades\Facade;

class AssetsFacade extends Facade
{

    protected static function getFacadeAccessor()
    {
        return 'assets';
    }
}

Tiếp theo, chúng ta sẽ tạo AssetsServiceProvider:


<?php
namespace App\Components\Assets;

/**
* Created by  Sang Nguyen
* Date: 06/22/2015
* Time: 3:43 PM
*/

use Illuminate\Support\ServiceProvider;

class AssetsServiceProvider extends ServiceProvider
{

    public function register()
    {
        $this->app->bind('assets', function () {
            return new Assets();
        });
     }
}

 

Tiếp theo hãy thêm vào provider của trong tập tin config/app.php


'App\Components\Assets\AssetsServiceProvider',

Tiếp theo khai báo Facade trong mục aliases của config/app.php


'Assets' => 'App\Components\Assets\Facade\AssetsFacade',

Vậy là xử lý cho việc tạo thư viện và cấu hình các tập tin đã xong. Vậy làm sao để sử dụng nó trong controller và view một cách tùy biến. Đầu tiên chúng ta sẽ tạo view composer để load các tập tin css, js theo từng module nhé.


<?php

View::composer('frontend.master', function ($view) {
    $view->with('scripts', Assets::getJavascript('frontend'));
    $view->with('stylesheets', Assets::getStylesheets('frontend'));
});

View::composer('backend.master', function ($view) {
    $view->with('scripts', Assets::getJavascript('backend'));
    $view->with('stylesheets', Assets::getStylesheets('backend'));
});

Chúng ta sẽ load tất cả các thư viện js, css chính trên các trang master của từng module. Giờ hãy tạo trong view của bạn 2 file frontend/master.blade.php và backend/master.blade.php nếu bạn chưa có.

Nội dung sẽ tương tự thế này.


<!DOCTYPE html>
<html lang="en">
<head>
<title>Master layout</title>

@foreach ($stylesheets as $stylesheet)
   {{ HTML::style($stylesheet) }}
@endforeach

</head>
<body>

   @yield('content')

   @foreach ($scripts as $script)
      {{ HTML::script($script) }}
   @endforeach

</body>
</html>

Lưu ý: trong laravel 5 bạn phải cài thêm thư viện laravelcollective/html và thêm vào provider ‘Collective\Html\HtmlServiceProvider’ và alias ‘HTML’ => ‘Collective\Html\HtmlFacade’, trong file app.php và sử dụng {!! HTML::script($script) !!}. 

 

Bạn có thể tạo 2 file master cho 2 module có cấu trúc giống nhau nhưng hệ thống sẽ dựa theo module bạn gọi mà load thư viện lên phù hợp. Hãy chạy ứng dụng lên và view resource xem nó load đúng chưa nhé.

Bạn vẫn chưa thấy được điểm mạnh của việc quản lý tập tin css và js như thế này đúng không, ngoài giảm sự rắc rối trong các view thì việc thêm hoặc xóa các tập tin không được sử dụng trong từng partial view sẽ dễ dàng hơn và có thể xử lý trong controller.

Giả sử trong PostController và action getIndex bạn muốn nhúng thêm thư viện jquery-ui, datatable chẳng hạn thì trong action này ta sẽ làm như sau.


<?php

namespace App\Controllers;

class PostController extends BaseController {

    public function getIndex()
    {
        Assets::addJavascript([
            'jquery-ui',
            'datatable'
        ]);
        Assets::addStylesheets(['datatable']);
        return View::make('post.index');
    }

}

 

Lưu ý là đường dẫn tập tin jquery ui và datatable phải được config trong config/assets.php rồi thì mới add vào view được nhé.

Tương tự như việc xóa bớt tập tin css, js dư thừa trong action nào đó, bạn có thể sử dụng hàm removeJavascript() và removeStylesheets() mà ta đã định nghĩa. Bạn hãy làm thử cho các trường hợp sẽ thấy chúng ta làm việc hiệu quả hơn rất nhiều so với việc thêm và xóa thủ công trong view như trước đây. Nếu vì lý do gì đó mà bạn thay đổi vị trí lưu các tập tin css, js hoặc chuyển qua dùng cdn thì bạn chỉ việc thay đổi trong file config/assets.php mà không cần phải sửa trong các view sử dụng nó.

Lâu rồi không viết lách gì cả nên diễn đạt của mình hơi lủng củng, chắc nhiều phần sẽ thấy khó hiểu, nếu có thắc mắc hay lỗi xảy ra thì bạn hãy để lại comment để mình giúp đỡ nhé.

Chúc các bạn thành công!

Mình là 1 developer mới vào nghề, chưa có nhiều kinh nghiệm với lập trình web nhưng luôn muốn chia sẻ những hiểu biết của mình với các lập trình viên khác.
  • Địa chỉ: Hồ Chí Minh