[javascript] Grunt가 다른 설정을 위해 index.html을 생성하게하십시오

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>

II. 프로덕션 설정 -하나의 파일로 축소 및 연결된 스크립트를로드합니다.

index.html과 함께 :

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

문제는,이다 어떻게 내가 실행할 때이 index.html을의 따라 구성에 만들 꿀꿀 할 수 있습니다 grunt dev또는 grunt prod?

아니면 내가 잘못된 방향으로 파고 있고 항상 MyApp-all.min.js모든 스크립트 (연결 된) 또는 별도의 파일에서 해당 스크립트를 비동기 적으로로드하는 로더 스크립트 중 하나를 생성하는 것이 더 쉬울 까요?

어떻게합니까?



답변

최근에 이러한 Grunt v0.4.0호환 작업을 발견했습니다 .

  • 그런트 전처리

    전처리 npm 모듈에 대한 그런트 작업.

  • 그런트

    향후 작업을 위해 환경 구성을 자동화하는 그런트 작업.

아래는 내 스 니펫입니다 Gruntfile.js.

ENV 설정 :

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 월 업데이트 :

다운 투표로 동기 부여 …

이 답변을 게시했을 때 Grunt의 옵션이 많지 않아 0.4.x내 요구에 맞는 솔루션을 제공했습니다. 이제 개월 후, 나는 거기에 더 많은 옵션이 있음을 추측 할 수있는 내가 여기에 게시 한 것보다 더 나은가. 필자는 개인적으로이 빌드를 위해이 기술을 개인적으로 사용하고 즐겁게 사용 하면서 미래의 독자들에게 주어진 다른 답변을 읽고 모든 옵션을 연구 할 시간을 가지라고 요청합니다. 더 나은 해결책을 찾으면 여기에 답변을 게시하십시오.

2014 년 2 월 업데이트 :

그것이 누군가에게 도움이 될지 확신 할 수 없지만, GitHub 에서 위에서 설명한 기술을 사용하여 완전한 (더 복잡한 설정)을 보여주는 데모 저장소를 만들었습니다 .


답변

나는 내 자신의 해결책을 생각해 냈습니다. 아직 닦지 않았지만 그 방향으로 움직일 것 같습니다.

본질적으로 , grunt.template.process () 를 사용하여 index.html현재 구성을 분석하고 원본 소스 파일 목록 또는 축소 된 코드가 포함 된 단일 파일에 대한 링크를 생성 하는 템플릿에서 my를 생성 합니다. 아래 예제는 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>

UPD. 것을 발견 보좌관 꿀꿀을 기반으로, 내장 된 usemin의 작업이 보좌관의 빌드 시스템과 통합됩니다. 개발 환경의 index.html 정보 및 기타 환경 설정에서 index.html의 프로덕션 버전을 생성합니다. 조금 정교하지만보기에는 흥미 롭습니다.


답변

나는 여기 ( 이전에 제공 한 솔루션 포함)의 솔루션을 싫어 하며 여기에 이유가 있습니다.

  • 가장 높은 투표 응답 의 문제점 은 JS 파일을 추가 / 이름 바꾸기 / 삭제할 때 스크립트 태그 목록을 수동으로 동기화해야한다는 것입니다.
  • 허용되는 답변 의 문제점 은 JS 파일 목록에 패턴 일치가 없다는 것입니다. 이것은 Gruntfile에서 직접 업데이트해야한다는 것을 의미합니다.

이 두 가지 문제를 해결하는 방법을 알아 냈습니다. 파일을 추가하거나 삭제할 때마다 스크립트 태그가 자동으로 생성되도록 해당 작업을 설정했습니다. 이런 식으로 JS 파일을 추가 / 제거 / 이름 바꾸기 할 때 html 파일이나 grunt 파일을 수정할 필요가 없습니다 .

그 작동 방식을 요약하기 위해 스크립트 태그 변수가있는 html 템플릿이 있습니다. https://github.com/alanshaw/grunt-include-replace 를 사용 하여 해당 변수를 채 웁니다. dev 모드에서 해당 변수는 모든 JS 파일의 글 로빙 패턴에서 비롯됩니다. watch 파일 태스크는 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와 함께 연결합니다 script. destPath각 파일에서 원하는 접두사입니다.

HTML은 다음과 같습니다.

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

</head>

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

이제 설정에서 볼 수 있듯이 모드 script에서 실행될 때 해당 변수의 값을 하드 코딩 된 태그 로 생성 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>

궁금한 점이 있으면 알려주세요.

추신 : 이것은 모든 클라이언트 측 JS 앱에서하고 싶은 무언가를위한 미친 양의 코드입니다. 누군가가 이것을 재사용 가능한 플러그인으로 바꿀 수 있기를 바랍니다. 아마 언젠가는


답변

나는 잠시 동안 나 자신에게 같은 질문을하고 있었고,이 grunt 플러그인은 원하는 것을 수행하도록 구성 될 수 있다고 생각한다 : https://npmjs.org/package/grunt-targethtml . 그런 대상에 따라 조건부 html 태그를 구현합니다.


답변

더 간단하고 직접적인 솔루션을 찾고 있었 으므로이 질문에 대한 답변을 결합했습니다.

gruntfile.js에 블록이 있으면 배치하는 방법

다음과 같은 간단한 단계를 생각해 냈습니다.

  1. 나열된대로 두 가지 버전의 색인 파일을 유지하고 이름을 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 파일을 선택하고 개발 버전을 갖도록 플래그를 생략하십시오.

추가하거나 구성 할 수있는 새로운 플러그인과 새로운 그런 작업이 없습니다.


답변

scriptlinker 라는 이름의이 거친 작업 은 dev 모드에서 스크립트를 추가하는 쉬운 방법처럼 보입니다. concat 작업을 먼저 실행 한 다음 prod 모드에서 연결된 파일을 가리킬 수 있습니다.


답변

grunt-dom-munger 는 CSS 선택기로 HTML을 읽고 조작합니다. 전의. HTML에서 태그를 읽습니다. 노드 제거, 노드 추가 등.

grunt-dom-munger를 사용하여 index.html에 의해 링크 된 모든 JS 파일을 읽고, 결합한 다음 grunt-dom-munger를 다시 사용하여 index.html을 수정하여 축소 된 JS 만 링크 할 수 있습니다.