Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Font Awesome 5 takes a long time to compile with webpacker #12596

Closed
sunnyrjuneja opened this issue Mar 14, 2018 · 14 comments
Closed

Font Awesome 5 takes a long time to compile with webpacker #12596

sunnyrjuneja opened this issue Mar 14, 2018 · 14 comments

Comments

@sunnyrjuneja
Copy link

Hi,

I'm a FontAwesome Pro customer and wanted to use Font Awesome in my Ruby on Rails project. No gem was released so I started using webpacker (rails feature to integrate webpack). Font Awesome Pro takes over 6 minutes to compile on Heroku with webpacker. I was able to replicate the same problem with Font Awesome Free (over 2 minutes).

Is it surprising to the maintainers that compiling with webpack takes so long? Here is my reproduction and issue filed with Webpacker. rails/webpacker#1347

@tagliala
Copy link
Member

tagliala commented Mar 14, 2018

Hi!

Thanks for being part of the Font Awesome Community.

I'm a RoR developer and I use Heroku ✋

I've done an experiment with webpacker, Rails 5.2 and FA: https://github.com/diowa/ruby2-rails5-bootstrap-heroku

Using the configuration you can see in the above repo (pretty standard), this is my compile time:

remote:        Asset precompilation completed (52.32s)

Compile time without font awesome (branch without-fa)

remote:        Asset precompilation completed (46.64s)

The application runs inside a free dyno on heroku-16 stack

Note: I'm not using sprockets at all.

My command line:

$ rails new ruby2-rails5-bootstrap-heroku --skip-coffee --skip-sprockets --skip-turbolinks --database postgresql --webpack -T

Full deploy log

