Sass import from rails engine not working - ruby-on-rails

I've created a Rails Engine for assets. I don't use sprockets for css. Instead, I rely on sass's #import. This works perfectly fine in the test/dummy app, but in the Rails app that is requiring the engine, it keeps throwing
Sass::SyntaxError: File to import not found or unreadable: gumby.
I've been at this for a while, and originally the path wasn't in the load path for sass. But then I added
config.sass.load_paths << "#{Gem.loaded_specs['gumby_on_rails'].full_gem_path}/app/assets/stylesheets"
to my config/application.rb and now it definitely shows the correct path to the file I'm trying to import. It is the second to the last path listed in the following trace:
Sass::SyntaxError: File to import not found or unreadable: gumby.
Load paths:
CompassRails::SpriteImporter
CompassRails::SpriteImporter
CompassRails::SpriteImporter
CompassRails::SpriteImporter
CompassRails::SpriteImporter
CompassRails::SpriteImporter
CompassRails::SpriteImporter
CompassRails::SpriteImporter
CompassRails::SpriteImporter
/Users/brandon/code/personal/blog_update/app/assets/images
/Users/brandon/code/personal/blog_update/app/assets/javascripts
/Users/brandon/code/personal/blog_update/app/assets/stylesheets
/Users/brandon/code/personal/blog_update/vendor/assets/javascripts
/Users/brandon/code/personal/blog_update/vendor/assets/stylesheets
/Users/brandon/.rvm/gems/jruby-1.7.11#blog/gems/angularjs-rails-1.0.7/vendor/assets/javascripts
/Users/brandon/.rvm/gems/jruby-1.7.11#blog/gems/turbolinks-2.2.2/lib/assets/javascripts
/Users/brandon/.rvm/gems/jruby-1.7.11#blog/gems/jquery-rails-3.1.0/vendor/assets/javascripts
/Users/brandon/.rvm/gems/jruby-1.7.11#blog/gems/coffee-rails-4.0.1/lib/assets/javascripts
/Users/brandon/code/personal/gumby/app/assets/stylesheets
/Users/brandon/code/personal/blog_update/app/assets/stylesheets
The rails engine's tree looks like this
app/
assets/
stylesheets/
gumby/
...
gumby.css.scss
(I know that technically you should namespace all your assets in an engine, but I didn't want to have gumby/gumby, and I feel the chances of a name clash are slim.)
So in the test/dummy app I can import this file via #import 'gumby';, but this fails in the Rails app. With the above exception. How do I get this working?
And by the way, this is a Rails 4.1 app, and the answers to several other "similar" questions are all due to using groups in the Gemfile. Rails 4 got rid of groups so this is not the problem/solution.

So the solution for me was to suck it up and namespace it gumby/gumby. Then I also had to change the config/application.rb to:
config.assets.paths << "#{Gem.loaded_specs['gumby_on_rails'].full_gem_path}/app/assets/stylesheets"
And for some reason modular-scale wasn't being required properly, even though the engine already required it. So I had to change application.css.scss to application.css.scss.erb and put <% require 'modular-scale' %> at the top.

then you should write it like this :
config.sass.load_paths << "#{Gem.loaded_specs['gumby_on_rails'].full_gem_path}/app/assets/stylesheets/gumby"
or try this (untested)
#import_tree 'gumby';

Related

How to set up importmap-rails in Rails 7 engine?

I have opened an issue in the importmap-rails gem github repository here about this but thought I'd throw the question out here in case anyone might have a workaround
This is what I have discovered so far
A new engine with Rails 7 alpha 2 or Rails 7.0, generated using rails plugin new custom_page --mountable --full generates a new engine that includes the importmap-rails gem in the bundled gems but there is no ability to use it. Adding spec.add_dependency 'importmap-rails' to the enginename.gemspec makes no difference, nor does adding a require importmap-rails to engine.rb. There is no importmap executable in the bin directory.
A call to bundle info importmap-rails
Produces a promising result showing that the gem is installed by default
* importmap-rails (0.8.1)
Summary: Use ESM with importmap to manage modern JavaScript in Rails without transpiling or bundling.
Homepage: https://github.com/rails/importmap-rails
Source Code: https://github.com/rails/importmap-rails
Path: /home/jamie/.rvm/gems/ruby-3.0.0#custom_page/gems/importmap-rails-0.8.1
A call to rails --tasks shows
rails app:importmap:install # Setup Importmap for the app
But I believe this is coming from the test application generated by the --full option rather than being available to the rails command for the engine.
I was expecting to see the same without app: prefix
A call to this task resolves to a template error as shown
rails app:importmap:install
Don't know how to build task 'app:template' (See the list of available
tasks with rails --tasks) Did you mean? app:tmp:create
If there is a workaround solution to this I'd be grateful to hear it and I'm sure others will too. The reason for me wanting this is that I totally failed to introduced webpacker in a rails 6.1.4 engine and I was hoping this was going to be my, much improved, solution
You don't need to use the install task to set up importmaps. All it does is a few copy paste operations and it doesn't really help with the engine set up anyway.
Add importmaps to engine's gemspec file:
# my_engine/my_engine.gemspec
spec.add_dependency "importmap-rails"
Update engine.rb:
# my_engine/lib/my_engine/engine.rb
require "importmap-rails"
module MyEngine
class Engine < ::Rails::Engine
isolate_namespace MyEngine
initializer "my-engine.importmap", before: "importmap" do |app|
# NOTE: this will add pins from this engine to the main app
# https://github.com/rails/importmap-rails#composing-import-maps
app.config.importmap.paths << root.join("config/importmap.rb")
# NOTE: something about cache; I did not look into it.
# https://github.com/rails/importmap-rails#sweeping-the-cache-in-development-and-test
app.config.importmap.cache_sweepers << root.join("app/assets/javascripts")
end
# NOTE: add engine manifest to precompile assets in production
initializer "my-engine.assets" do |app|
app.config.assets.precompile += %w[my_engine_manifest]
end
end
end
Update assets manifest:
# my_engine/app/assets/config/my_engine_manifest.js
//= link_tree ../javascripts/my_engine .js
Add javascript entry point for our engine, if needed. Pins will be available without this file.
# my_engine/app/assets/javascripts/my_engine/application.js
// do some javascript
document.querySelector("h1").innerText = "hi, i'm your engine";
console.log("hi, again");
Update engine's layout:
# my_engine/app/views/layouts/my_engine/application.html.erb
<!DOCTYPE html>
<html>
<head>
<!--
NOTE: This loads/imports main app `application.js` and all the pins from
the main app and from the engine (because we set it up in the engine.rb).
-->
<%= javascript_importmap_tags %>
<!--
NOTE: To add engine's javascript functionality we have to load the
entrypoint here or `import` it in the main app `application.js`
-->
<%= javascript_import_module_tag "my_engine/application" %>
</head>
<body> <%= yield %> </body>
</html>
Create importmap.rb and pin my_engine/application, this name has to match with javascript_import_module_tag. It cannot clash with any other name in the main app, so you can't just use application:
# my_engine/config/importmap.rb
# NOTE: this pin works because `my_engine/app/assets/javascripts
# is in the `Rails.application.config.assets.paths`
pin "my_engine/application"
Some extras to test the setup:
# config/routes.rb
Rails.application.routes.draw do
mount MyEngine::Engine => "/"
end
# my_engine/config/routes.rb
MyEngine::Engine.routes.draw do
get "home", to: "homes#index"
end
# my_engine/app/controllers/my_engine/homes_controller.rb
module MyEngine
class HomesController < ApplicationController
def index; end
end
end
# my_engine/app/views/my_engine/homes/index.html.erb
<h1>Home</h1>
At this point you should have this in your rendered layout's <head> tag, among other things:
<script type="importmap" data-turbo-track="reload">{
"imports": {
"application": "/assets/application-66ce7505c61e3e4910ff16e7c220e1fbfb39251cd82e4bab8d325b3aae987cf9.js",
"my_engine/application": "/assets/my_engine/application-31ce493e8376b4c20703a50f38d419ae309ffe410b7ab7fec47440e02eef08a8.js",
}
}</script>
<script type="module">import "application"</script>
<script type="module">import "my_engine/application"</script>
H1 tag should change to <h1>hi, i'm your engine</h1> on reload.
Additional importmaps can be added manually with https://generator.jspm.io/.
For bonus points, bin/importmap can be customized to work inside the engine. Create a new importmap file inside bin directory.
# my_engine/bin/importmap
#!/usr/bin/env ruby
# NOTE: don't forget to `chmod u+x bin/importmap` to make it executable.
# make sure we are loading the correct versions of things
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
# NOTE: importmap requires some rails goodness that we don't have in the engine,
# because we don't have `config/application.rb` that loads the environment.
require "rails"
# importmap-rails is not loaded automatically
require "importmap-rails"
# the actual command runner
require "importmap/commands"
Run from inside the engine directory:
$ bin/importmap pin react
Pinning "react" to https://ga.jspm.io/npm:react#18.1.0/index.js
$ cat config/importmap.rb
pin "my_engine/application"
pin "react", to: "https://ga.jspm.io/npm:react#18.1.0/index.js"
I haven't tested it too much, so any feedback would be welcome. Restart the server if something doesn't show up, I don't know how reloading behaves with all this.
I fall back to the old school Javascript include in the html.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.js"></script>
Well it definitely works on all browser instead of figuring out if the browser supports the feature that I might use later.
I have full control which page to put too... but that might not be what you want...

