Добрый день, коллеги!
Хотел поделиться своими наработками в области автоматизации процесса сборки javascript проекта использующего Google Closure Compiler и Google Closure Library при помощи Apache Maven. Страничка проекта https://github.com/urmuzov/closure-maven, там же лежит документация по каждому из компонентов проекта.
Главный компонент проекта — это архетип. Архетип объединяет в себя все остальные компоненты проекта, которые при желании могут использоваться отдельно от него.
Архетип предоставляет средства для решения самых часто встречающихся задач при разработке, а именно:
С профилями
Создать проект при помощи этого архетипа очень просто, достаточно выполнить команду (вам потребуется maven версии 3):
Этой командой вы скажете maven сгенерировать проект исходя из архетипа
Maven сгенерирует такую иерархию каталогов и файлов: (
Для того чтобы разобраться что здесь для чего, попробуем собрать проект.
Для того чтобы собрать проект необходимо выполнить следующую команду. Вместо
Большие куски логов, которые не интересны с точки зрения архетипа я убрал.
Скомпилированный проект выглядит так:
В процессе сборки были выполнены следующие операции:
В принципе все IDE имеют схожий функционал для работы с maven.
Для быстрого переключения модулей в NetBeans есть выпадающий список в тулбаре, профили в списке появляются автоматически:

В IntelliJ IDEA тоже выбирается из выпадающего списка в тулбаре:

Но добавляются вручную:

Для Eclipse, я думаю, все делается аналогично.
В принципе этого должно быть достаточно для того чтобы разобраться в использовании этого архетипа, но если что обращайтесь ко мне или к документации, которая пока что только на русском языке:
Также возможно кому-то будет интересен этот проект с точки зрения использования всех перечисленных выше наработок в одном более сложном проекте.
Ну и как говорится, Fork me on GitHub!
Хотел поделиться своими наработками в области автоматизации процесса сборки javascript проекта использующего Google Closure Compiler и Google Closure Library при помощи Apache Maven. Страничка проекта https://github.com/urmuzov/closure-maven, там же лежит документация по каждому из компонентов проекта.
О проекте
Главный компонент проекта — это архетип. Архетип объединяет в себя все остальные компоненты проекта, которые при желании могут использоваться отдельно от него.
Архетип предоставляет средства для решения самых часто встречающихся задач при разработке, а именно:
- Запаковывает javascript код в maven артефакты для распространения (такие артефакты содержат помеченные пакеты специальной структуры, названные closure-packages);
- Распаковывает closure-packages из подключенных в
<dependencies>
артефактов для компиляции; - Помогает в объединении и оптимизации js и css файлов при помощи Web Resource Optimizer for Java (wro4j);
- Предоставляет 5 профилей компиляции для разных целей:
compiled
— для «боевой» сборки проекта. Уровень компиляцииADVANCED_OPTIMIZATIONS
;merged
— для склеивания всех исходных js файлов в один, фактически без компиляции. Уровень компиляцииWHITESPACE_ONLY
, форматированиеPRETTY_PRINT
;sources
— для дебага javascript файлов в бразуере. Компиляция происходит как и в профилеcompiled
, но в html будут подключены файлы с исходными кодами;sources-no-compile
— для дебага html/css файлов. Компиляции не происходит, просто в html подключаются файлы с исходными кодами;jar
— для сборки jar-архива для распространения;
- Генерирует jsdoc и jslint отчеты при выполнении
mvn site
.
С профилями
sources
и sources-no-compile
связано одно ограничение, они будут работать если в системе установлен python. Это ограничение связано с выполнением скрипта depswriter.py
, формирующим файл deps.js
, который необходим для работы Closure Library. Подробнее про depswriter здесь.Cоздание проекта
Создать проект при помощи этого архетипа очень просто, достаточно выполнить команду (вам потребуется maven версии 3):
mvn -DarchetypeRepository=http://urmuzov.github.com/maven-repository/releases/ \
-DarchetypeGroupId=com.github.urmuzov \
-DarchetypeArtifactId=closure-package-maven-archetype \
-DarchetypeVersion=1.0.2 \
-DgroupId=my.test.group \
-DartifactId=test-artifact \
-Dversion=1.0.0-SNAPSHOT \
-Dpackage=my.test.pkg \
archetype:generate
Этой командой вы скажете maven сгенерировать проект исходя из архетипа
com.github.urmuzov:closure-package-maven-archetype:1.0.2
находящегося в репозитории urmuzov.github.com/maven-repository/releases
при этом группа, артефакт и версия вашего проекта будут соответственно my.test.group
, test-artifact
и 1.0.0-SNAPSHOT
, основной пакет вашего проекта будет my.test.pkg
.Maven сгенерирует такую иерархию каталогов и файлов: (
//так обозначены мои комментарии
)~$ cd test-artifact/
~/test-artifact$ tree
.
├── pom.xml
└── src
└── main
├── python
│ └── closure-library //скрипты на python необходимые для генерации deps.js
│ ...
├── resources
│ ├── jquery-1.4.4.min.js
│ └── my
│ └── test
│ └── pkg //пакет, который вы указали при создании проекта
│ └── javascript // зарезервированная директория, из нее компилятор будет брать js файлы для компиляции, также есть зарезервированная директория externs из которой компилятор будет брать экстерны
│ ├── desktop.entry.js // точка входа в приложение
│ ├── mobile.entry.js // точка входа в приложение
│ └── sample // пакет js кода
│ └── sample.js // файл с исходным кодом
└── webapp
├── index.html // html файл для точки входа desktop.entry.js
├── META-INF
├── mobile.html // html файл для точки входа mobile.entry.js
└── WEB-INF
├── web.xml
└── wro.xml // конфигурация wro
14 directories, 19 files
Для того чтобы разобраться что здесь для чего, попробуем собрать проект.
Сборка проекта
Для того чтобы собрать проект необходимо выполнить следующую команду. Вместо
compiled
можно использовать любой из 5 профилей.~/test-artifact$ mvn -P compiled clean install
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building test-artifact 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
...
[INFO] --- closure-package-maven-plugin:1.0.2:copy (default) @ test-artifact ---
[INFO]
[INFO] --- closure-compiler-maven-plugin:1.0.2:compile (compile-advanced) @ test-artifact ---
[INFO] simplePasses: [desktop, mobile]
[INFO] == SimplePass (/home/urmuzov/test-artifact/target/closure/javascript/desktop.entry.js -> /home/urmuzov/test-artifact/target/test-artifact/desktop.js) ==
[INFO] file size: desktop.js -> 1588 bytes
[INFO] == SimplePass (/home/urmuzov/test-artifact/target/closure/javascript/mobile.entry.js -> /home/urmuzov/test-artifact/target/test-artifact/mobile.js) ==
[INFO] file size: mobile.js -> 1587 bytes
...
[INFO] --- gmaven-plugin:1.0-rc-5:execute (property-setup) @ test-artifact ---
[INFO] SimplePass[desktop]: For simple inclusion use ${desktop.entry.js} in your HTML file
[INFO] SimplePass[mobile]: For simple inclusion use ${mobile.entry.js} in your HTML file
...
[INFO] --- wro4j-maven-plugin:1.3.8:run (default) @ test-artifact ---
...
[INFO] /home/urmuzov/java/target/test-artifact/target/all.js (78601bytes) has been created!
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Большие куски логов, которые не интересны с точки зрения архетипа я убрал.
Скомпилированный проект выглядит так:
~/test-artifact$ cd target/test-artifact/
~/test-artifact/target/test-artifact$ tree
.
├── desktop.js // скомпилированная точка входа desktop.entry.js
├── index.html // html файл точки входа desktop.entry.js
├── META-INF // папка META-INF в контексте javasript приложения нам не интересна
├── mobile.html // html файл точки входа mobile.entry.js
├── mobile.js // скомпилированная точка входа mobile.entry.js
├── target
│ └── all.js // сжатая группа all из src/main/webapp/WEB-INF/wro.xml
└── WEB-INF // папка WEB-INF в контексте javasript приложения нам не интересна
Операции выполненные при сборке
В процессе сборки были выполнены следующие операции:
-
closure-package-maven-plugin
посмотрел все<dependency>
проекта в поисках closure-packages, нашел запакованную Closure Library и распаковал ее в специальную директорию для компилятора
<dependency> <groupId>com.github.urmuzov</groupId> <artifactId>closure-library-package</artifactId> <version>${closureMaven.version}</version> </dependency>
-
closure-compiler-maven-plugin
исходя из значения свойства<properties>...<passes>desktop mobile</passes>...</properties>
выполнил два «простых прохода» компиляции для файловdesktop.entry.js
иmobile.entry.js
скомпилировав их вdesktop.js
иmobile.js
. Подробнее о проходах, настройках и плагине в целом можно почитать на этой странице.
- При помощи
gmaven-plugin
были сгенерированы свойства для быстрого подключения js файлов из html файлов, в данном случае это${desktop.entry.js}
и${mobile.entry.js}
. Сразу отвечу на вопрос, «а зачем вообще нужны эти свойства?». Все дело в том, что при использовании профилейcompiled
илиmerged
необходимо подключать только один файл со скомпилированным кодом, например вот так:
<script type="text/javascript" src="desktop.js"></script>
А при использовании профилейsources
илиsources-no-compile
необходимо подключать три файла, вот так:
<script type="text/javascript" src="goog/base.js"></script> <script type="text/javascript" src="deps.js"></script> <script type="text/javascript" src="desktop.entry.js"></script>
Поэтому для того чтобы не переписывать/комментировать эти строки в html файле при смене профиля можно использовать конструкцию${output.closure.js.prefix}desktop${output.closure.js.suffix}
, которая преобразуется в нужный код для разных профилей. Для большего удобства при помощиgmaven-plugin
эта конструкция превращается в${desktop.entry.js}
, пример html файла можно посмотреть здесь.
- При помощи wro4j файл jquery-1.4.4.min.js преобразуется в all.js. Эта операция в принципе имеет мало смысла, но если файлов с библиотеками будет несколько wro может их объединить, минифицировать, а для css еще и включить в них картинки при помощи data:url.
Интеграция с IDE
В принципе все IDE имеют схожий функционал для работы с maven.
Для быстрого переключения модулей в NetBeans есть выпадающий список в тулбаре, профили в списке появляются автоматически:

В IntelliJ IDEA тоже выбирается из выпадающего списка в тулбаре:

Но добавляются вручную:

Для Eclipse, я думаю, все делается аналогично.
Дополнительная информация
В принципе этого должно быть достаточно для того чтобы разобраться в использовании этого архетипа, но если что обращайтесь ко мне или к документации, которая пока что только на русском языке:
- О проекте в целом здесь
- О плагине для компилятора здесь
- О архетипе здесь
- Примеры использования компилятора отдельно от архетипа здесь
Также возможно кому-то будет интересен этот проект с точки зрения использования всех перечисленных выше наработок в одном более сложном проекте.
Ну и как говорится, Fork me on GitHub!