为多宿主Rails应用程序预编译资产

时间:2015-02-15 15:06:00

标签: ruby-on-rails asset-pipeline sprockets

我有一个多宿主的Rails 3.2应用程序,其中每个" home"有自己的皮肤。这些资产是使用自定义Rake任务预编译的:

require "fileutils"

namespace :assets do
  namespace :precompile do
    task :homes, [:short_name] => ["assets:environment"] do |t, args|
      include Sprockets::Helpers::RailsHelper
      homes = args.short_name ? home.where(:short_name => args.short_name) : home.all
      homes.each do |home|
        appenv = Rails.application.assets
        appenv.clear_paths
        paths = [
          "app/assets/homes/#{home.short_name}/images",
          "app/assets/homes/#{home.short_name}/stylesheets",
          "app/assets/homes/#{home.short_name}/javascripts"
        ]
        paths.each{|x| appenv.append_path x}

        config = Rails.application.config
        config.assets.prefix = home.short_name
        config.assets.digest = true
        config.assets.debug = false
        config.assets.compress = true
        target = File.join(Rails.public_path, config.assets.prefix)

        puts "Compiling assets for #{home.name} into #{target}"
        Sprockets::StaticCompiler.new(appenv, target, ["*"], digest: true, manifest: true).compile
        Sprockets::StaticCompiler.new(appenv, target, ["*"], digest: false, manifest: true).compile
      end
    end
  end
end

这个Rake任务需要一个可选的" home"参数,并且只会编译那个" home"如果提供 - 如果没有它循环通过所有"家庭"并为每一个编译资产:

rake assets precompile:homes[my_home]

rake assets precompile:homes

在我的ApplicationController中,我动态设置资产路径:

MyApp::Application.config.assets.prefix = @home.short_name
MyApp::Application.config.assets.digests = YAML.load_file(File.join(Rails.public_path, @home.short_name, "manifest.yml"))

这非常有效 - 只要我在开发环境中运行Rake任务 - 但是在生产中运行时,我在appenv.clear_paths上尝试修改环境时出错:

$ rake assets precompile:homes RAILS_ENV=production

TypeError: can't modify immutable index
/var/rails/MyApp/vendor/ruby/1.9.1/gems/sprockets-2.2.3/lib/sprockets/index.rb:80:in `expire_index!'
/var/rails/MyApp/vendor/ruby/1.9.1/gems/sprockets-2.2.3/lib/sprockets/trail.rb:49:in `clear_paths'
/var/rails/MyApp/lib/tasks/assets.rake:10:in `block (4 levels) in <top (required)>

我理解这是因为Sprockets使用不同的对象来表示生产中的appenv,在开发中这是完整的环境(Sprockets :: Environment),而在生产中它是一个简化和受限的子集(Sprockets :: Index) )这是只读的。但是这导致了一个问题22:为了能够在我需要在开发中运行它的任务中动态设置资产路径,但是为了压缩和缩小资产,并使摘要工作,我有在生产中运行它。正如你所看到的,我试图在开发过程中强制它压缩并生成摘要,但这似乎没有效果:

    config.assets.digest = true
    config.assets.debug = false
    config.assets.compress = true

我一直试图找到一个解决方案,但是现在已经找不到任何有效的方法了 - 没有一个严重的感冒和一般感觉有点疲惫的帮助:(在我看来,这应该是一个相当普遍的情况,所以我希望这里有人知道该怎么做......

1 个答案:

答案 0 :(得分:0)

我很欣赏Rails 3.2有点过时了,Rails 5 having been announced以及所有这些,但直到有人捐出一个月的空闲时间(联系我了解详情)我和#39;我必须保持这个东西运行。幸运的是,一旦我的感冒消失了,解决我遇到的问题并不是太难 - 这就是固定的Rake任务的样子:

require "fileutils"

namespace :assets do
  namespace :precompile do
    task :homes, [:short_name] => ["assets:environment"] do |t, args|
      include Sprockets::Helpers::RailsHelper
      homes = args.short_name ? home.where(:short_name => args.short_name) : home.all
      homes.each do |home|
        appenv = Rails.application.assets
        appenv.clear_paths
        paths = [
          "app/assets/homes/#{home.short_name}/images",
          "app/assets/homes/#{home.short_name}/stylesheets",
          "app/assets/homes/#{home.short_name}/javascripts"
        ]
        paths.each{|x| appenv.append_path x}

        config = Rails.application.config
        config.assets.prefix = home.short_name
        config.assets.digest = true
        target = File.join(Rails.public_path, config.assets.prefix)

        puts "Compiling assets for #{home.name} into #{target}"
        Sprockets::StaticCompiler.new(appenv, target, ["*"], digest: false, manifest: false).compile
        Sprockets::StaticCompiler.new(appenv, target, ["*"], digest: true, manifest: true).compile
      end
    end
  end
end

这与我之前的几种方式不同:

  • 在运行编辑之前,不再在debug上设置compressRails.application.assets选项,因为这些选项显然没有效果。
  • 已经切换了摘要/非摘要资产的编译顺序,因此在非摘要资产之后创建摘要资产。

第二个更改解决了丢失的摘要问题,并且environments/development.rb资产中的以下内容被缩小,CSS文件不再包含SASS行号注释:

config.assets.debug = false
config.assets.compress = true

所以它完全按照我想要的方式工作,只要它在开发环境中运行,这很好 - 问题已解决

编辑:所以,我注意到SCSS文件中的资产引用没有给出摘要文件名,一些进一步的测试显示config.assets.digest = true 需要毕竟是设定的。上面的代码已更新以反映这一点。当actionpack / lib / sprockets / helpers / rails_helper.rb检查digest_assets

时,if digest_assets && options[:digest] != false为false