How to import images using webpacker in rails 6

I am trying to use jquery.datatables using webpacker in rails 6. I have
#app/javascript/packs/application.js
...
require("datatables.net")
require("datatables.net-dt")
...
Then I have
#app/javascript/packs/
#import '../stylesheets/datatables.scss';
and then
#app/javascript/stylesheets/datatables.scss
#import 'datatables.net-dt/css/jquery.dataTables';
but the webpacker-dev-server gives following error
Module not found: Error: Can't resolve '../images/sort_asc.png' in '/Users/app/javascript/packs'
resolve '../images/sort_asc.png' in '/Users/app/javascript/packs'
using description file: /Users/app/package.json (relative path: ./app/javascript/packs)
Field 'browser' doesn't contain a valid alias configuration
using description file: /Users/app/package.json (relative path: ./app/javascript/images/sort_asc.png)
no extension
The directory structure for datatables.net-dt is as follows
datatables.net-dt
css
images
js
and there are five png images in images folder. Presumably they are background images for the css. How do I load these images, ideally without having to name each one?

How can I configure Compass and Zurb Foundation 5 in my Rails 4 app so that they are both accessible in the same directory?

I have a Rails 4 app in which I am using Compass and Zurb Foundation 5. I would like to use both Compass and Foundation 5 with a Rails 4 app.
More specifically, I want to be able to do this in a stylesheet.scss file:
#import "compass";
#import "foundation_and_overrides";
[additional imports]
In other words, I want to be able to have all my sass files in the same directory. However, currently, Foundation scss files lives in 'app/assets/stylesheets' because it appears that the Foundation file 'foundation_and_overrides.scss' needs to live in this directory. At the same time, I have all my other sass files in a '/sass' directory, which then are compiled to 'app/assets/stylesheets'
How can I configure Compass and/or Foundation so that they are all accessible from the same directory?
It seems it is just a question of knowing the correct path to use for my import.
As per this stackoverflow post I attempted the following:
#import 'foundation/foundation-global';
#import 'foundation/components/type';
However, then I get the following compass error:
error sass/stylesheet.scss (Line 2: File to import not found or unreadable: foundation/foundation.
Load paths:
/Users/Anders/Dropbox/WWW/sbox-project/research/foundation-test/sass
/Users/Anders/.rvm/gems/ruby-2.0.0-p247/gems/compass-0.12.4/frameworks/blueprint/stylesheets
/Users/Anders/.rvm/gems/ruby-2.0.0-p247/gems/compass-0.12.4/frameworks/compass/stylesheets
Compass::SpriteImporter)
Gem versions in use:
compass (0.12.4)
compass-rails (1.1.7)
foundation-rails (5.2.1.0)
Compass config file (compass.rb)
project_type = :rails
http_path = "/"
css_dir = "app/assets/stylesheets"
sass_dir = "sass"
images_dir = "app/assets/images"
javascripts_dir = "app/assets/javascripts"
Any advice would be appreciated! Also, please let me know what additional information I should provide to offer advice on this. Thanks!
in compass.rb
sass_dir = 'app/assets/stylesheets'
it's also better to have compiled css files in the 'public' folder.
css_dir = 'public/stylesheets'
images_dir = 'public/images'
javascripts_dir = 'public/javascripts'
fonts_dir = 'public/fonts'
then init compass :
compass init
or if using bundler :
bundle exec compass init
your config/compass.rb changes will then be applied to config.rb

