На блоге уже был обзор RequireJs, как загрузчика модулей, теперь разберем еще одну его возможность – компоновку/сборку проекта – RequireJS Optimizer.
Что умеет делать делать RequireJS Optimizer?
- оптимизировать JavaScript файлы: компоновать и минифицировать( по умолчанию UglifyJS )
- оптимизировать CSS файлы
Возможны варианты запуска: Node.js(желательно), Rhino.
Установка на ноду:
$ npm install requirejs
Проверим работоспособность:
$ r.js -v r.js: 2.1.1, RequireJS: 2.1.1
Теперь проделаем все по примеру с офсайта. Создаем следующую структуру проекта:
- appdirectory
- main.html
- css
- common.css
- main.css
- scripts
- require.js
- main.js
- one.js
- two.js
- three.js
- r.js
Для тех, кому лень создавать эти все файлы, вот готовая структура.
Переходим в директорию appdirectory/scripts и выполняем команду:
$ node ../../r.js -o name=main out=main-built.js baseUrl=.
либо если r.js установлен глобальной командой, то можно так:
$ r.js -o name=main out=main-built.js baseUrl=.
"-o" - основная команда, которой запускается оптимизатор "name=" - параметр для главного исходного файла(без расширения .js) "out=" - исходящий файл
И в итоге оптимизатор должен выдать собранный и оптимизированный код проекта в файл main-built.js.
Если мы хотим require.js тоже строить в наш билд-файл, тогда добавим 2 опции:
$ r.js -o baseUrl=. paths.requireLib=require name=main include=requireLib out=main-built.js
– в которых сделаем подключение модуля(include) и скажем где его брать(path).
Если мы хотим исключить какой-то файл из сборки(например: чтобы отдельно его подключить для отладки), то мы должны использовать опцию excludeShallow:
$ r.js -o name=main excludeShallow=two out=main-built.js baseUrl=.
и указать ей файл, который мы хотим исключить. В данном случае это two.js.
Также можно сказать r.js чтобы собрал файлы, но не оптимизировал их, для этого выставляем опцию optimize=none:
$ r.js -o name=main optimize=none out=main-built.js baseUrl=.
Для скриптов, которые хотим грузить используя CDN либо с других сторонних доменов, необходимо задать в path ключевое слово “empty:“(чтобы r.js не пытался их подгрузить):
$ r.js -o name=main out=main-built.js baseUrl=. paths.jquery=empty:
но, понятное дело, в коде останется полный путь:
requirejs.config({ paths: { 'jquery': 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min' } });
Для сжатия CSS файлов используем следующую команду:
$ r.js -o cssIn=main.css out=main-built.css
Ну и чтобы совсем уже все было здорово можно записать все команды в один файл конфигурации, а потом просто вызвать его:
$ r.js -o build.js
Вот так вот выглядит минимальный файл конфигурации:
({ baseUrl: "appdirectory/scripts/", name: "main", out: "main-built.js", })
Внимание! Именно так: обрамленный круглыми скобками JSON формат, а в конце нет точки с запятой.
Если мы хотим оптимизировать весь проект: файл за файлом, то делаем так:
({ appDir: "appdirectory/", baseUrl: "scripts", dir: "./build", modules: [ { name: "main" } ] })
В итоге мы получим структуру аналогичную нашему проекту, только с оптимизированными файлами. Тут также нужно не забыть создать отдельную директорию (в нашем случае это ./build ), чтобы не перетереть текущий проект. (Так что по запросу “А-а-а! RequireJs стер мой проект!” сюда)
appDir - директория приложения baseUrl - путь к скриптам от appDir dir - директория где будут созданы оптимизированные варианты
Есть еще один вариант запуска оптимизатора – через модуль requirejs в node.js. Это нам позволит сделать следующий код:
var requirejs = require("requirejs"); var config = { appDir: "appdirectory/", baseUrl: "scripts", dir: "./build", modules: [ { name: "main" } ] }; requirejs.optimize( config, function(results) { console.log(results); });
и теперь выполним его напрямую на ноде(без r.js):
node build.js
И на закуску две интересные опции конфига – onBuildRead и onBuildWrite – callback-метода, которые будут вызваны, когда оптимизатор прочитает/запишет файл, пример:
... onBuildRead: function (moduleName, path, contents) { return contents.replace(/foo/g, 'bar'); }, onBuildWrite: function (moduleName, path, contents) { return contents.replace(/bar/g, 'foo'); }, ...
Вот тут можно найти полный и подробно комментированный(на английском) пример конфигурационного файла для RequireJs Optimizer.
UPD: различие между опциями exclude и excludeShallow:
exclude – исключает всю ветку зависимостей за исключаемым файлом(т.е. если файл 1 внутри себя еще содержал зависимость от файлов 2 и 3, то все файлы будут исключены)
excludeShallow – исключает только сам файл, оставляя при этом все файлы зависимостей