$ git push heroku master -f
Counting objects: 104, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (94/94), done.
Writing objects: 100% (104/104), 68.41 KiB | 4.89 MiB/s, done.
Total 104 (delta 27), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote: 
remote: -----> Deleting 6 files matching .slugignore patterns.
remote: -----> Node.js app detected
remote: 
remote: -----> Creating runtime environment
remote:        
remote:        NPM_CONFIG_LOGLEVEL=error
remote:        NODE_VERBOSE=false
remote:        NODE_ENV=production
remote:        NODE_MODULES_CACHE=true
remote: 
remote: -----> Installing binaries
remote:        engines.node (package.json):  9.8.0
remote:        engines.npm (package.json):   unspecified (use default)
remote:        engines.yarn (package.json):  1.5.1
remote:        
remote:        Resolving node version 9.8.0...
remote:        Downloading and installing node 9.8.0...
remote:        Using default npm version: 5.6.0
remote:        Resolving yarn version 1.5.1...
remote:        Downloading and installing yarn (1.5.1)...
remote:        Installed yarn 1.5.1
remote: 
remote: -----> Restoring cache
remote:        Loading 2 from cacheDirectories (default):
remote:        - node_modules
remote:        - bower_components (not cached - skipping)
remote: 
remote: -----> Building dependencies
remote:        Installing node modules (yarn.lock)
remote:        yarn install v1.5.1
remote:        [1/4] Resolving packages...
remote:        [2/4] Fetching packages...
remote:        info fsevents@1.1.3: The platform "linux" is incompatible with this module.
remote:        info "fsevents@1.1.3" is an optional dependency and failed compatibility check. Excluding it from installation.
remote:        [3/4] Linking dependencies...
remote:        warning "@rails/webpacker > postcss-cssnext@3.1.0" has unmet peer dependency "caniuse-lite@^1.0.30000697".
remote:        warning " > webpack-cli@2.0.12" has unmet peer dependency "webpack@^4.0.0".
remote:        warning " > webpack-dev-server@2.11.2" has unmet peer dependency "webpack@^2.2.0 || ^3.0.0".
remote:        warning "webpack-dev-server > webpack-dev-middleware@1.12.2" has unmet peer dependency "webpack@^1.0.0 || ^2.0.0 || ^3.0.0".
remote:        [4/4] Building fresh packages...
remote:        Done in 32.08s.
remote: 
remote: -----> Caching build
remote:        Clearing previous node cache
remote:        Saving 2 cacheDirectories (default):
remote:        - node_modules
remote:        - bower_components (nothing to cache)
remote: 
remote: -----> Pruning devDependencies
remote:        yarn install v1.5.1
remote:        [1/4] Resolving packages...
remote:        [2/4] Fetching packages...
remote:        info fsevents@1.1.3: The platform "linux" is incompatible with this module.
remote:        info "fsevents@1.1.3" is an optional dependency and failed compatibility check. Excluding it from installation.
remote:        [3/4] Linking dependencies...
remote:        warning "@rails/webpacker > postcss-cssnext@3.1.0" has unmet peer dependency "caniuse-lite@^1.0.30000697".
remote:        warning " > webpack-cli@2.0.12" has unmet peer dependency "webpack@^4.0.0".
remote:        warning " > webpack-dev-server@2.11.2" has unmet peer dependency "webpack@^2.2.0 || ^3.0.0".
remote:        warning "webpack-dev-server > webpack-dev-middleware@1.12.2" has unmet peer dependency "webpack@^1.0.0 || ^2.0.0 || ^3.0.0".
remote:        [4/4] Building fresh packages...
remote:        warning Ignored scripts due to flag.
remote:        Done in 8.66s.
remote: 
remote: -----> Build succeeded!
remote:  !     Unmet dependencies don't fail yarn install but may cause runtime issues
remote:        https://github.com/npm/npm/issues/7494
remote: 
remote: -----> Ruby app detected
remote: -----> Compiling Ruby/Rails
remote: -----> Using Ruby version: ruby-2.5.0
remote: -----> Installing dependencies using bundler 1.15.2
remote:        Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin -j4 --deployment
remote:        Warning: the running version of Bundler (1.15.2) is older than the version that created the lockfile (1.16.1). We suggest you upgrade to the latest version of Bundler by running `gem install bundler`.
remote:        Fetching gem metadata from https://rubygems.org/.........
remote:        Fetching version metadata from https://rubygems.org/..
remote:        Fetching dependency metadata from https://rubygems.org/.
remote:        Using rake 12.3.0
remote:        Using concurrent-ruby 1.0.5
remote:        Using minitest 5.11.3
remote:        Using thread_safe 0.3.6
remote:        Using builder 3.2.3
remote:        Using erubi 1.7.1
remote:        Using mini_portile2 2.3.0
remote:        Using crass 1.0.3
remote:        Using rack 2.0.4
remote:        Using nio4r 2.2.0
remote:        Using websocket-extensions 0.1.3
remote:        Using mini_mime 1.0.0
remote:        Using arel 9.0.0
remote:        Using mimemagic 0.3.2
remote:        Using msgpack 1.2.4
remote:        Using bundler 1.15.2
remote:        Using method_source 0.9.0
remote:        Using newrelic_rpm 4.8.0.341
remote:        Using pg 1.0.0
remote:        Using puma 3.11.3
remote:        Using rack-timeout 0.4.2
remote:        Using thor 0.20.0
remote:        Using temple 0.8.0
remote:        Using tilt 2.0.8
remote:        Using i18n 0.9.5
remote:        Using tzinfo 1.2.5
remote:        Using nokogiri 1.8.2
remote:        Using websocket-driver 0.7.0
remote:        Using marcel 0.3.1
remote:        Using mail 2.7.0
remote:        Using bootsnap 1.2.0
remote:        Using rack-test 0.8.3
remote:        Using rack-proxy 0.6.4
remote:        Using sprockets 3.7.1
remote:        Using activesupport 5.2.0.rc1
remote:        Using slim 3.0.9
remote:        Using loofah 2.2.0
remote:        Using rails-dom-testing 2.0.3
remote:        Using globalid 0.4.1
remote:        Using activemodel 5.2.0.rc1
remote:        Using rails-html-sanitizer 1.0.3
remote:        Using activejob 5.2.0.rc1
remote:        Using activerecord 5.2.0.rc1
remote:        Using actionview 5.2.0.rc1
remote:        Using actionpack 5.2.0.rc1
remote:        Using actioncable 5.2.0.rc1
remote:        Using actionmailer 5.2.0.rc1
remote:        Using activestorage 5.2.0.rc1
remote:        Using railties 5.2.0.rc1
remote:        Using sprockets-rails 3.2.1
remote:        Using rails 5.2.0.rc1
remote:        Using slim-rails 3.1.3
remote:        Fetching webpacker 3.3.1
remote:        Installing webpacker 3.3.1
remote:        Bundle complete! 32 Gemfile dependencies, 53 gems now installed.
remote:        Gems in the groups development and test were not installed.
remote:        Bundled gems are installed into ./vendor/bundle.
remote:        Bundle completed (3.11s)
remote:        Cleaning up the bundler cache.
remote:        Warning: the running version of Bundler (1.15.2) is older than the version that created the lockfile (1.16.1). We suggest you upgrade to the latest version of Bundler by running `gem install bundler`.
remote:        Removing webpacker (3.3.0)
remote:        The latest bundler is 1.16.1, but you are currently running 1.15.2.
remote:        To update, run `gem install bundler`
remote: -----> Detecting rake tasks
remote: -----> Preparing app for Rails asset pipeline
remote:        Running: rake assets:precompile
remote:        yarn install v1.5.1
remote:        [1/5] Validating package.json...
remote:        [2/5] Resolving packages...
remote:        [3/5] Fetching packages...
remote:        info fsevents@1.1.3: The platform "linux" is incompatible with this module.
remote:        info "fsevents@1.1.3" is an optional dependency and failed compatibility check. Excluding it from installation.
remote:        [4/5] Linking dependencies...
remote:        warning "@rails/webpacker > postcss-cssnext@3.1.0" has unmet peer dependency "caniuse-lite@^1.0.30000697".
remote:        warning " > webpack-cli@2.0.12" has unmet peer dependency "webpack@^4.0.0".
remote:        warning " > webpack-dev-server@2.11.2" has unmet peer dependency "webpack@^2.2.0 || ^3.0.0".
remote:        warning "webpack-dev-server > webpack-dev-middleware@1.12.2" has unmet peer dependency "webpack@^1.0.0 || ^2.0.0 || ^3.0.0".
remote:        [5/5] Building fresh packages...
remote:        Done in 26.95s.
remote:        Webpacker is installed 🎉 🍰
remote:        Using /tmp/build_42a065c9f921e906ad9d1e711273b18a/config/webpacker.yml file for setting up webpack paths
remote:        Compiling…
remote:        Compiled all packs in /tmp/build_42a065c9f921e906ad9d1e711273b18a/public/packs
remote:        yarn install v1.5.1
remote:        [1/5] Validating package.json...
remote:        [2/5] Resolving packages...
remote:        success Already up-to-date.
remote:        Done in 1.52s.
remote:        Asset precompilation completed (52.32s)
remote:        Cleaning assets
remote:        Running: rake assets:clean
remote:        rake aborted!
remote:        Don't know how to build task 'assets:clean' (see --tasks)
remote:        /tmp/build_42a065c9f921e906ad9d1e711273b18a/vendor/bundle/ruby/2.5.0/gems/rake-12.3.0/exe/rake:27:in `<top (required)>'
remote:        (See full trace by running task with --trace)
remote: 
remote: -----> Discovering process types
remote:        Procfile declares types     -> release, web
remote:        Default types for buildpack -> console, rake, worker
remote: 
remote: -----> Compressing...
remote:        Done: 71.6M
remote: -----> Launching...
remote:  !     Release command declared: this new release will not be available until the command succeeds.
remote:        Released v45
remote:        https://ruby2-rails5-bootstrap-heroku.herokuapp.com/ deployed to Heroku
remote: 
remote: Verifying deploy... done.
remote: Running release command...
remote: 
remote: D, [2018-03-14T17:07:35.847473 #23] DEBUG -- :    (1.1ms)  SELECT pg_try_advisory_lock(2039951872651186620)
remote: D, [2018-03-14T17:07:35.904183 #23] DEBUG -- :    (7.3ms)  SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
remote: D, [2018-03-14T17:07:35.929337 #23] DEBUG -- :   ActiveRecord::InternalMetadata Load (3.4ms)  SELECT  "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = $1 LIMIT $2  [["key", "environment"], ["LIMIT", 1]]
remote: D, [2018-03-14T17:07:35.948013 #23] DEBUG -- :    (1.8ms)  BEGIN
remote: D, [2018-03-14T17:07:35.951635 #23] DEBUG -- :    (1.9ms)  COMMIT
remote: D, [2018-03-14T17:07:35.953058 #23] DEBUG -- :    (1.1ms)  SELECT pg_advisory_unlock(2039951872651186620)
remote: Waiting for release.... done.
To https://git.heroku.com/ruby2-rails5-bootstrap-heroku.git
 + 76716b2...104ba71 master -> master (forced update)

@sunnyrjuneja
Copy link
Author

sunnyrjuneja commented Mar 14, 2018

@tagliala Thank you so much for chiming in!

In https://github.com/diowa/ruby2-rails5-bootstrap-heroku/blob/master/app/javascript/packs/application.js

Can you replace

import fontawesome from '@fortawesome/fontawesome'
import faGithub from '@fortawesome/fontawesome-free-brands/faGithub'

fontawesome.library.add(faGithub)

with


import fontawesome from '@fortawesome/fontawesome'
import solid from '@fortawesome/fontawesome-free-solid'
import regular from '@fortawesome/fontawesome-free-regular'
import brands from '@fortawesome/fontawesome-free-brands'

fontawesome.library.add(solid, regular, brands)

and report the the compilation time?

@robmadole
Copy link
Member

@sunnyrjuneja is there a reason why you are including entire styles in your library instead of just the icons that you need?

@tagliala
Copy link
Member

tagliala commented Mar 15, 2018

@robmadole a use case could be a custom CMS with icon and style selection inside an admin area. In those case, the developer don't know which icons will be used by the final user and should include them all

@sunnyrjuneja

Result from deploy of this branch: https://github.com/diowa/ruby2-rails5-bootstrap-heroku/tree/full-fa

remote:        Asset precompilation completed (69.58s)

For comparison, here there are the compile times with my MBP 2017 13" i7/16GB/69$adapter

master (tree shaking):

$ time RAILS_ENV=production rails webpacker:clobber webpacker:compile
Webpacker is installed 🎉 🍰
Using /Users/geremia/dev/ruby2-rails5-bootstrap-heroku/config/webpacker.yml file for setting up webpack paths
Removed webpack output path directory /Users/geremia/dev/ruby2-rails5-bootstrap-heroku/public/packs
Compiling…
Compiled all packs in /Users/geremia/dev/ruby2-rails5-bootstrap-heroku/public/packs

real	0m12.837s
user	0m15.363s
sys	0m1.027s

without fa:

$ time RAILS_ENV=production rails webpacker:clobber webpacker:compile
Webpacker is installed 🎉 🍰
Using /Users/geremia/dev/ruby2-rails5-bootstrap-heroku/config/webpacker.yml file for setting up webpack paths
Removed webpack output path directory /Users/geremia/dev/ruby2-rails5-bootstrap-heroku/public/packs
Compiling…
Compiled all packs in /Users/geremia/dev/ruby2-rails5-bootstrap-heroku/public/packs

real	0m12.295s
user	0m14.658s
sys	0m0.994s

full fa:

$ time RAILS_ENV=production rails webpacker:clobber webpacker:compile
Webpacker is installed 🎉 🍰
Using /Users/geremia/dev/ruby2-rails5-bootstrap-heroku/config/webpacker.yml file for setting up webpack paths
Removed webpack output path directory /Users/geremia/dev/ruby2-rails5-bootstrap-heroku/public/packs
Compiling…
Compiled all packs in /Users/geremia/dev/ruby2-rails5-bootstrap-heroku/public/packs

real	0m24.433s
user	0m27.390s
sys	0m1.127s

There is a ~12 second difference, so Heroku compile times do not surprise me

Please note that I'm not into Node, so tell me what I could test related to rails and webpacker and I will do that

@sunnyrjuneja
Copy link
Author

@robmadole Hey Rob, it's pretty cumbersome to import styles / icons individually and I expected the overhead to be pretty low (cache the js once).

Our icon helper looks something like this:

  def check_icon(html_options = {}, style = 'far')
    icon = [style, 'fa-check']
    icon_helper(icon, html_options)
  end

The default style is "regular" but I want to be able to occasionally use light or solid (or may already do so). It's not easy from the method definition to know which styles I'm already using.

We currently only use 10 icons from FA. If there was an easy way to import solid, regular and light for each icon, I could manage that.

@tagliala My experience with node is also pretty limited. To confirm, is it safe to say that font awesome is now both aware of this and can reproduce this? Just to be clear, it takes 120 seconds with the free version and over 5 minutes with the pro version.

@robmadole @tagliala What's a next step? Is there anything I can do to help?

@robmadole
Copy link
Member

How long does it take locally on a dev machine?

@sunnyrjuneja
Copy link
Author

sunnyrjuneja commented Mar 15, 2018

@robmadole negligible time on my i7 desktop 16 gb

@robmadole
Copy link
Member

I'm not sure what we can do to help. Heroku is a resource-constrained environment. You are loading thousands of icons (that's a lot of JS to churn through). My recommendation would be to not bundle that many icons if you are not using them. I certainly understand your frustration but I can't think of anything else to do in order to help. The JS code for the icon content is really not that crazy. It's just a bunch of names and SVG path data. Would love to help but I'm out of ideas 😸

@sunnyrjuneja
Copy link
Author

sunnyrjuneja commented Mar 15, 2018

@robmadole I feel frustrated because without FA Pro it takes less than 30 seconds and 512 mb ram holds up the rest of our application just fine.

There are two things that would be help me:

  • Being able to move off webpacker and into the asset pipeline (via a gem for pro)
  • Providing a helper that makes it easy to import solid, regular and light in one go.

Would you be amenable to either of these options?

@robmadole
Copy link
Member

Being able to move off webpacker and into the asset pipeline (via a gem)

Right now our focus is on supporting JavaScript packages and bundlers like webpack and rollup. We might eventually make Rails-specific integrations for our SVG with JS but we'll have to see what the demand is and what benefit it might provide. I think you are assuming that using the asset pipeline would provide performance improvements. Isn't it normally the other way around with JS (webpacker is faster than asset pipeline?)

Providing a helper that makes it easy to import solid, regular and light in one go

What version of Webpack are you using?

@sunnyrjuneja
Copy link
Author

@robmadole For whatever reason, the asset pipeline has absolutely no problem chunking through fontawesome-all.js (I downloaded it into vendor/assets/javascripts/fontawesome-all.js and required it in app/assets/javascript/application.js. Maybe it's doing less work?). My entire deployment dropped from over 7 minutes to under 1 minute. I'm fine with this solution but I want to keep my assets in a package management (Gemfile or package.json). If fontawesome-all.js ships in node package (perhaps a folder named dist in the fontawesome package), I can just require it through the asset pipeline since it can see node_modules.

It's extremely disappointing to hear that you might not support Rails. I backed the project (wrongfully) assuming that Rails would certainly be a first class citizen. I have been checking https://fontawesome.com/get-started/advanced-options for updates in the gem section, created this issue https://github.com/FortAwesome/Font-Awesome-Pro/issues/980, and 👍 FortAwesome/font-awesome-sass#146. It feels like the opportunity to communicate your stance could have come sooner. I did check the FA Kickstarter and see nothing about Rails so I guess that's my bad.

What version of Webpack are you using?

Webpacker (Rails integration for Webpack) uses Webpack 3 and will be updated to Webpack 4 soon. So, I use Webpack 3 and will be using Webpack 4, soon.

I just noticed the Pro CDN is now in beta. I guess I can use that as a solution for now. It also has the added benefit of removing the fontawesome registry dependency from my deployment process. I didn't think much of it until yesterday when it ruined night :(.

@sunnyrjuneja
Copy link
Author

It turns out I can't use the cdn because it doesn't support wildcard subdomains.

@robmadole
Copy link
Member

I'm fine with this solution but I want to keep my assets in a package management (Gemfile or package.json). If fontawesome-all.js ships in node package (perhaps a folder named dist in the fontawesome package), I can just require it through the asset pipeline since it can see node_modules.

We'll be releasing a new package as part of 5.1.0 that includes all the files that are available via the Pro CDN as an npm package. This should accomplish what you just mentioned.

It feels like the opportunity to communicate your stance could have come sooner.

That's fair.

Webpacker (Rails integration for Webpack) uses Webpack 3 and will be updated to Webpack 4 soon. So, I use Webpack 3 and will be using Webpack 4, soon.

You might be able to use Code Splitting to write your helper to import all 3 styles with one function call.

@robmadole
Copy link
Member

Closing as it hasn't been identified that there is a bug or issue with Font Awesome that is causing this. I will re-open if evidence comes up to the contrary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants