2014-01-14 87 views
2

我是Grunt的新手,我在遞歸模板方面遇到了一些問題。這裏有一個具體的,小例子:Grunt:遞歸模板如何工作?

var path = require('path'); 

module.exports = function(grunt) { 
    grunt.initConfig({ 
    // Stash path here so we can reference it from templates. 
    path: path, 
    argPrint: function(arg1, arg2) { return "arg1: " + arg1 + " arg2: " + arg2; }, 
    build: { 
     root_dir: __dirname, 
     build_dir: '<%= path.resolve(build.root_dir, "dev") %>', 
     vendor_dir: '<%= path.resolve(build.build_dir, "vendor") %>', 
     classes_dir: '<%= path.resolve(build.vendor_dir, "classes") %>', 
     test: '<%= argPrint(build.build_dir, "vendor") %>' 
    } 
    }); 

    grunt.registerTask('print_build_dir', 'Prints the build directory.', function() { 
    grunt.log.writeln(grunt.config("build.root_dir")); 
    grunt.log.writeln(grunt.config("build.build_dir")); 
    grunt.log.writeln(grunt.config("build.vendor_dir")); 
    grunt.log.writeln(grunt.config("build.classes_dir")); 
    grunt.log.writeln(grunt.config("build.test")); 
    }); 
}; 

波普說成Gruntfile.js,運行npm install grunt,然後運行grunt print_build_dir

如果你在/Users/jvilk/Code/grunt-test,我會期望,輸出將是:

$ grunt print_build_dir 
/Users/jvilk/Code/grunt-test 
/Users/jvilk/Code/grunt-test/dev 
/Users/jvilk/Code/grunt-test/dev/vendor 
/Users/jvilk/Code/grunt-test/dev/vendor/classes 
arg1: /Users/jvilk/Code/grunt-test/dev arg2: vendor 

相反,輸出是:

$ grunt print_build_dir 
/Users/jvilk/Code/grunt-test 
/Users/jvilk/Code/grunt-test/dev 
/Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test/dev/vendor 
/Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test/dev/vendor/classes 
arg1: /Users/jvilk/Code/grunt-test/dev arg2: vendor 

這是怎麼回事?從test配置屬性,顯然path.resolve應該收到vendor_dir屬性的正確參數 - 即它將解析爲path.resolve("/Users/jvilk/Code/grunt-test/dev", "vendor") - 但我完全困惑於爲什麼它預先將build.root_dir的值與一個額外的正斜槓財產。

任何幫助或指導將不勝感激我和我的努力Gruntfile。謝謝!

編輯:作爲一個先發制人的附錄,我意識到我不需要使用模板來實現這個特殊的例子 - 我可以直接使用path.resolve。但是,在我的非示例Gruntfile中,path.resolve中的一個目錄名稱是動態設置的屬性,需要使用模板。

EDIT2:由於安德魯指出,模板工程擴建對vendor_dir以下列方式:

'<%= path.resolve(build.build_dir, "vendor") %>' -> 
    path.resolve('<%= path.resolve(build.root_dir, "dev") %>', "vendor") -> 
    '/Users/jvilk/Code/grunt-test/<%= path.resolve(build.root_dir, "dev") %>/vendor' -> 
     '/Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test/vendor' 

test性質的工作,因爲它擴大了,像這樣:

'<%= argPrint(build.build_dir, "vendor") %>' -> 
    argPrint('<%= path.resolve(build.root_dir, "dev") %>', "vendor") -> 
    'arg1: <%= path.resolve(build.root_dir, "dev") %> arg2: vendor' -> 
     'arg1: /Users/jvilk/Code/grunt-test arg2: vendor' 

我不理解他們爲什麼做出這個設計決定,但是我可以通過將所有這些包含在一個重複處理字符串的函數中,直到所有<%=都消失爲止,輕鬆地模擬我想要的模板語義。

回答

2

首先讓我開始與一個工作樣本。

