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

Import assets from Ruby Gem #488

Closed
frozenfung opened this issue Jun 9, 2017 · 13 comments
Closed

Import assets from Ruby Gem #488

frozenfung opened this issue Jun 9, 2017 · 13 comments

Comments

@frozenfung
Copy link

frozenfung commented Jun 9, 2017

Hey guys,

I know it may be sound weird. But I do have a lot assets (scss, font) which are bundled with Gems. Right now I am not able to re-pack them all with NPM pkgs.

I would like to let webpack search around my Ruby Gems' nest for those treasures.
Recommended, crazy or suck?

thanks
Fung

@gauravtiwari
Copy link
Member

@frozenfung Just copy the static files into vendor folder and then reference them using module resolver or something - https://github.com/rails/webpacker#using-babel-module-resolver

Or you could try adding your gem directory to module resolve in shared.js - but I think that will slow down the compiler and also increase memory usage. Try it out and see how it plays out for you 👍

@JasonHerr
Copy link

@gauravtiwari do you mean the vendor folder of the Gem or the final application?

@gauravtiwari
Copy link
Member

@JasonHerr Rails application vendor folder. You could put it anywhere though that makes most sense to you 👍

@frozenfung
Copy link
Author

Finally I decide to resolve them from shared.js. Basic concept like:

configuration.js

const { execSync } = require('child_process')

const gemInstallationDir = /INSTALLATION DIRECTORY: (.+)\n/.exec(execSync('gem environment').toString())[1];

const gemAssetsPaths = (() => {
  const assets_path = settings.gem_assets_path
  return assets_path.map(asset_path => join(gemInstallationDir, 'gems', asset_path))
})();

module.exports = {
  settings,
  env,
  loadersDir,
  output,
  gemAssetsPaths
}

shared.js

const { env, settings, output, loadersDir, gemAssetsPaths } = require('./configuration.js')

const resolveModules = [resolve(settings.source_path)]
                         .concat(gemAssetsPaths)
                         .concat(['node_modules'])

resolve: {
  modules: resolveModules,
}

webpacker.yml

gem_assets_path:
  - gem0/app/assets/javascripts
  - gem1/app/assets/stylesheets 
  - gem2/vendor/assets/stylesheets

How do you think? It is possible?
@gauravtiwari

@gauravtiwari
Copy link
Member

@frozenfung Looks good 👍 Not sure if you need execSync though - why not reference the paths statically since it's local to your system?

I have been thinking to add something like resolved_paths array key like extensions so folks can add custom paths:

resolved_paths:
  - vendor/bundle/gems
  - engines/x_engine/assets/javascripts

@frozenfung
Copy link
Author

frozenfung commented Jun 11, 2017

execSync is a necessary because I have my gems install in different path between dev/test/prod.

In dev, the path looks like

/Users/frozenfung/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/rails-5.1

in prod, which we use docker

/usr/local/bundle/gems/rails-5.1

I am not sure if I am the only one that has the situation.

I think resolved_paths sounds good because there are so many path we could have if we use external package manager like bower. When I started hacking yesterday I found it was awkward because gems has its version included in the name of directory which is different from node module.

For example, if I would like to import a bootstrap js module from node_modules

import 'bootstrap-sass/assets/javascripts/bootstrap/collapse';

with gem

import 'bootstrap-sass-3.3.5/assets/javascripts/bootstrap/collapse';

Anyway we need to tackle the version either in webpacker.yml or your entry file when we upgrade/degrade and it is annoying. Maybe we could do some magic in configuration.js that find the latest gem version automatically for user when we load resolved_paths from webpacker.yml ?

If it's ok I would like to make a PR for this.

@gauravtiwari

@gauravtiwari
Copy link
Member

gauravtiwari commented Jun 18, 2017

@frozenfung Sorry, I am such late 😄

From your comment, gem doesn't seem like a place to store JS or CSS assets. The idea behind resolved_paths is to allow people to include any random folder that may contains any frontend assets. Ideally it's best to have npm module if it's more like a library instead of a ruby Gem.

Does bower works normally if you add it to resolved path?

I think it's not worth the effort. As you know most of the stuff are now moving to npm so perhaps use the time to migrate your packages to npm - more future proof that way.

@frozenfung
Copy link
Author

I decide to transfer all my gem-based assets into npm pkgs. Eventually, it is a must.
thanks

:)

@quinn
Copy link

quinn commented Nov 29, 2018

@frozenfung

From your comment, gem doesn't seem like a place to store JS or CSS assets. The idea behind resolved_paths is to allow people to include any random folder that may contains any frontend assets. Ideally it's best to have npm module if it's more like a library instead of a ruby Gem.

It's great that you feel that way, but this is a frequently used pattern in the rails community. For example, turbolinks is a gem that includes assets that are included via the asset pipeline. Turbolinks also has an npm package you can use, but this is not the case for most rails plugins (gems). Supporting this would be a huge step towards webpacker being a full replacement of the rails asset pipeline.

@justinvdk
Copy link

justinvdk commented Dec 20, 2018

I agree with @quinn , if Webpacker needs wants to be a full replacement for rails' assets pipeline it must support a way to bridge assets from gems.

NPM is certainly the way to go for one to package its javascript and such, but I think it is illogical to have to depend on the individual gems to provide this. If Gems contain assets that don't make sense on their own (cocoon comes to mind) it would be quite stupid to have to provide a tiny part of their code via two separate dependency management systems.

For people that are looking for a (more elegant) solution, I've been toying with this. Feel to take a look and comment. With this I'm able to configure gems by name in my webpacker.yml and make them available to webpacker. It is, I think, a more elegant way of solutions that have already been proposed, with less manual configuration (after setup, you should only have to provide gem names).
Assets other than javascript are not supported, but it can be done with little extension.

@jakeNiemiec
Copy link
Member

NPM is certainly the way to go for one to package its javascript and such, but I think it is illogical to have to depend on the individual gems to provide this.

@justinvdk Gem devs have started to publish NPM "companion" packages like https://www.npmjs.com/package/ahoy.js

@m5o
Copy link

m5o commented Jan 30, 2019

@guilleiguaran once said there could be a helper to make this easily happen. And it seems Guillermo is the one with a lot of knowledge of sprockets and webpacker. Is this already available? 🤔

@meatherly
Copy link

call me crazy but I did some messing around with this: https://api.rubyonrails.org/classes/ActionView/Helpers/AssetUrlHelper.html

This allows me to still use sprockets for gems and use webpacker for my JS related things
e.g.

# development.rb
config.action_controller.asset_host = Proc.new { |source|
  if source.include?('packs')
    ENV['ASSETS_URL']
  else
    "http://localhost:3000"
  end
}

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

No branches or pull requests

8 participants