问题
I have an existing rails
application where I am working on a separate branch to implement yarn
for managing my vendor assets. My app stack is:
- ruby-2.4.0
- rails 5.1.4
- node 9.4.0
- yarn 1.3.2
After installing yarn, I ran yarn init
and it generated a package.json in the project root. After a few packages added, it looks like:
# package.json
{
"name": "my-project-name",
"version": "1.0.0",
"private": true,
"repository": "my-repo",
"author": "me",
"license": "MIT",
"dependencies": {
"bootstrap": "3",
"font-awesome": "^4.7.0",
"jquery": "^3.3.1",
"jquery-backstretch": "^2.1.16",
"jquery-ujs": "^1.2.2",
"waypoints": "^4.0.1"
}
}
I created under app/assets a couple of files for including stylesheets and javascripts from node_modules
:
# app/assets/javascripts/node_modules.js
//= require jquery
//= require jquery-ujs
//= require bootstrap/dist/js/bootstrap.min.js
//= require waypoints
//= require jquery-backstretch
# app/assets/stylesheets/font_path_overwrite.scss
$fa-font-path: "font-awesome/fonts/";
# app/assets/stylesheets/node_modules.css.scss
/*
*= require bootstrap/dist/css/bootstrap.min.css
*= require font_path_overwrite
*= require font-awesome/scss/font-awesome
*/
I also changed:
# config/initializers/assets.rb
# ...
Rails.application.config.assets.paths << Rails.root.join('node_modules')
Rails.application.config.assets.precompile += %w(*.js *.scss)
Rails.application.config.assets.precompile += %w(*.png *.woff2 *.woff *.ttf *.eot *.jpg *.gif *.svg *.ico)
# Rakefile
# ...
Rake::Task['assets:precompile'].enhance [:js_deps_install]
task :js_deps_install do
sh 'yarn install'
end
As per SO-43170792, I added a new
heroku buildpacks:set heroku/ruby
heroku buildpacks:add --index 1 heroku/nodejs
In my staging environment I deployed these changes and I suddenly realized that something strange is happening with my assets precompilation node_modules/
folder: whilst everything seems to work fine for js and css files, I am having some issues with fonts (especially font-awesome's fonts).
Debugging in the network inspector the file assets/font-awesome/fonts/fontawesome-webfont.ttf?v=4.7.0
is not found since it was precompiled and not just copied into:
public/assets/font-awesome/fonts/fontawesome-webfont-[hash].ttf
I understand why I am facing this situation (which is very similar to this unaswered question from two months ago).
I am looking for a clean solution or smart workaround (e.g. create a middleware to redirect the plain .ttf
request to the rails complaint hashed version and cache the answer for x hours. Would you have any suggestion?
回答1:
I guess I found the cleanest solution after a few attempts:
Attempt 1: Sass and overwrite fonts directories
I did a pretty extensive refactoring of sass modules in app/assets/stylesheets
directory. Here a couple of examples:
For fonts
// sass_font_awesome.scss
$fa-font-path: "font-awesome/fonts";
@import 'font-awesome/scss/font-awesome';
@font-face {
font-family: 'FontAwesome';
src: asset-url('#{$fa-font-path}/fontawesome-webfont.eot');
src: asset-url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix') format('embedded-opentype'),
asset-url('#{$fa-font-path}/fontawesome-webfont.woff2') format('woff2'),
asset-url('#{$fa-font-path}/fontawesome-webfont.woff') format('woff'),
asset-url('#{$fa-font-path}/fontawesome-webfont.ttf') format('truetype'),
asset-url('#{$fa-font-path}/fontawesome-webfont.svg?#fontawesomeregular') format('svg');
font-weight: normal;
font-style: normal;
}
For images
// sass_multiselect.scss
$ms-img-path: 'multiselect/js/img';
@import 'multiselect/css/multi-select';
.ms-container{
background: transparent asset-url('#{$ms-img-path}/switch.png') no-repeat 50% 50%;
width: 370px;
}
This approach was still breaking when node_modules folder was precompiled. Actually all the node cli scripts had some issues in terms of syntax for Ugflifier.
Attempt 2: Install Webpack and create a app/javascripts/pack/application.sass
@import '~font-awesome/scss/font-awesome'
@import '~multiselect/css/multi-select'
I was still facing some issues with relative paths. I found the solution in webpacker documentation adding to my config/webpacker/environment.js
the following loader:
// webpack/environment.js
const { environment } = require('@rails/webpacker')
// resolve-url-loader must be used before sass-loader
environment.loaders.get('sass').use.splice(-1, 0, {
loader: 'resolve-url-loader',
options: {
attempts: 1
}
});
Solution: the easiest way
I finally found out the default behaviour of webpacker gem and it was very easy:
// app/javascripts/packs/styles.js
import 'font-awesome/scss/font-awesome.scss';
import 'multiselect/css/multi-select.css';
This compile to a bundled styles.css without needing any additional loader.
It took me quite a lot time to figure it out and I hope it will be helpful to you too!
回答2:
I made it work by overriding font paths.
application.scss:
$fa-font-path:"font-awesome/fonts";
@import 'font-awesome/scss/font-awesome';
@font-face {
font-family: 'FontAwesome';
src: font-url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}');
src: font-url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),
font-url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'),
font-url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
font-url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
font-url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
// src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
font-weight: normal;
font-style: normal;
}
Run rake assets:precompile
and you should see font files in public/assets/font-awesome/fonts
with digested file names.
Compiled CSS should access font files from Rails assets:
@font-face{
font-family:'FontAwesome';
src:url(/assets/font-awesome/fonts/fontawesome-webfont-7bfcab6db99...979.eot?v=4.7.0)
来源:https://stackoverflow.com/questions/48572272/rails-asset-pipeline-working-with-fonts-and-yarn