Dmi*_*ich 208 javascript build-automation build gruntjs
我正在尝试使用Grunt作为我的webapp的构建工具.
我想要至少有两个设置:
I.开发设置 - 从单独的文件加载脚本,没有连接,
所以我的index.html看起来像:
<!DOCTYPE html>
<html>
<head>
<script src="js/module1.js" />
<script src="js/module2.js" />
<script src="js/module3.js" />
...
</head>
<body></body>
</html>
Run Code Online (Sandbox Code Playgroud)
II.生产设置 - 在一个文件中加载我的脚本缩小和连接,
与index.html相关:
<!DOCTYPE html>
<html>
<head>
<script src="js/MyApp-all.min.js" />
</head>
<body></body>
</html>
Run Code Online (Sandbox Code Playgroud)
现在的问题是,如何才能让咕噜使这些的index.html的取决于配置,当我运行grunt dev
或grunt prod
?
或者也许我正在挖掘错误的方向并且总是生成更容易MyApp-all.min.js
但是将所有脚本(连接)或从异步文件中异步加载这些脚本的加载器脚本放入其中?
伙计们,你是怎么做到的?
mhu*_*lse 161
我最近发现了这些Grunt v0.4.0
兼容任务:
以下是我的片段Gruntfile.js
.
ENV设置:
env : {
options : {
/* Shared Options Hash */
//globalOption : 'foo'
},
dev: {
NODE_ENV : 'DEVELOPMENT'
},
prod : {
NODE_ENV : 'PRODUCTION'
}
},
Run Code Online (Sandbox Code Playgroud)
预处理:
preprocess : {
dev : {
src : './src/tmpl/index.html',
dest : './dev/index.html'
},
prod : {
src : './src/tmpl/index.html',
dest : '../<%= pkg.version %>/<%= now %>/<%= ver %>/index.html',
options : {
context : {
name : '<%= pkg.name %>',
version : '<%= pkg.version %>',
now : '<%= now %>',
ver : '<%= ver %>'
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
任务:
grunt.registerTask('default', ['jshint']);
grunt.registerTask('dev', ['jshint', 'env:dev', 'clean:dev', 'preprocess:dev']);
grunt.registerTask('prod', ['jshint', 'env:prod', 'clean:prod', 'uglify:prod', 'cssmin:prod', 'copy:prod', 'preprocess:prod']);
Run Code Online (Sandbox Code Playgroud)
并在/src/tmpl/index.html
模板文件中(例如):
<!-- @if NODE_ENV == 'DEVELOPMENT' -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.js"></script>
<script src="../src/js/foo1.js"></script>
<script src="../src/js/foo2.js"></script>
<script src="../src/js/jquery.blah.js"></script>
<script src="../src/js/jquery.billy.js"></script>
<script src="../src/js/jquery.jenkins.js"></script>
<!-- @endif -->
<!-- @if NODE_ENV == 'PRODUCTION' -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://cdn.foo.com/<!-- @echo name -->/<!-- @echo version -->/<!-- @echo now -->/<!-- @echo ver -->/js/<!-- @echo name -->.min.js"></script>
<!-- @endif -->
Run Code Online (Sandbox Code Playgroud)
我确信我的设置与大多数人不同,以上的用处取决于你的情况.对我来说,虽然它是一个很棒的代码,但Yeoman grunt-usemin比我个人需要的更强大.
注意:我刚刚发现了上面列出的任务,因此我可能会错过一项功能和/或我的流程可能会改变.就目前而言,我喜欢grunt-preprocess和grunt-env所提供的简单性和功能.:)
投票率下降的动机......
当我发布这个答案时,Grunt 0.4.x
提供的解决方案并没有太多选择可以满足我的需求.现在,几个月后,我猜想有更多的选择可能比我在这里发布的更好.虽然我仍然亲自使用,并喜欢使用这种技术用于我的构建,但我要求未来的读者花时间阅读给出的其他答案并研究所有选项.如果您找到更好的解决方案,请在此处发布您的答案.
我不确定它是否会对任何人有任何帮助,但我在GitHub上创建了这个演示存储库,它使用我上面概述的技术显示了一个完整的(并且更复杂的设置).
Dmi*_*ich 34
我想出了自己的解决方案.还没有打磨,但我想我会朝这个方向前进.
在essense中,我正在使用grunt.template.process()index.html
从分析当前配置的模板生成我,并生成我原始源文件的列表或指向具有缩小代码的单个文件的链接.下面的示例适用于js文件,但相同的方法可以扩展到css和任何其他可能的文本文件.
grunt.js
:
/*global module:false*/
module.exports = function(grunt) {
var // js files
jsFiles = [
'src/module1.js',
'src/module2.js',
'src/module3.js',
'src/awesome.js'
];
// Import custom tasks (see index task below)
grunt.loadTasks( "build/tasks" );
// Project configuration.
grunt.initConfig({
pkg: '<json:package.json>',
meta: {
banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %> */'
},
jsFiles: jsFiles,
// file name for concatenated js
concatJsFile: '<%= pkg.name %>-all.js',
// file name for concatenated & minified js
concatJsMinFile: '<%= pkg.name %>-all.min.js',
concat: {
dist: {
src: ['<banner:meta.banner>'].concat(jsFiles),
dest: 'dist/<%= concatJsFile %>'
}
},
min: {
dist: {
src: ['<banner:meta.banner>', '<config:concat.dist.dest>'],
dest: 'dist/<%= concatJsMinFile %>'
}
},
lint: {
files: ['grunt.js'].concat(jsFiles)
},
// options for index.html builder task
index: {
src: 'index.tmpl', // source template file
dest: 'index.html' // destination file (usually index.html)
}
});
// Development setup
grunt.registerTask('dev', 'Development build', function() {
// set some global flags that all tasks can access
grunt.config('isDebug', true);
grunt.config('isConcat', false);
grunt.config('isMin', false);
// run tasks
grunt.task.run('lint index');
});
// Production setup
grunt.registerTask('prod', 'Production build', function() {
// set some global flags that all tasks can access
grunt.config('isDebug', false);
grunt.config('isConcat', true);
grunt.config('isMin', true);
// run tasks
grunt.task.run('lint concat min index');
});
// Default task
grunt.registerTask('default', 'dev');
};
Run Code Online (Sandbox Code Playgroud)
index.js (the index task)
:
module.exports = function( grunt ) {
grunt.registerTask( "index", "Generate index.html depending on configuration", function() {
var conf = grunt.config('index'),
tmpl = grunt.file.read(conf.src);
grunt.file.write(conf.dest, grunt.template.process(tmpl));
grunt.log.writeln('Generated \'' + conf.dest + '\' from \'' + conf.src + '\'');
});
}
Run Code Online (Sandbox Code Playgroud)
最后,index.tmpl
使用生成逻辑:
<doctype html>
<head>
<%
var jsFiles = grunt.config('jsFiles'),
isConcat = grunt.config('isConcat');
if(isConcat) {
print('<script type="text/javascript" src="' + grunt.config('concat.dist.dest') + '"></script>\n');
} else {
for(var i = 0, len = jsFiles.length; i < len; i++) {
print('<script type="text/javascript" src="' + jsFiles[i] + '"></script>\n');
}
}
%>
</head>
<html>
</html>
Run Code Online (Sandbox Code Playgroud)
UPD.发现Yeoman基于grunt,具有内置的usemin任务,可与Yeoman的构建系统集成.它根据index.html的开发版本中的信息以及其他环境设置生成index.html的生产版本.看起来有点复杂但有趣.
Dan*_*lan 15
我不喜欢这里的解决方案(包括我之前给出的解决方案),原因如下:
我已经想出如何解决这两个问题.我已经设置了我的grunt任务,以便每次添加或删除文件时,都会自动生成脚本标记以反映这一点.这样,在添加/删除/重命名JS文件时,您无需修改html文件或grunt文件.
总结一下它是如何工作的,我有一个带有脚本标签变量的html模板.我使用https://github.com/alanshaw/grunt-include-replace来填充该变量.在开发模式下,该变量来自我所有JS文件的通配模式.当添加或删除JS文件时,监视任务会重新计算此值.
现在,要在dev或prod模式下获得不同的结果,只需使用不同的值填充该变量即可.这是一些代码:
var jsSrcFileArray = [
'src/main/scripts/app/js/Constants.js',
'src/main/scripts/app/js/Random.js',
'src/main/scripts/app/js/Vector.js',
'src/main/scripts/app/js/scripts.js',
'src/main/scripts/app/js/StatsData.js',
'src/main/scripts/app/js/Dialog.js',
'src/main/scripts/app/**/*.js',
'!src/main/scripts/app/js/AuditingReport.js'
];
var jsScriptTags = function (srcPattern, destPath) {
if (srcPattern === undefined) {
throw new Error("srcPattern undefined");
}
if (destPath === undefined) {
throw new Error("destPath undefined");
}
return grunt.util._.reduce(
grunt.file.expandMapping(srcPattern, destPath, {
filter: 'isFile',
flatten: true,
expand: true,
cwd: '.'
}),
function (sum, file) {
return sum + '\n<script src="' + file.dest + '" type="text/javascript"></script>';
},
''
);
};
...
grunt.initConfig({
includereplace: {
dev: {
options: {
globals: {
scriptsTags: '<%= jsScriptTags(jsSrcFileArray, "../../main/scripts/app/js")%>'
}
},
src: [
'src/**/html-template.html'
],
dest: 'src/main/generated/',
flatten: true,
cwd: '.',
expand: true
},
prod: {
options: {
globals: {
scriptsTags: '<script src="app.min.js" type="text/javascript"></script>'
}
},
src: [
'src/**/html-template.html'
],
dest: 'src/main/generatedprod/',
flatten: true,
cwd: '.',
expand: true
}
...
jsScriptTags: jsScriptTags
Run Code Online (Sandbox Code Playgroud)
jsSrcFileArray
是典型的grunt文件循环模式. jsScriptTags
将jsSrcFileArray
它们与script
两侧的标签连接在一起. destPath
是我想要的每个文件的前缀.
以下是HTML的样子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Example</title>
</head>
<body>
@@scriptsTags
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
现在,正如您在配置中看到的那样,script
当它在prod
模式下运行时,我将该变量的值生成为硬编码标记.在开发模式下,此变量将扩展为如下值:
<script src="../../main/scripts/app/js/Constants.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/Random.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/Vector.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/StatsData.js" type="text/javascript"></script>
<script src="../../main/scripts/app/js/Dialog.js" type="text/javascript"></script>
Run Code Online (Sandbox Code Playgroud)
如果您有任何疑问,请告诉我.
PS:对于我想在每个客户端JS应用程序中执行的操作,这是一个疯狂的代码量.我希望有人可以把它变成一个可重用的插件.也许有一天我会.
Per*_*son 13
我一直在问自己同样的问题,我认为这个grunt插件可以配置为你想要的:https://npmjs.org/package/grunt-targethtml.它实现了依赖于grunt目标的条件html标记.
我正在寻找一个更简单,更直接的解决方案,所以我结合了这个问题的答案:
并提出了以下简单步骤:
在您的index.html文件的Gruntfile.js的concat/copy块中使用以下逻辑:
concat: {
index: {
src : [ (function() {
if (grunt.option('Release')) {
return 'views/index-production.html';
} else {
return 'views/index-development.html';
}
}()) ],
dest: '<%= distdir %>/index.html',
...
},
...
},
Run Code Online (Sandbox Code Playgroud)运行'grunt --Release'选择index-production.html文件,并取消标志以获得开发版本.
没有新的插件可以添加或配置,也没有新的grunt任务.
grunt-dom-munger使用CSS选择器读取和操作HTML.防爆.从你的HTML中读取标签.删除节点,添加节点等.
您可以使用grunt-dom-munger读取您的index.html链接的所有JS文件,uglify它们然后再次使用grunt-dom-munger修改index.html以仅链接缩小的JS
我发现了一个名为grunt-dev-prod-switch的grunt插件.它所做的就是根据你传递给grunt的--env选项注释掉它寻找的某些块(虽然它限制你开发,生成和测试).
按照此处说明进行设置后,您可以运行例如:
grunt serve --env=dev
它所做的只是注释掉包裹的块
<!-- env:test/prod -->
your code here
<!-- env:test/prod:end -->
Run Code Online (Sandbox Code Playgroud)
并且它将取消注释被包裹的块
<!-- env:dev -->
your code here
<!-- env:dev:end -->
Run Code Online (Sandbox Code Playgroud)
它也适用于javascript,我用它来设置正确的IP地址连接到我的后端API.块只是改为
/* env:dev */
your code here
/* env:dev:end */
Run Code Online (Sandbox Code Playgroud)
在你的情况下,它会像这样简单:
<!DOCTYPE html>
<html>
<head>
<!-- env:dev -->
<script src="js/module1.js" />
<script src="js/module2.js" />
<script src="js/module3.js" />
...
<!-- env:dev:end -->
<!-- env:prod -->
<script src="js/MyApp-all.min.js" />
...
<!-- env:prod:end -->
</head>
<body></body>
</html>
Run Code Online (Sandbox Code Playgroud)