Contents

 

  • Rails and Webpack and Webpacker
    • Organization of the code
    • Adding Webpack-bundle-analyzer
  • Async loading of plugins
  • jQuery and how to expose/import and use
    • Adding into the global scope
    • Exposing jquery into global scope
    • Ingest dependencies into legacy modules
  • Adding fonts
    • Font awesome
    • Boostrap icons
      • Using them as svg
      • Using it as font
    • feather-icons
    • octicons ?

Rails and Webpack and Webpacker

The gem is called webpacker and the js thing is webpack.

All javascript is now located in app/javacscript packed in “packs” at
app/javascript/packs

Organization of the code

Good organization according this video is to have:

  • runtime pack – the webpack code
  • vendor with all the 3rd party libs
  • application.js pack with our code

Add this in your layout, the link_tag is for rails, and the pack_tag’s are for the webpack packs

    = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
    = stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'

    = javascript_packs_with_chunks_tag 'vendor', 'data-turbolinks-track': 'reload'
    = javascript_packs_with_chunks_tag 'application', 'data-turbolinks-track': 'reload'

Adding Webpack-bundle-analyzer

This will give you nice visualization of all the js modules loaded and organized by packs

yarn add Webpack-bundle-analyzer

Then add in config/webpack/development.js

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
environment.plugins.append('BundleAnalyzerPlugin', new BundleAnalyzerPlugin())

Async loading of plugins

Benefit of the webpack by loading the imports only where there are used.
Instead of doing that:

    import PDFJS from 'pdfjs/webpack'

    $('.pdf-canvas').each(() = {
        const url = $(this).data('url')
        PDFJS.getDocument(url).then(pdf => {
          // ... render
        })
    }

Do this:

    import PDFJS from 'pdfjs/webpack'
    $('.pdf-canvas').each(() = {
        const url = $(this).data('url')
        import('pdfjs/webpack').then(PDFJS) => {
          PDFJS.getDocument(url).then(pdf => {
          // ... render
          })
        }
    }

Magic comments to use the chunks

import(‘pdfjs/webpack’).then(…)
import(/* webpackChunkName: “pdfjs” */ ‘pdfjs/webpack’).then(…)

This will create a new “pack” file which you can see in the output of the webpack-dev-server

jQuery and how to expose/import and use

Adding into the global scope

If you were to add some javascript to your page that calls a jquery function, it would fail as Javascript wouldn’t understand the $. This is because Webpack doesn’t add anything to the global scope by default. We thus need to add $ to the global scope.

To this add in config/webpack/environment.js

environment.plugins.append(
  "Provide",
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    Popper: ['popper.js', 'default']
}))

We can add also an (alias)[https://webpack.js.org/configuration/resolve/]

environment.config.set('resolve.alias', {
  jquery: 'jquery/src/jquery'
});

and now we can use it like

import jquery;

links:

Exposing jquery into global scope

Use the expose-loader to expose to the global scope.
Then you will be able to do something like that in the views:

<script>
  console.log($('.hello'))
</script>`

Install it with

yarn add expose-loader

and configure it with

// this exposes jquery to be available in the views
environment.loaders.append('expose', {
  test: require.resolve("jquery"),
  loader: "expose-loader",
  options: {
    exposes: ["$", "jQuery"],
  }
});

Ingest dependencies into legacy modules

Better fix or remove the old code instaad of using this trick.

If we have old code we can try using the imports-loader

yarn add imports-loader

Then use it like that

environment.loaders.append('choosen-js', {
  test: require.resolve("choosen-js"),
  use: [
    loader: 'imports-loader',
    options: 'jQuery=jquery,$=jquery,this=>window',
  ]
});

Adding fonts

Font awesome

Install with

yarn add @fortawesome/fontawesome-free

and the js and the scss in application.js or better in vendor.js

import "@fortawesome/fontawesome-free/js/all";
import "@fortawesome/fontawesome-free/css/all.css";

Do not add anything in the application.scss because this is the old way.

Use it with

<i class="fab fa-twitter fa-2x"></i>

If you want to use the scss solution you have to do

Boostrap icons

The offical repo
yarn add bootstrap-icons

Using them as svg

According this answer we have to add in manifest.js

//= link_directory ../../../node_modules/bootstrap-icons .svg

then use it like

svg.bi.bi-telephone-minus fill="currentColor" width="16" height="16" style="color: red;" viewBox="0 0 16 16"
          use xlink:href=asset_path("bootstrap-icons/bootstrap-icons.svg#telephone-minus")

Or if you want you can click on the website and copy/paste the code to embed the SVG directly into the webpage.

Using it as font

Add this at application.js or vendor.js

import "bootstrap-icons/font/bootstrap-icons.css";  

The use it like that

i class="bi-alarm bi"

feather-icons

feather-icons git and showcase

yarn add feather-icons

Add this at application.js or vendor.js

const feather = require('feather-icons')
document.addEventListener("turbolinks:load", () => {
  feather.replace();
})

Then use it with

i data-feather="circle"

However using javascript for icons doesn’t look right, so let’s switch to the css version.

Put this link in manifest.js

//= link feather-icons/dist/feather-sprite.svg

create a app/assets/stylesheets/feather-icons.scss

.feather {
  width: 24px;
  height: 24px;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: none;
}

octicons ?

And we have add icons forever