Webpack plugin for rails assets compatible manifest - ruby-on-rails

I'm trying to fully replace the rails asset pipeline with a webpack based pipeline. I've got the dev setup with the webpack-dev-server and hot reloading etc all working beautifully. Now what I'm trying to achieve is a compilation step for production that would mimic how rails compiles assets (digesting / generating a compatible manifest.json file) such that I can still use helpers like javascript_include_tag etc. This is where I'm stuck.
I've read lots of tutorials on using webpack with rails, but they all end up writing their own view helpers to load the assets. I'm trying to avoid this because I don't want extra overhead or for devs to need to understand a different pipeline. I also want config like asset_host= to work out of the box for using a CDN etc.
Ultimately, what I want is something similar to gulp-rev-rails-manifest that generates a rails-asset-pipeline compatible manifest file on compilation, but I haven't found a plugin (yet) that exists for Webpack. So...
is it possible to run a webpack build through a gulp stream using webpack only (ie not using gulp-webpack) so I can use the above gulp plugin. The reason I don't want to use gulp-webpack is that it takes over your entries / output etc and I find that whole setup confusing since this all already exists in webpack.config
Or
Does anyone have any decent resources on writing plugins for Webpack. It seems a bit of a black box to me and the official site has a menu section for "How to write a plugin" but it's not actually a link to anything.
Or
Is there actually a plugin that will do exactly this and I don't know how to search properly on the interwebs.
Any help is greatly appreciated :)

Running webpack in a gulp task is very simple:
var webpack = require('webpack');
var webpackConfig = require('./webpack.config');
gulp.task('webpack', function(done) {
webpack(webpackConfig, function(err, stats) {
done(err);
});
});
Note that the stats object provided to the webpack callback contains information about all assets emitted by webpack, so you could potentially use it to generate your own manifest.
Here are a few webpack plugins you might find useful:
https://github.com/sporto/assets-webpack-plugin
https://github.com/danethurber/webpack-manifest-plugin
https://github.com/diurnalist/chunk-manifest-webpack-plugin
While there is no official tutorial on how to create a plugin, there's still a Plugin API doc that describes the different interfaces your plugins can hook into. The webpack source and github contain a lot of webpack plugin examples.
Here's a very simple plugin that just logs assets:
module.exports = function() {
this.plugin('done', function(stats) {
console.log(stats.toJson().assets);
});
};

Related

Using Parcel 2 with Ruby on Rails

How can I output the javascript file from Parcel, include this javascript file in Rails app/assets/javascripts/application.js, and ideally get it working with hot module reloading?
Alternatively, is this a bad approach, and do you recommend something more streamlined, that lets me use mostly traditional .html.erb Rails templates but sprinkle in ReactJS UI components here and there?
I was able to do this perfectly in Parcel 1 but I am finding that the setup is quite different in Parcel 2.
I am using the traditional Rails 5 application.html.erb templating.
My attempt so far with Parcel 2 has been to use the library tutorial in the Parcel documentation. I can mount the simplest React component to my Rails app but then if I try to import anything I get errors like require is not defined, and HMR is not working.
I'm not sure how much context to provide for this question. But if it helps, my previous setup with Parcel 1 was to have a separate npm app at the root folder (next to the Rails /app folder) which output a dist/index.js file using the npm script parcel start app/index.jsx --out-dir dist --public-url /assets/dist. This was added to the Rails assets via config.assets.paths << Rails.root.join('frontend') and included in app/assets/javascripts/application.js .
Now for Parcel 2 I removed the include in application.js and added <script type="module" src="/assets/dist/index.js"></script> in application.html.erb
There are two errors you're seeing that I might be able to help with:
Runtime errors like require is not defined. This would be expected if you set up parcel to output your javascript as a library target (as you indicated). Libraries are typically npm packages that are consumed by other projects. In this context, parcel will output a commonjs bundle (including require-based imports) that's intended to be processed by another bunder (maybe parcel again, or webpack) before it's ready to be executed in a browser. You probably want to build your javascript with a browser target instead, so that all dependencies are included without require statements to other packages.
Assuming your package.json for the parcel project currently looks similar to the the library tutorial, the way you'd do that would be to remove the "main": "path-to/my-root-javascript.js" field, and change the build script to parcel build path-to/my-root-javascript.js. There's also a bunch of ways to customize this - see the targets documentation.
HMR not working. If parcel is only in charge of bundling your javascript (and rails is building your html from templates), then the "normal" way that parcel does HMR won't work. This "normal" way would involve parcel injecting an HMR script in the html file that's its responsible for building and serving. But if Rails is taking care of the HTML, parcel can't do this automatically. Perhaps there is a way to configure rails to watch when parcel rebuilds the js bundle, and refresh the page?
This might be a bit of an onion-peeling exercise - it's hard to say if the above suggestions will solve it all end-to-end. If you can post a minimal reproduction of the issue (maybe a simplified version of your ruby + parcel project?) on github that shows the problem, I'm happy to troubleshoot it further.

