У многих веб разработчиков рано или поздно встает вопрос об ускорении загрузки своих сайтов. Это связано с тем, что не у всех есть мегабитные каналы, и некоторые пользователи все еще сидят на dialup. В данной статье я опишу как сжимать яваскрипты дла production, объединять их в один файл, так же дальнейшие улучшения. Предположим у нас есть набор скриптов: swfobject.js, jquery-1.3.2.js, jquery.media.js, jquery.markitup.js, jquery.markitup.set.js, application.js. Их размер порядка 150 КБ, упаковщик позволит сжать их до 50 КБ.
Раньше я пользовался asset_packager, но его возможности скромны, он просто удаляет комментарии, лишние пробелы и переносы строк в файлах яваскриптов и css. Поэтому я стал искать другой способ. Предлагаю вам свое решение.
Добавляем в файл config/environment.rb строчку
и выполняем sudo rake gems:install
Создадим config/js_files.yml, имеющий содержание обычного ямл файла:
Чтобы полчить список файлов, создадим файл initializers/javascript_files.rb
Из этого кода видно что пути для яваскриптов в продакшне изменяются на подпапку «packed».
:cache, когда установлено config.action_controller.perform_caching = true будет выдавать нам один файл base_packed.js, содержанием которого будут все файлы перечисленные в :base.
Создаем файл lib/tasks/packr.rake
Сразу несколько слов об этом коде, тут в данном случае будут запакованы только файлы с ключем «base» и сложены в папку «javascripts/packed», к этом я вернусь в конце статьи.
Итак, все готово к упаковке. Но перед этим надо создать папку «javascripts/packed», иначе получите ошибку.
Чтобы запустить упаковщик выполните команду rake packr:pack. Упакованные файлы вы найдете в созданной заренее «javascripts/packed».
В скриптах указана папка для упакованных файлов, задана она в каждом скрипте. Для универсальности следует вынести ее в константу.
В таске запаковываются файлы только из ключа :base, здесь следует убрать этот параметр из строчки
Файлы исходников яваскриптов находятся по прежнему в папе «public/javascripts», нужно переместить их, например, в «lib/javascripts», т.к. в продакшне они там ни к чему. В девелопменте можно просто делать ссылку из lib в public. В продакшне в «public/javascripts» складывать запакованные файлы, и папка «packed» будет не нужна. При этом упростится и скрипт initializers/javascript_files.rb, т.к. не нужно будет делить файлы на продакшн и девелопмент.
Файлы надо упаковывать на сервере, перед перезапуском сервера. Если вы используете capistrano то можно делать, например, следующим образом:
Предложения и замечания приветствуются.
Спасибо за внимание!
Раньше я пользовался asset_packager, но его возможности скромны, он просто удаляет комментарии, лишние пробелы и переносы строк в файлах яваскриптов и css. Поэтому я стал искать другой способ. Предлагаю вам свое решение.
Установка гема packr
Добавляем в файл config/environment.rb строчку
config.gem 'packr', :lib => false
и выполняем sudo rake gems:install
Создание списка файлов скриптов
Создадим config/js_files.yml, имеющий содержание обычного ямл файла:
base:
- swfobject.js
- jquery-1.3.2.js
- jquery.media.js
- jquery.markitup.js
- jquery.markitup.set.js
- application.js
Инициализация файлов
Чтобы полчить список файлов, создадим файл initializers/javascript_files.rb
JAVASCRIPT_FILES = YAML::load( File.read("#{RAILS_ROOT}/config/js_files.yml") ).symbolize_keys
if RAILS_ENV == "production"
JAVASCRIPT_FILES_PACKED = Proc.new{prod_files = {} ; JAVASCRIPT_FILES.each { |key , value| prod_files[key] = value.map{|v| "packed/" + v} } ; prod_files }.call
ActionView::Helpers::AssetTagHelper.register_javascript_expansion JAVASCRIPT_FILES_PACKED
else
ActionView::Helpers::AssetTagHelper.register_javascript_expansion JAVASCRIPT_FILES
end
Из этого кода видно что пути для яваскриптов в продакшне изменяются на подпапку «packed».
ActionView::Helpers::AssetTagHelper.register_javascript_expansion JAVASCRIPT_FILES— позволит подключать хелпером javascript_include_tag несколько файлов по ключам которые указаны в js_files.yml.
Добавление яваскриптов в шаблон
javascript_include_tag :base, :cache => "base_packed"
:cache, когда установлено config.action_controller.perform_caching = true будет выдавать нам один файл base_packed.js, содержанием которого будут все файлы перечисленные в :base.
Task для упаковки
Создаем файл lib/tasks/packr.rake
require 'packr'
namespace :packr do
task :pack do
files = YAML::load( File.read("#{RAILS_ROOT}/config/js_files.yml") )["base"]
files.each do |file|
puts "#{file} packing..."
File.open("#{RAILS_ROOT}/public/javascripts/packed/#{file}", 'wb') do |f|
f.write(Packr.pack(File.read("#{RAILS_ROOT}/public/javascripts/#{file}"), :shrink_vars => true, :private => true, :base62 => true))
end
puts "packed\n\n"
end
end
end
Сразу несколько слов об этом коде, тут в данном случае будут запакованы только файлы с ключем «base» и сложены в папку «javascripts/packed», к этом я вернусь в конце статьи.
Итак, все готово к упаковке. Но перед этим надо создать папку «javascripts/packed», иначе получите ошибку.
Чтобы запустить упаковщик выполните команду rake packr:pack. Упакованные файлы вы найдете в созданной заренее «javascripts/packed».
Дальнейшие улучшения
Первое:
В скриптах указана папка для упакованных файлов, задана она в каждом скрипте. Для универсальности следует вынести ее в константу.
Второе:
В таске запаковываются файлы только из ключа :base, здесь следует убрать этот параметр из строчки
files = YAML::load( File.read("#{RAILS_ROOT}/config/js_files.yml") )["base"]и сделать проходы по всем ключам. При необходимости добавить параметр какой именно ключ необходимо паковать.
Третье:
Файлы исходников яваскриптов находятся по прежнему в папе «public/javascripts», нужно переместить их, например, в «lib/javascripts», т.к. в продакшне они там ни к чему. В девелопменте можно просто делать ссылку из lib в public. В продакшне в «public/javascripts» складывать запакованные файлы, и папка «packed» будет не нужна. При этом упростится и скрипт initializers/javascript_files.rb, т.к. не нужно будет делить файлы на продакшн и девелопмент.
Четвертое:
Файлы надо упаковывать на сервере, перед перезапуском сервера. Если вы используете capistrano то можно делать, например, следующим образом:
task :before_symlink do
run "mkdir -p #{release_path}/public/javascripts"
run "rake packr:pack"
end
Предложения и замечания приветствуются.
Спасибо за внимание!