我试图使用Grunt作为我的网络应用程序的构建工具。

我想至少有两个设置:

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>

2生产设置-加载我的脚本缩小和连接在一个文件,

根据index.html:

<!DOCTYPE html>
<html>
    <head>
        <script src="js/MyApp-all.min.js" />
    </head>
    <body></body>
</html>

问题是,当我运行grunt dev或grunt prod时,我如何让grunt根据配置创建这些index.html ?

或者也许我在错误的方向上挖掘,它会更容易总是生成MyApp-all.min.js,但把它里面要么我所有的脚本(连接)或加载器脚本异步加载这些脚本从单独的文件?

你们是怎么做到的,伙计们?


当前回答

我发现了一个叫咕哝-dev-prod-switch的插件。它所做的只是根据您传递给grunt的——env选项注释掉它所寻找的某些块(尽管它将您限制为dev、prod和test)。

一旦你设置好它,你可以运行,例如:

Grunt serve——env=dev,它所做的就是注释掉被

    <!-- env:test/prod -->
    your code here
    <!-- env:test/prod:end -->

它会取消注释那些被

    <!-- env:dev -->
    your code here
    <!-- env:dev:end -->

它也适用于javascript,我用它来设置正确的IP地址连接到我的后端API。方块变成

    /* env:dev */
    your code here
    /* env:dev:end */

在你的情况下,它会像这样简单:

<!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>

其他回答

这个答案不适合新手!

使用玉石模板…将变量传递给Jade模板是一个标准的用例

我用的是grunt(咕哝-contrib-jade),但你不必用grunt。只需使用标准的npm jade模块。

如果使用grunt,那么你的gruntfile会像这样…

jade: {
    options: {
      // TODO - Define options here
    },
    dev: {
      options: {
        data: {
          pageTitle: '<%= grunt.file.name %>',
          homePage: '/app',
          liveReloadServer: liveReloadServer,
          cssGruntClassesForHtmlHead: 'grunt-' + '<%= grunt.task.current.target %>'
        },
        pretty: true
      },
      files: [
        {
          expand: true,
          cwd: "src/app",
          src: ["index.jade", "404.jade"],
          dest: "lib/app",
          ext: ".html"
        },
        {
          expand: true,
          flatten: true,
          cwd: "src/app",
          src: ["directives/partials/*.jade"],
          dest: "lib/app/directives/partials",
          ext: ".html"
        }
      ]
    }
  },

现在我们可以很容易地访问Jade模板中grunt传递的数据。

与Modernizr使用的方法非常相似,我根据传递的变量值在HTML标记上设置了一个CSS类,并且可以根据CSS类是否存在从那里使用JavaScript逻辑。

如果使用Angular,这是非常棒的,因为你可以根据类是否存在来在页面中包含元素。

例如,我可能会包含一个脚本,如果类是存在的…

(例如,我可能在开发中包含实时重载脚本,但在生产中不包含)

<script ng-if="controller.isClassPresent()" src="//localhost:35729/livereload.js"></script> 

我已经有了自己的解决办法。还没有完善,但我想我会朝着那个方向发展。

从本质上讲,我使用了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');
};

index.js(索引任务):

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 + '\'');
    });
}

最后,指数。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>

乌利希期刊指南。发现Yeoman基于grunt,有一个内置的usemin任务,与Yeoman的构建系统集成。它根据index.html开发版本中的信息以及其他环境设置生成index.html的生产版本。有点复杂,但看起来很有趣。

我不喜欢这里的解决方案(包括我之前给出的),原因如下:

投票最多的答案的问题是,当你添加/重命名/删除一个JS文件时,你必须手动同步脚本标签列表。 接受的答案的问题是你的JS文件列表不能有模式匹配。这意味着你必须在Gruntfile中手动更新它。

我已经找到了解决这两个问题的方法。我已经设置了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

jsSrcFileArray是典型的grunt文件替换模式。jsScriptTags接受jsSrcFileArray,并将它们与两侧的脚本标记连接在一起。destPath是我想在每个文件上使用的前缀。

下面是HTML的样子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Example</title>

</head>

<body>    
@@scriptsTags
</body>
</html>

现在,正如您在配置中看到的,当它在prod模式下运行时,我将该变量的值生成为一个硬编码的脚本标记。在dev模式下,该变量将展开为如下值:

<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>

如果你有任何问题请告诉我。

PS:对于我想在每个客户端JS应用中做的事情来说,这是一个疯狂的代码量。我希望有人能把它变成一个可重用的插件。也许有一天我会的。

我一直在问自己同样的问题,我认为这个grunt插件可以配置成你想要的:https://npmjs.org/package/grunt-targethtml。它实现了条件html标记,依赖于grunt目标。

使用wiredep https://github.com/taptapship/wiredep和usemin https://github.com/yeoman/grunt-usemin的组合,以便让grunt照顾这些任务。Wiredep会一次添加一个脚本文件,而usemin会将它们全部连接到一个文件中进行生产。这可以通过一些html注释来完成。例如,当我运行bower install && grunt bowerInstall时,我的bower包会自动包含并添加到html中:

<!-- build:js /scripts/vendor.js -->
<!-- bower:js -->
<!-- endbower -->
<!-- endbuild -->