Rails - How to pass Sprockets::Context in manual sass compiling

╄→гoц情女王★ 提交于 2019-12-07 08:53:36

问题


I'm using the following code snippet to manually compile a sass manifest with some variable overrides appended.

template = File.read("#{Rails.root}/app/assets/schemes/#{scheme}/css/styles.css.scss")

scheme_variables.each do |key, value|
  template << "$#{key}:#{value};\n"
end

engine = Sass::Engine.new(template, { 
  :syntax => :scss,
  :cache => false,
  :read_cache => false,
  :style => :compressed,
  :filesystem_importer => Sass::Rails::SassImporter,
  :load_paths => MyApp::Application.assets.paths,
  :sprockets => {
    :context => ?,
    :environment => MyApp::Application.assets
  }
})
output = engine.render

The Sass::Engine constructor wants a sprockets context and environment in the options hash. What do I put in for the context? The first thing I tried was...

:context => MyApp::Application.assets.context_class,

...but that gives me the following error "undefined method `font_path' for #" when it hits one of my sass asset helpers.

The second thing I tried was...

:context => ActionController::Base.helpers,

...That fixed the asset helper issue, but throws the following error "undefined method `depend_on' for #" when it tries to work through my glob imports (e.g. @import "mixins/*").

I'm using Rails 4.2 and sass-rails 5.0.3.

Any advice on this would be much appreciated. Thanks!


回答1:


With using Sass::Rails::ScssTemplate you can render your sass code with this snippet:

template = '...' # Your sass code

logical_path = pathname = ''
environment = Rails.application.assets
context = environment.context_class.new(environment, logical_path, pathname)

template = Sass::Rails::ScssTemplate.new(pathname) { template }
output = template.render(context, {})

If you want to render from a file then just add its path to pathname and its asset path to logical_path.

For me it works with Rails 4.2.5.1 and sass-rails 5.0.4.




回答2:


I ended up solving this in a slightly different way - using Sass::Rails::ScssTemplate's render method. Basically, I write my altered css string out to a file and pass it into the Sass::Rails::ScssTemplate constructor. I then compile and remove the temp file when it's done. This doesn't feel great, but it's working well for me.

scheme_css_dir = "#{Rails.root}/app/assets/schemes/#{scheme}/css"
css = File.read("#{scheme_css_dir}/styles.css.scss")

variables_str = ''
scheme_variables.each do |key, value|
  variables_str << "$#{key}:#{value};\n"
end

css.gsub!('@import "./variables";', variables_str)

file = Tempfile.new(['styles', '.css.scss'], scheme_css_dir)
file.write(css)
file.close

abs_path = file.path
relative_path = abs_path[Rails.root.to_s.size + 1..-1]

template = Sass::Rails::ScssTemplate.new(abs_path)
environment = Evrconnect::Application.assets
context = environment.context_class.new(
  :environment => environment,
  :name => relative_path,
  :filename => abs_path,
  :metadata => {}
)
output = template.render(context)

file.unlink



回答3:


To answer your original question, you need to supply either the current view_context, or create one with ActionView::Base.new.

http://apidock.com/rails/AbstractController/Rendering/view_context




回答4:


In Rails 5.x, Sprockets v3.7.x

NOTE: Following method requires: Rails.application.config.assets.compile == true, i.e., set config.assets.compile = true. Check Sprockets README

I manually returned compiled source for sass/js, using the following code.

# For Scss Assets
def pdf_stylesheet_link_tag(name)
  if Rails.env.development?
    asset = Rails.application.assets.find_asset(name + '.scss')
    raw ('<style type="text/css">' + asset.source + '</style>')
  else
    raw ('<style type="text/css">' + pdf_asset_contents(name, '.css') + '</style>')
  end
end

# For Javascript Assets
def pdf_javascript_include_tag(name, *type)
  if Rails.env.development?
    if debug? # Can be used to check `debug == true` in params for current route
      javascript_include_tag(name)
    else
      asset = Rails.application.assets.find_asset(name + '.js')
      raw ('<script>' + asset.source + '</script>')
    end
  else
    javascript_tag pdf_asset_contents(name, '.js')
  end
end

Above code actually helps to dynamically pass compiled version of sass/js to Wicked_PDF, which actually helps to load styles and js on Generated PDFs, for Dev Environments.

pdf_stylesheet_link_tag can be used as a helper for templates, in development/stage (where, config.assets.precompile == false), instead of using wicked_pdf_stylesheet_link_tag(which actually requires a path to precompiled source-file).




回答5:


After overnight trial and errors, I found and want to share todays's way of doing it ("today" meaning: rails 5.2.1 and sprockets 3.7.2).

Work as expected: no need of a temp file, accept @import, allow asset path helpers.

# Compile SASS and return the resulting string
# Pass the file path and name without 'sass' extension, relative to assets/stylesheets
def compile_sass(stylesheet) 
  # Load file content
  path = Rails.root.join 'app', 'assets', 'stylesheets', "#{stylesheet}.sass"
  sass = File.read path

  # Configure engine
  environment = Sprockets::Railtie.build_environment Rails.application
  scope = environment.context_class.new environment: environment, \
    filename: "/", metadata: {}
  scope.sass_config.merge! cache: false, style: :compressed

  # Compile
  engine = Sass::Rails::SassTemplate.new {sass}
  engine.render scope
end

Other sass_config options can be found here : https://github.com/sass/ruby-sass/blob/stable/doc-src/SASS_REFERENCE.md#options




回答6:


The following works with rails 5.2.0, sprockets 3.7.2, sassc-rails 1.3.0 and sassc 1.12.1:

 template = '...' # Your sass code

 environment = Sprockets::Railtie.build_environment(Rails.application)
 engine = SassC::Rails::SassTemplate.new

 engine.call(environment: environment,
             filename: '/', 
             data: template, 
             metadata: {})[:data]


来源:https://stackoverflow.com/questions/30376024/rails-how-to-pass-sprocketscontext-in-manual-sass-compiling

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!