使用 Grunt 進行資源管理(Asset processing with Grunt)

Yii 2.0 已經有相當不錯的資源管理系統。他可以處理發布,映射(mapping),格式轉換,組合和壓縮。 還算不錯,但是如果我們正在和前端團隊合作,而我們對於資源管理的需求可能超過 Yii 可以處理的情況。

這時候,將資源管理交給 Grunt 是個好方法。因為 Grunt 有許多成熟的套件,可以滿足我們在客戶端開發上幾乎所有想到的需求。

1. 準備

我們從Yii基本應用開始,安裝方法在官方教學裡面

如果你還沒安裝 Node.js,必須先安裝。安裝好Node.js過後, 安裝TypeScript、Grunt 以及 相關套件如下:

npm install -g grunt-cli

npm install grunt --save-dev
npm install grunt-contrib-copy --save-dev
npm install grunt-contrib-less --save-dev
npm install grunt-contrib-uglify --save-dev
npm install grunt-contrib-watch --save-dev
npm install grunt-concat-sourcemap --save-dev
npm install typescript --save-dev
npm install grunt-typescript --save-dev

2. 作法

首先,關閉 Yii 內建的資源管理,我們修改config/web.php如下:

$params = require(__DIR__ . '/params.php');

$config = [
    // ...
    'components' => [
        // ...
        'assetManager' => [
            'bundles' => false,
        ],
    ],
];

// ...

return $config;

再來修改views/layouts/main.php

<?= Html::csrfMetaTags() ?>後面加上:

<?= Html::cssFile(YII_DEBUG ? '@web/css/all.css' : '@web/css/all.min.css?v=' . filemtime(Yii::getAlias('@webroot/css/all.min.css'))) ?>

這會在 debug 模式中加入http://example.com/css/all.css,並在正式模式中加入含修改時間(避免 cache)的http://example.com/css/all.min.css。這個檔案會被 Grunt 發布出去。

<?php $this->endBody() ?>前面,加入:

<?= Html::jsFile(YII_DEBUG ? '@web/js/lib.js' : '@web/js/lib.min.js?v=' . filemtime(Yii::getAlias('@webroot/js/lib.min.js'))) ?>
<?= Html::jsFile(YII_DEBUG ? '@web/js/all.js' : '@web/js/all.min.js?v=' . filemtime(Yii::getAlias('@webroot/js/all.min.js'))) ?>

與前面設定CSS的部份相同,這會加入被Grunt 發布的JS檔案連接。

現在在根目錄建立Gruntfile.js。該檔案設定 grunt 會怎麼處理你的資源:

module.exports = function (grunt) {
    grunt.initConfig({
        less: {
            dev: {
                options: {
                    compress: false,
                    sourceMap: true,
                    outputSourceFiles: true
                },
                files: {
                    "web/css/all.css": "assets/less/all.less"
                }
            },
            prod: {
                options: {
                    compress: true
                },
                files: {
                    "web/css/all.min.css": "assets/less/all.less"
                }
            }
        },
        typescript: {
            base: {
                src: ['assets/ts/*.ts'],
                dest: 'web/js/all.js',
                options: {
                    module: 'amd',
                    sourceMap: true,
                    target: 'es5'
                }
            }
        },
        concat_sourcemap: {
            options: {
                sourcesContent: true
            },
            all: {
                files: {
                    'web/js/all.js': grunt.file.readJSON('assets/js/all.json')
                }
            }
        },
        copy: {
            main: {
                files: [
                    {expand: true, flatten: true, src: ['vendor/bower/bootstrap/fonts/*'], dest: 'web/fonts/', filter: 'isFile'}
                ]
            }
        },
        uglify: {
            options: {
                mangle: false
            },
            lib: {
                files: {
                    'web/js/lib.min.js': 'web/js/lib.js'
                }
            },
            all: {
                files: {
                    'web/js/all.min.js': 'web/js/all.js'
                }
            }
        },
        watch: {
            typescript: {
                files: ['assets/ts/*.ts'],
                tasks: ['typescript', 'uglify:all'],
                options: {
                    livereload: true
                }
            },
            js: {
                files: ['assets/js/**/*.js', 'assets/js/all.json'],
                tasks: ['concat_sourcemap', 'uglify:lib'],
                options: {
                    livereload: true
                }
            },
            less: {
                files: ['assets/less/**/*.less'],
                tasks: ['less'],
                options: {
                    livereload: true
                }
            },
            fonts: {
                files: [
                    'vendor/bower/bootstrap/fonts/*'
                ],
                tasks: ['copy'],
                options: {
                    livereload: true
                }
            }
        }
    });

    // Plugin loading
    grunt.loadNpmTasks('grunt-typescript');
    grunt.loadNpmTasks('grunt-concat-sourcemap');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-copy');

    // Task definition
    grunt.registerTask('build', ['less', 'typescript', 'copy', 'concat_sourcemap', 'uglify']);
    grunt.registerTask('default', ['watch']);
};

現在 Grunt 會根據assets/jsassets/lessassets/ts來管理用戶端原始檔。

建立assets/js/all.json

[
    "vendor/bower/jquery/dist/jquery.js",
    "vendor/bower/bootstrap/dist/js/bootstrap.js",
    "vendor/yiisoft/yii2/assets/yii.js",
    "vendor/yiisoft/yii2/assets/yii.validation.js",
    "vendor/yiisoft/yii2/assets/yii.activeForm.js"
]

all.json列出要處理進lib.js的JavaScript 檔案。上面的程式碼做的事情與一般的 Yii 資源管理相同:加入 jQuery、bootstrap、和 Yii 本身的 JavaScript。

現在建立assets/less/all.less

@import "../../vendor/bower/bootstrap/less/bootstrap.less";
@import "site.less";

以及建立assets/less/site.lesssite.less的內容應該從web/css/site.css複製過來。

3. 使用方法

  • 運行grunt build來處理資源。
  • 開發期間,我們可以運行 grunt,程式會監控檔案的改變,並在需要的時候重建檔案。
  • 增加 JavaScript 檔案時,放在assets/js,並列入assets/js/all.json
  • 增加 LESS 檔案時,放在assets/less,並列入assets/less/all.less
  • 增加 TypeScript 檔案時,放在assets/ts。 .

results matching ""

    No results matching ""