Rails 6 - Should I put my CSS & JS in rails asset pipeline or webpacker or through Amazon Cloudfront? Which is the most efficient?

I use to host my CSS files in the rails asset pipeline and JS on webpacker. I recently realize my webpage has been loading slower and slower.
I ran Chrome lighthouse on my site and found that my CSS and JS assets are "render-blocking resources" and causing my page to load slower.
I've already tried moving all of my CSS and JS over to webpacker (semantic-ui css is still being imported by the rails asset pipeline, had lots of problems trying to make this work but couldnt still)
I notice on Chrome lighthouse that my load time improved marginally, I guess its from the minification of CSS and JS by webpacker but it's no where near the improvements I was looking for.
So my question here is, what is the most efficient method to serve CSS and JS files for rails app?
My app is hosted on Heroku's Hobby Tier.. could this be a factor as well?
Both approaches should allow you to achieve similar results. I don't know rails asset pipeline, but if it's used similarly to webpack it just changes your files on the build time & it's up to you how much code the user gets to download.
First of all, you can check the output size - in webpack, you can check the build standard output, or directly check the files it creates.
One trap you could be failing into with webpack is to have it set up wrongly. It could anything, from not minimizing code when for production build to having loades set up in a way that makes your images included directly inside js as data URL.
One advantage of using webpack, is that allows you to set up more complicated loading logic - for example lazy loading. Here something more about lazy load:
https://dev.to/marcinwosinek/lazy-load-library-in-application-build-with-webpack-5757

How to deploy angulardart 5.2 properly for production?

on the angulardart official website, I can not find any docs related to production deployment. I prefer command line way, so far I find out I can do webdev build to generate a build/ directory. But there are still some more questions:
I want to clarify what files I should deploy to the production server. I think they should be favicon.ico, index.html, main.dart.js, styles.css 4 files, right?
Why does it generate .build.manifest, .packages, packages/? two files and one directory which contains many directories and files. They are just confusing me. This is for production. Why do I ever want to have those files? Should I write a deploy script to simply auto-remove them?
It seems the generated main.dart.js is a minimized js file. But why are there many useless newlines in it? How to get rid of those useless newlines properly by using angulardart way? I can do that with gulp, but I don't want to use gulp if dart can handle this.
How to minimize html and css files properly by using angulardart way? for example, index.html and styles.css. Again, I can do that with gulp, but I don't want to use gulp if dart can handle this.
Thank you very much for your help.
Here you can find some of official doc :
https://webdev.dartlang.org/angular/guide/deployment

Adding Lodash to a new Rails 5.2 app with webpacker

So, using Rails 5.2beta (gem install rails --pre), if you create a new app via rails new myapp --webpack=react... how would I go about incorporating Lodash into my flow from there?
I've mucked around with babel-plugin-lodash and lodash-webpack-plugin to no avail.
The compile doesn't fail if I do something like import { _pick, _map } from 'lodash/array'; ... but those variables are undefined when trying to use them.
I'm a bit lost as I'm both new to webpacker & webpack, and a lot of existing examples seem to target an older version of webpack?
Anyway, thank you for any help...
UPDATE:
Ok, looks like you can just do import map from "lodash/map"
So where are you trying to use lodash from? By this I mean are you sure the files are getting compiled / processed by Webpacker, or are they getting processed via the Asset Pipeline?
On my webpacker project I realized that there's a problem: that yes, regular old Javascript compiled with the Asset Pipeline won't know about the NPM Modules included via Webpack. (or at least the require statements wouldn't work).
Because of this I made a hard rule: all javascript goes where webpacker expect it (app/javascript) and no Javascript goes in app/assets. We only use the asset pipeline for CSS (which works great in our case, as I still don't think React - our frontend framework of choice - has a good story around site wide CSS).

Grunt and Rails

I'm working on using a Grunt workflow to manage my assets in my Rails app rather than Sprockets.
So far, I have my apps JS and CSS both being concatenated and minified into public/assets/javascripts/application.js and public/assets/stylesheets/application.css respectively.
And also have my Bower components JS and CSS being concatenated and minified into public/assets/javascripts/vendor.js and public/assets/stylesheets/vendor.css respectively.
Fonts and Images from Bower components are then copied into public/assets/(images|fonts).
This is all well and good but now I need the references to fonts/images within those files to be updated to reflect their new location.
I have looked at cssmin and yes it rewrites file references but I cannot get the file path to change depending upon the type of file being referenced.
Any ideas on how I can do this?
Also, I ahve been reading about Grunt plugins which can read your view files and use those to minify and concatenate files and update the and tags in the views for you.
Surely I can't do that in a Rails app? Is there a way I can deal with this in Rails?
This other StackOverflow post may be of help:
Integrate Grunt into Rails asset pipeline
The accepted answer recommends using the Half Pipe gem.
The second answer linked to a blog post about a Do-It Yourself solution: Goodbye, Sprockets! A Grunt-based Rails Asset Pipeline.
I haven't used either solution, but they are worth a try.

Resources