209

Web アプリケーションのビルド ツールとして Grunt を使用しようとしています。

少なくとも 2 つのセットアップが必要です。

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>

Ⅱ.本番環境のセットアップ- スクリプトを縮小および連結して 1 つのファイルにロードし、

それに応じてindex.htmlを使用:

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

問題は、実行時の構成に応じて、これらの index.html を作成するにはどうすればよいですgrunt devgrunt prod?

または、間違った方向に掘り下げていて、常に生成する方が簡単ですがMyApp-all.min.js、すべてのスクリプト (連結) またはそれらのスクリプトを個別のファイルから非同期にロードするローダー スクリプトのいずれかをその中に入れますか?

どうやってやるの?

4

12 に答える 12

161

私は最近、次の Gruntv0.4.0互換タスクを発見しました。

以下は、私のGruntfile.js.

環境設定:

env : {

    options : {

        /* Shared Options Hash */
        //globalOption : 'foo'

    },

    dev: {

        NODE_ENV : 'DEVELOPMENT'

    },

    prod : {

        NODE_ENV : 'PRODUCTION'

    }

},

前処理:

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 %>'
            }

        }

    }

}

タスク:

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']);

そして/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 -->

私のセットアップはほとんどの人とは異なると確信しており、上記の有用性は状況によって異なります。私にとって、これはすばらしいコードですが、Yeoman grunt-useminは私が個人的に必要とするよりも堅牢です。

注:今日、上記のタスクを発見したばかりなので、機能が不足している可能性や、プロセスが今後変更される可能性があります今のところ、grunt-preprocessgrunt-envが提供するシンプルさ機能が気に入っています。:)


2014 年 1 月の更新:

反対票に動機付けられた...

この回答を投稿したとき0.4.x、私のニーズに合ったソリューションを提供する Grunt のオプションはあまりありませんでした。数か月経った今、私がここに投稿したものよりも優れたオプションが他にもあると思います. 私はまだ個人的にこのテクニックをビルドに使用し、楽しんでいますが、将来の読者は、与えられた他の回答を読んで、すべてのオプションを調査するために時間を割いてください. より良い解決策を見つけた場合は、ここに回答を投稿してください。

2014 年 2 月の更新:

誰にとっても役立つかどうかはわかりませんが、上記で概説した手法を使用して完全な (そしてより複雑なセットアップ) を示すこのデモ リポジトリを GitHub に作成しました。

于 2013-02-20T00:40:40.650 に答える
35

私は独自の解決策を思いつきました。まだ洗練されていませんが、その方向に進むと思います。

本質的に、私は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 (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 + '\'');
    });
}

最後に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>

アップデート。gruntに基づくYeomanには、Yeoman のビルド システムと統合する組み込みのuseminタスクがあることがわかりました。開発版のindex.htmlの情報やその他の環境設定から本番版のindex.htmlを生成します。少し洗練されていますが、見ていて面白いです。

于 2012-09-14T12:51:32.913 に答える
14

私はしばらくの間同じ質問を自問してきましたが、この grunt プラグインはあなたが望むように設定できると思います: https://npmjs.org/package/grunt-targethtml。grunt ターゲットに依存する条件付き html タグを実装します。

于 2012-10-01T20:27:51.863 に答える
8

私はよりシンプルで簡単な解決策を探していたので、この質問からの答えを組み合わせました:

if else ブロックを gruntfile.js に配置する方法

そして、次の簡単な手順を思いつきました:

  1. リストしたインデックス ファイルの 2 つのバージョンを保持し、index-development.html と index-prodoction.html という名前を付けます。
  2. 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',
           ...
        },
        ...
    },
    
  3. 「grunt --Release」を実行して index-production.html ファイルを選択し、フラグをオフにして開発バージョンを取得します。

追加または構成する新しいプラグインはなく、新しい単調なタスクもありません。

于 2014-01-08T22:59:59.773 に答える
5

grunt-dev-prod-switch という grunt プラグインを見つけました。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 でも動作します。バックエンド API に接続するための適切な IP アドレスを設定するために使用します。ブロックは次のように変わります

    /* 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>
于 2015-04-07T18:50:34.420 に答える
5

scriptlinkerという名前のこの単調なタスクは、開発モードでスクリプトを追加する簡単な方法のように見えます。おそらく最初に concat タスクを実行してから、prod モードで連結されたファイルを指すようにすることができます。

于 2013-08-19T17:43:34.830 に答える
4

grunt にこれらのタスクを処理させるには、wiredep https://github.com/taptapship/wiredepと usemin https://github.com/yeoman/grunt-useminを組み合わせて使用​​します。Wiredep は依存関係を一度に 1 つのスクリプト ファイルに追加し、usemin はそれらすべてを実稼働用の 1 つのファイルに連結します。これは、いくつかの html コメントだけで実現できます。たとえば、次のコマンドを実行すると、bower パッケージが自動的にインクルードされ、html に追加されますbower install && grunt bowerInstall

<!-- build:js /scripts/vendor.js -->
<!-- bower:js -->
<!-- endbower -->
<!-- endbuild -->
于 2014-06-09T19:57:08.027 に答える
4

grunt-bake は、ここでうまく機能する素晴らしい grunt スクリプトです。JQM 自動ビルド スクリプトで使用します。

https://github.com/imaginethepoet/autojqmphonegap

私の grunt.coffee ファイルを見てください:

bake:
    resources: 
      files: "index.html":"resources/custom/components/base.html"

これは、base.html 内のすべてのファイルを調べ、それらを吸い込んで index.html を作成します。これはマルチページ アプリ (phonegap) に最適です。これにより、すべての開発者が 1 つの長い単一ページ アプリで作業しているわけではないため、開発が容易になります (多数の競合チェックインが回避されます)。代わりに、ページを分割してコードの小さなチャンクで作業し、watch コマンドを使用して完全なページにコンパイルできます。

Bake は base.html からテンプレートを読み取り、watch にコンポーネントの html ページを挿入します。

<!DOCTYPE html>

jQuery モバイルのデモ

app.initialize();

<body>
    <!--(bake /resources/custom/components/page1.html)-->
    <!--(bake /resources/custom/components/page2.html)-->
    <!--(bake /resources/custom/components/page3.html)-->
</body>

これをさらに一歩進めて、ページに「メニュー」「ポップアップ」などのインジェクションを追加すると、ページをより小さな管理しやすいコンポーネントに実際に分割できます。

于 2013-12-13T21:12:12.913 に答える
2

この答えは初心者向けではありません!

Jade テンプレートを使用する ... Jade テンプレートに変数を渡すのは標準的な使用例です

私はうなり声 (grunt-contrib-jade) を使用していますが、うなり声を使用する必要はありません。標準の 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 ロジックを使用できます。

クラスが存在するかどうかに基づいてページに要素を含めるためにng-ifを実行できるため、Angularを使用する場合、これは素晴らしいことです。

たとえば、クラスが存在する場合はスクリプトを含めることができます...

(たとえば、ライブ リロード スクリプトを開発に含めて、運用には含めない場合があります)

<script ng-if="controller.isClassPresent()" src="//localhost:35729/livereload.js"></script> 
于 2015-06-30T10:27:43.310 に答える