Есть грунт генерировать индекс.html для различных настроек
Я пытаюсь использовать Grunt в качестве инструмента сборки для моего веб-приложения.
Я хочу иметь по крайней мере двух установок:
И. разработка установки - загрузки скриптов из отдельных файлов, без конкатенации,
так что мой индекс.html будет выглядеть примерно так:
<!DOCTYPE html>
<html>
<head>
<script src="js/module1.js" />
<script src="js/module2.js" />
<script src="js/module3.js" />
...
</head>
<body></body>
</html>
второй. Установки производства - загрузите мои скрипты, уменьшенные и объединенные в один файл,
с индексом.html соответственно:
<!DOCTYPE html>
<html>
<head>
<script src="js/MyApp-all.min.js" />
</head>
<body></body>
</html>
в вопрос в том,как я могу сделать хрюканье сделать эти индексы.html зависит от конфигурации, когда я запускаю grunt dev или grunt prod?
или, может быть, я копаю в неправильном направлении, и было бы проще всегда генерировать MyApp-all.min.js но поместите в него либо все мои скрипты (объединенные), либо скрипт загрузчика, который асинхронно загружает эти скрипты из отдельных файлов?
как вы это делаете, ребята?
12 ответов:
Я недавно обнаружил эти хрюкать
v0.4.0совместимые задачи:
Grunt задача вокруг модуля npm предварительной обработки.
Grunt задача для автоматизации настройки среды для будущих задач.
ниже приведены фрагменты из моего
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 -->Я уверен, что моя установка отличается от большинства людей, и полезность выше, будет зависеть от вашей ситуации. Для меня, в то время как это удивительный бит кода, Йомен грунт-usemin является более надежным, чем мне лично нужно.
Примечание: я просто обнаружен перечисленные выше задачи сегодня, поэтому я могу пропустить функцию и / или мой процесс может измениться в будущем. На данный момент, я люблю простоту и функции, которые grunt-preprocess и grunt-env должны предложить. :)
Jan 2014 update:
мотивировано голосованием вниз ...
когда я опубликовал этот ответ, не было много вариантов для Grunt
0.4.xэто предложило решение, которое работало для моих нужд. Сейчас, месяцы спустя, я бы предположил, что есть больше вариантов, что может быть лучше, чем то, что я выложил здесь. в то время как я все еще лично использую и наслаждаюсь использованием этой техники для моих сборок, я прошу, чтобы будущие читатели нашли время, чтобы прочитать другие ответы, данные и исследовать все варианты. если вы найдете лучшее решение, пожалуйста, напишите свой ответ здесь.Feb 2014 update:
Я не уверен, что это будет любая помощь кому угодно, но я создал этот демонстрационный репозиторий на GitHub это показывает полную (и более сложную настройку), используя технику(ы), которую я описал выше.
Я придумал свое собственное решение. Еще не отполирован, но я думаю, что буду двигаться в этом направлении.
в сущности, я использую хрюкать.шаблон.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>
UPD. узнал, что старшина, который основан на grunt, имеет встроенный usemin задача, которая интегрируется с системой сборки Yeoman. Он генерирует производственную версию индекса.html из информации в разработке версия индекса.HTML, а также другие параметры среды. Немного сложный, но интересный.
мне не нравятся решения здесь (в том числе тот, который я ранее дал) и вот почему:
- проблема с самый высокий проголосовал ответ это то, что вы должны вручную синхронизировать список тегов скрипта при добавлении/переименовании/удалении файла JS.
- проблема с принято отвечать это то, что ваш список JS-файлов не может иметь соответствия шаблону. Это означает, что вы должны обновить его вручную в Gruntfile.
я придумал, как решить обе эти проблемы. Я настроил свою задачу grunt так, что каждый раз, когда файл добавляется или удаляется, теги скрипта автоматически генерируются, чтобы отразить это. Таким образом, вам не нужно изменять html-файл или файл grunt при добавлении / удалении / переименовании файлов JS.
чтобы суммировать, как это работает, у меня есть шаблон html с переменной для тегов скрипта. Я использую https://github.com/alanshaw/grunt-include-replace для заполнения этой переменной. В режиме разработчика, что переменная приходит из глоббинг образец все мои 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- Это ваш типичный хряк файл-подстановка шаблона.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>Дайте мне знать, если у вас есть какие-либо вопросы.
PS: Это сумасшедшее количество кода для того, что я хотел бы сделать в каждом клиентском JS-приложении. Я надеюсь, что кто-то может превратить это в плагин многоразовые. Может быть, когда-нибудь и буду.
Я задавал себе тот же вопрос некоторое время, и я думаю, что этот плагин grunt может быть настроен на то, что вы хотите:https://npmjs.org/package/grunt-targethtml. он реализует условные HTML-теги, которые зависят от цели grunt.
Я искал более простое, прямое решение, поэтому я объединил ответ из этого вопроса:
как разместить блок if else в gruntfile.js
и придумал следующие простые шаги:
- сохраните две версии ваших индексных файлов, как вы указали, и назовите их index-development.html и индекс-prodoction.формат html.
используйте следующую логику в вашем Gruntfile.Яш это функция concat/скопировать блок в свой индекс.HTML-файл:
concat: { index: { src : [ (function() { if (grunt.option('Release')) { return 'views/index-production.html'; } else { return 'views/index-development.html'; } }()) ], dest: '<%= distdir %>/index.html', ... }, ... },запустите 'grunt -- Release', чтобы выбрать индекс-производство.html-файл и оставить флаг, чтобы иметь версию разработки.
никаких новых плагинов для добавления или настройки и никаких новых задач grunt.
Это хрюканье задача с именем scriptlinker выглядит, как простой способ добавить скрипты в режиме разработки. Вероятно, вы можете сначала запустить задачу concat, а затем указать ее на свой объединенный файл в режиме prod.
grunt-dom-munger читает и манипулирует HTML с помощью селекторов CSS. Бывший. читать теги из HTML. Удаление узлов, добавление узлов и многое другое.
вы можете использовать grunt-dom-munger для чтения всех ваших JS-файлов, связанных с вашим индексом.html, уродуйте их, а затем снова используйте grunt-dom-munger, чтобы изменить свой индекс.html только для ссылки на уменьшенный JS
я нашел плагин grunt под названием grunt-dev-prod-switch. Все, что он делает, это комментирует определенные блоки, которые он ищет на основе опции --env, которую вы передаете в grunt (хотя она ограничивает вас 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>
grunt-bake-это фантастический сценарий grunt, который будет отлично работать здесь. Я использую его в своем сценарии автоматической сборки JQM.
https://github.com/imaginethepoet/autojqmphonegap
взгляните на мое ворчание.кофе файл:
bake: resources: files: "index.html":"resources/custom/components/base.html"это смотрит на все файлы в базе.html и всасывает их для создания индекса.html отлично работает для многостраничных приложений (phonegap). Это позволяет упростить разработку, поскольку все разработчики не работают на одном длинном одностраничном приложении (предотвращение большого количества проверок конфликтов). Вместо этого вы можете разбить страницы и работать с меньшими кусками кода и компилировать на всю страницу с помощью команды watch.
Bake считывает шаблон из базы.html и вводит компонентные html-страницы на часах.
<!DOCTYPE html>jQuery Mobile Demos
приложение.инициализировать();
<body> <!--(bake /resources/custom/components/page1.html)--> <!--(bake /resources/custom/components/page2.html)--> <!--(bake /resources/custom/components/page3.html)--> </body>вы можете сделать этот шаг дальше и добавить инъекции на свои страницы для "меню" "всплывающие окна" и т. д., Чтобы вы действительно могли разбить страницы на более мелкие управляемые компоненты.
используйте комбинацию wiredep https://github.com/taptapship/wiredep и usemin https://github.com/yeoman/grunt-usemin для того, чтобы иметь grunt заботиться об этих задачах. Wiredep добавит ваши зависимости по одному файлу скрипта за раз, а usemin объединит их все в один файл для производства. Это может быть достигнуто только с некоторыми комментариями html. Например, мои пакеты bower автоматически включаются и добавляются в html при запуске
bower install && grunt bowerInstall:<!-- build:js /scripts/vendor.js --> <!-- bower:js --> <!-- endbower --> <!-- endbuild -->
считают processhtml. Это позволяет определить несколько "целей"для сборки. Комментарии используются для условного включения или исключения материала из HTML:
<!-- build:js:production js/app.js --> ... <!-- /build -->становится
<script src="js/app.js"></script>Он даже претендует на то, чтобы делать изящные вещи вроде этого (см. README):
<!-- build:[class]:dist production --> <html class="debug_mode"> <!-- /build --> <!-- class is changed to 'production' only when the 'dist' build is executed --> <html class="production">
этот ответ не для нубов!
используйте нефритовые шаблоны ... передача переменных в шаблон Jade-это стандартный вариант использования bog
Я использую grunt (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" } ] } },теперь мы можем легко получить доступ к данным, переданным grunt в шаблоне Jade.
очень похоже на подход, используемый с помощью Modernizr я устанавливаю класс CSS на теге HTML в соответствии со значением передаваемой переменной и могу использовать логику JavaScript оттуда, основываясь на том, присутствует ли класс CSS или нет.
это здорово, если вы используете Angular, так как вы можете сделать ng-if для включения элементов на странице в зависимости от того, присутствует ли класс.
например, я мог бы включить скрипт, если класс присутствует ...
(например, я мог бы включить сценарий live reload в dev, но не в производство)
<script ng-if="controller.isClassPresent()" src="//localhost:35729/livereload.js"></script>
Comments