jekyll not generating posts

I am using the bloggy gem to put a jekyll blog within my current rails app. Basically, you have a normal jekyll build but then you put your files in the config/jekyll directory and generate files into the public/blog directory.
However, when I run jekyll build, none of my posts are generated.
Here is the config file:
markdown: rdiscount
permalink: /:title.html
destination: ../../public/blog
exclude:
- Rakefile
- Gemfile
- .gitignore
Here is my directory structure within config/jekyll
./_config.yml
./_layouts
./_layouts/default.html
./_layouts/page.html
./_layouts/post.html
./_posts
./_posts/2013-06-07-dear-nsa.md
./_posts/2013-06-07-wut.markdown
./atom.xml
./css
./css/screen.css
./css/syntax.css
./index.html
And here is the generated directory structure with public/blog
./atom.xml
./css
./css/screen.css
./css/syntax.css
./index.html
A clue I've come up with: if I specify the source as the _posts, it will generate html versions of my posts into public/blog... but will not include the css or index page.

Error compiling CSS asset (Compass + Sass + Heroku)

I have a site running on Heroku using Compass with Saas an is working fine (compiling assets when pushing to Heroku seems to be fine).
I added a new folder inside assets to namespace other styling, like this
/app/assets/stylesheets/site/site1.css
/app/assets/stylesheets/site/site2.css
/app/assets/stylesheets/site/common/base.css.saas
/app/assets/stylesheets/site/site/site1.css.saas
/app/assets/stylesheets/site/site/site2.css.saas
...
The problem is when I visit a page that use site1.css styling I get the following error
Error compiling CSS asset
Sass::SyntaxError: File to import not found or unreadable: ../compass/css3/text-shadow.
Load path: /app
(in /app/app/assets/stylesheets/site/common/base.css.sass)
/app/app/assets/stylesheets/site/common/base.css.sass)
The line that the error refers is this
/app/assets/stylesheets/site/common/base.css.sass
#import "../compass/css3/text-shadow"
I tried both "../compass/css3/text-shadow" and "compass/css3/text-shadow". In both cases I got the same error.
Any idea how to solve this?
Solved.
I needed to specify on production.rb file the additional files to compile
config.assets.precompile +=
Dir["#{Rails.root}/app/assets/stylesheets/site/site/*.*"].collect {|s| "site/" + File.basename(s).gsub(/.scss|.sass/, '') }
Now is working fine.

Resources