grunt.initConfig({ 
    path: path, 
    argPrint: function(arg1, arg2) { return "arg1: " + arg1 + " arg2: " + arg2; }, 
    resolvePath: function(from, to) { return path.resolve(grunt.config.process(from), to); }, 
    build: { 
     root_dir: __dirname, 
     build_dir: "<%= resolvePath(build.root_dir, 'dev')%>", 
     vendor_dir: "<%= resolvePath(build.build_dir, 'vendor') %>", 
     classes_dir: "<%= resolvePath(build.vendor_dir, 'classes') %>", 
     test: "<%= argPrint(build.build_dir, 'vendor') %>" 
    } 
    }); 

    grunt.registerTask('print_build_dir', 'Prints the build directory.', function() { 
    grunt.log.writeln(grunt.config.get("build.root_dir")); 
    grunt.log.writeln(grunt.config.get("build.build_dir")); 
    grunt.log.writeln(grunt.config.get("build.vendor_dir")); 
    grunt.log.writeln(grunt.config.get("build.classes_dir")); 
    grunt.log.writeln(grunt.config.get("build.test")); 
    }); 
}; 

此輸出你所期望的:

/用戶/ andrewtremblay /開發/咕嚕測試

/用戶/ andrewtremblay /開發/咕嚕,測試/開發

/Users/andrewtremblay/Development/grunt-test/dev/vendor

/Users/andrewtremblay/Development/grunt-test/dev/vendor/cl驢

ARG1:/用戶/ andrewtremblay /開發/咕嚕,測試/開發ARG2:供應商

我測試這個時候與我ResolvePath函數傳遞給from的值不被人注意處理。 (而不是使用的config.get('build.build_dir')輸出是使用config.getRaw('build.build_dir')結果)

我不知道這是否是一個錯誤或沒有,但我認爲答案在於path.resolve以及如何通過它處理的變量會導致不確定的行爲。

From the docs(我的重點):

path.resolve([from ...], to)

如果to是不是已經絕對from參數在右前置到 左的順序,直到絕對路徑中找到。 如果在使用全部 路徑之後仍然沒有找到絕對路徑,那麼也使用當前工作目錄 。生成的路徑被標準化,除非路徑被解析到根目錄 目錄,否則將刪除尾部 斜槓。

這(加上path.resolve沒有處理你的配置對象的事實)可以解釋爲什麼你的工作目錄不斷被預置。

+0

就是這樣。我向argPrint添加了arg1的調試打印,並注意到它正在使用原始模板進行調用。我的模板思維模式不正確;我認爲它立即替換了所有的配置變量,但是它會在一個層次上處理模板,並將其轉發,然後遞歸處理所有其他模板直至完成。 –

0

當Grunt從config中執行get時,它會在找到模板模式時處理這些值。

它看起來像它處理模板,直到它找到一個沒有模板模式的字符串。因此,在您的情況每一步的樣子:

__dirname => 
    '/Users/jvilk/Code/grunt-test' 

build.build_dir => 
    '<%= path.resolve(build.root_dir, "dev") %> => 
    __dirname + "dev" => 
     '/Users/jvilk/Code/grunt-test/dev' 

build.vendor_dir => 
    '<%= path.resolve(build.build_dir, "vendor") %>' => 
    '/Users/jvilk/Code/grunt-test/<%= path.resolve(build.root_dir, "dev") %>/vendor' => 
     '/Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test/dev/vendor' 

build.classes_dir => 
    '<%= path.resolve(build.vendor_dir, "classes") %>' => 
    '/Users/jvilk/Code/grunt-test/<%= path.resolve(build.build_dir, "vendor") %>'/classes' => 
     '/Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test/<%= path.resolve(build.root_dir, "dev") %>/vendor/classes' => 
     '/Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test//Users/jvilk/Code/grunt-test/dev/vendor/classes' 

我不知道是否有解決這個除了在運行時手動擴展您的configs一個好辦法:

grunt.config("build.build_dir", grunt.config("build.build_dir")) 
grunt.config("build.vendor_dir", grunt.config("build.vendor_dir")) 
grunt.config("build.classes_dir", grunt.config("build.classes_dir")) 
+0

這個模板擴展沒有意義......'vendor_dir'和'test'是相同的 - *除了*他們調用不同的函數! 膨脹這種形式將產生以下爲'test': '/用戶/ jvilk /代碼/咕嚕測試/ ARG1:/用戶/ jvilk /代碼/咕嚕-測試/開發ARG2:vendor' 此外,外部正斜槓從哪裏來? 'root_dir'是'/ Users/jvilk/Code/grunt-test',而不是'/ Users/jvilk/Code/grunt-test /'...是Grunt進行奇怪的基本名提取,因爲它看起來像一個文件路徑... ? 謝謝你的迴應,但。 –

+1

我沒有注意到argPrint中的差異。我認爲@安德魯的答案解釋了它。 – doowb