Integrating DataTables.net into Rails with Webpacker
Tags: rails, webpacker, datatables
Published: 2020-11-15 08:27:47

---
title: Integrating DataTables.net into Rails with Webpacker
published: true
description: An opinionated way to integrate DataTables.net into a Rails 6 project with Webpacker for server-rendered views.
tags: rails,webpacker,datatables
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/syfdkfrjnmcmdlutqa41.png
---

> Originally posted at my [blog](https://mutatedbread.space/blogs/2020-11-16/integrating_datatables_net_into_rails_with_webpacker)

## Hey there,

This article is about an opinionated way to integrate `DataTables.net` into a Rails 6 project with `Webpacker` for server-rendered views. I hope this article and code bits can help people with similar use cases in setting thing up.

## Premise

Back then on Ruby on Rails, we could just place every `js` files in the `/assets` directory and Sprockets will compile everything in it. Then, all methods and symbols will be readily available on the global scope to be used on Rails server-rendered views.

When I started a new Rails project at work, I discovered that we can use Webpacker to compile our `js` files and leverage the abundance of packages from `npm` . Also, I quickly found out that Webpacker does not expose all methods and classes included in all `js` files globally, while trying to debug it for hours. 😂

From my crude understanding of how Webpacker works, as `js` files are compiled into individual modules, so do the methods and classes defined are packaged into its very own scope. It means that things do not get leaked into other modules unless being required or imported. The same applies to global scope.

I found ways to import `jQuery` at the global scope via a global import but the same approach does not work to expose `DataTables.net` at the global scope of `$`.

## How I want this to work

1. `jQuery` and `DataTables.net` compiled and initialised at `application.js` level for ease of maintainance.
2. `jQuery` and initialised `DataTables.net` instance must exists at global scope for server-rendered views.

## Steps

### Installing Dependencies

1. Get the necessities

    ```bash
    yarn add jquery datatables.net datatables.net-dt
    ```

    > Please refer to [https://datatables.net/download/npm](https://datatables.net/download/npm) to know which relevant `DataTables.net` release to get for your preferred stying framework.

2. Get `webpack` loaders

    ```bash
    yarn add -D css-loader expose-loader imports-loader
    ```

3. Add the following `js` files that defined the packages we want to load.

    1. `jQuery` loader, save at `config/webpack/loaders/jquery.js`

        ```js
        // expose-loader helps us to expose the jquery module as $ and jQuery at
        // the global object, allowing us to access it at Rails server-rendered
        // views.
        module.exports = {
            test: require.resolve("jquery"),
            loader: "expose-loader",
            options: {
                exposes: ["$", "jQuery"],
            },
        };
        ```

    2. `DataTables.net` loader, save at `config/webpacker/loaders/datatables.js`

        ```js
        // datatables.net relies on the jquery global variable to work.
        // import-loader helps us to add the necessary require('jquery') so the
        // jquery variable is available when any datatables.net packages are loaded.
        // refer to https://webpack.js.org/loaders/imports-loader/
        module.exports = {
            test: /datatables\.net.*/,
            loader: "imports-loader",
            options: {
                // Disables AMD plugin as DataTables.net
                // checks for AMD before CommonJS.
                additionalCode: "var define = false;",
            },
        };
        ```

4. At `config/webpacker/environment.js`, we will append our loaders to `webpack` and add a `ProviderPlugin`.

    ```jsx
    const { environment } = require("@rails/webpacker");

    const webpack = require("webpack");

    // import our loaders.
    const datatables = require("./loaders/datatables");
    const jquery = require("./loaders/jquery");

    // append them to webpack loaders.
    environment.loaders.append("datatables", datatables);
    environment.loaders.append("expose", jquery);

    // ProviderPlugin helps us to load jQuery when the variables of $ and jQuery
    // are encountered as free variables at other modules.
    // Let's say if you want to use Bootstrap 4 and Popper.js.
    //
    // Refer here https://webpack.js.org/plugins/provide-plugin/
    environment.plugins.append(
        "Provide",
        new webpack.ProvidePlugin({
            $: "jquery",
            jQuery: "jquery",
        })
    );

    module.exports = environment;
    ```

5. At `app/javascript/packs/application.js`

    ```js
    import dt from "datatables.net";

    document.addEventListener("turbolinks:load", () => {
        dt(window, $);
    });
    ```

6. At whatever views you have. Let's say `app/views/members/index.html.slim`.

    ```ruby
    h1 Member List

    table#member-table
      thead
        tr
          td Member ID
          td Family Name
          td Given Name
          td Birth Day
      tbody
        - @members.each do |member|
          tr
            td = member.id
            td = member.famil_name
            td = member.given_name
            td = member.birthdate.strftime('%d %B %Y')

    / Just slap this in.
    javascript:
      document.addEventListener('turbolinks:load', function() {
        $('#member-table').DataTable();
      });
    ```

7. Import 'datatables.net-dt/css/jquery.datatables.css' with your preferred method.

That should do the trick. Now:

1. Our `DataTables.net` have the needed `jquery` variable within its scope.
2. `DataTables.net` is initialised at `application.js` level.
3. We get to access `$(<query>).DataTable()` at the global scope at any Rails server-rendered views.

## Example project

I have setup an example projects with the workings [here](https://github.com/MutatedBread/rails_webpacker_datatables_example).

## References and citations

The approach in this article is a compilation of solutions from many precursors asking and answering the same question.

> I might have missed out some references here.

1. https://stackoverflow.com/questions/29080148/expose-jquery-to-real-window-object-with-webpack
2. https://github.com/jbox-web/ajax-datatables-rails/blob/master/doc/webpack.md
3. https://webpack.js.org/plugins/provide-plugin/#usage-jquery
4. https://webpack.js.org/loaders/expose-loader/#root
5. https://webpack.js.org/loaders/imports-loader/
6. https://stackoverflow.com/questions/57964095/rails-6-webpack-datatables-jquery
7. https://datatables.net/forums/discussion/57642/installation-issues-rails-yarn-webpacker