DataTables and Webpack

DataTables and Webpack

swincswinc Posts: 2Questions: 0Answers: 0

Hi there -- I'm using DataTables in Webpack and following the instructions here: https://www.datatables.net/download/npm

The interesting thing about Webpack is that it provides BOTH AMD and CommonJS environments, so when the datatables.net module checks for what to export, it defaults to the AMD module. This breaks everything if in fact you used a CommonJS require() to import the module. What you get is a very mysterious 'cannot set $ of undefined' error.

It took me a while to figure this out but as far as I can tell there are two ways to fix this without modifying the datatables.net code:
(1) Disable AMD entirely in Webpack (see http://stackoverflow.com/questions/29302742/is-there-a-way-to-disable-amdplugin); or
(2) Do NOT immediately invoke datatables.net as instructed at https://www.datatables.net/download/npm. In other words, just require the file without invoking or passing arguments. I'm not exactly sure why this latter solution works.

I suppose an additional solution would be to just embrace the AMD dependency but I have not tried this.

I like DataTables a lot so posting this here to help anyone else out that may run across this issue.

swinc

Replies

  • allanallan Posts: 63,678Questions: 1Answers: 10,497 Site admin

    Very interesting and super useful. Thanks for sharing this knowledge with us!

    Allan

  • swemaniacswemaniac Posts: 1Questions: 0Answers: 0

    I have a similar experience but slightly different solution to the problem.

    The problem is indeed that the AMD module support gets "priority" since it's the first check in the datatable source.

    I too used the imports-loader plugin for webpack for just datatables.
    I did however need to invoke the factory function with (window, $) to make it work.

    Here's a gist of exactly what I had to do to get it working in npm and webpack with bootstrap styling: https://gist.github.com/swemaniac/2fbe5d6d5e425b7c046168b6d6e74e95

  • allanallan Posts: 63,678Questions: 1Answers: 10,497 Site admin

    Thanks for posting your findings! There is also a discussion about it here.

    I'll be writing this up into a proper WebPack install guide for DataTables in the coming weeks.

    Regards,
    Allan

  • marcstobermarcstober Posts: 2Questions: 1Answers: 0

    In regards to @swinc 's point (2) above: does it work because it's using AMD?

    I am inclined to just use this if it works. I'm not using AMD in my own code, but I don't see a reason to bother with imports-loader if this works.

    The other issue I found is that, for the styling packages, webpack doesn't seem to know what to "do with" a styling-only package if you just import the package. You have to point it to the CSS file in the package. I.e.:

    import dt from 'datatables.net-dt'; // does NOT work
    import 'datatables.net-dt/css/jquery.datatables.css'; // this works
    

    (Note that you have to have a CSS loader in your webpack config, but you probably want this anyway.)

    What I'm not sure about is if I'm really doing this as designed.

    Here's fuller sample code: https://gist.github.com/marcstober/c34bb4bdf7ef622cb24d6675723749bd

  • mdavis1mdavis1 Posts: 1Questions: 0Answers: 0
    edited December 2016

    as an FYI for anyone that comes across this:

    related issue

    it's important to note the case difference in the css file name(s): datatables.net-dt/css/jquery.dataTables.css. none of the examples provided should (or will in my experience) work if you build your application on a non-Mac box.

    additionally;

    with webpack all i had to define were the style/css loader and the es6 import statement:

    {
      test: /\.css$/,
      loader: "style!css"
    }
    
    import 'datatables.net-dt/css/jquery.dataTables.css'
    

    no additional config is necessary to pull in the CSS.

    for javascript dependency:

    import dt from 'datatables.net'

    thanks!

    edited to note: webpack2.*

  • ProcessorientedProcessoriented Posts: 1Questions: 0Answers: 0

    Really good and helpful post/discussion, thanks all!

    I did want to let you all know that the second link to https://datatables.net/download/npm in the original post is broken (looks like a period "." character was appended to the end of the url).

  • guanzoguanzo Posts: 2Questions: 1Answers: 0

    I'm having some weird issues with webpack and datatables. Specifically, $('table').DataTable() and $('table').dataTable() are both returning the same thing, the jquery object. Whereas i'm expecting $('table').DataTable() to return the api instance. My current workaround is to obtain the api instance by doing var tableAPI = $('table').DataTable().api().

    Here is what i have in my main.js file:

    import dt from 'datatables.net';
    import 'datatables.net-dt/css/jquery.datatables.css';
    

    webpack config for jquery:

    new webpack.ProvidePlugin({
            $: "jquery",
            jQuery: "jquery",
            'window.jQuery': 'jquery',
            'window.$': 'jquery'
        }),
    
  • allanallan Posts: 63,678Questions: 1Answers: 10,497 Site admin

    That's really odd! If you were using DataTables 1.9 then that would explain it, but that doesn't have an api() method.

    Can you link to a page showing the issue so I can check it out?

    Allan

  • allanallan Posts: 63,678Questions: 1Answers: 10,497 Site admin

    Are you using AMD or CommonJS? You say you attempted to disable AMD. If you use CommonJS you'd need to execute the returned function:

    var $  = require( 'jquery' );
    var dt = require( 'datatables.net' )( window, $ );
    

    Also you wouldn't need to import both datatables.net and datatables.net-bs. The Bootstrap styling will automatically import datatables.net.

    Allan

  • skawaiiskawaii Posts: 3Questions: 1Answers: 0

    I'm really glad I found this page. I was struggling trying to figure out why my tables weren't looking right after importing datatables.net-bs4 (using an ES6 style import). Simply importing the CSS as above did the trick.

  • artistanartistan Posts: 3Questions: 0Answers: 0

    WOW
    (2) Do NOT immediately invoke datatables.net
    THANK YOU.

  • danielku15danielku15 Posts: 6Questions: 1Answers: 0

    It would be nice to tell datatables globally what to do. e.g. via a global variable that is picked up by DataTables while initializing:

    window.DataTables.module = 'none'; // 'amd', 'commonjs', 'none'
    

    In my case I have require.js in place for TypeScript, but so far not everything is migrated to the module system and some other 3rd party dependencies do not use it as well. When I include DataTables I end up with tons of errors. I would like to force it to the classical "browser" mode until my application is ready to use only modules.

    Some registration scripts are also not easy to achieve as I am using some script bundeling. I think I can manage to get it running with some additional injected scripts between DataTables and the 3rd party scripts but the easier solution would be some global configuration.

  • sunixsunix Posts: 4Questions: 0Answers: 0

    Just disable AMD parser.

    var config = Encore.getWebpackConfig();
    
    config.module.rules.unshift({
      parser: {
        amd: false,
      }
    });
    
    module.exports = config;
    
  • duleorlovicgmxduleorlovicgmx Posts: 1Questions: 0Answers: 0
    edited October 2019

    My two cents on how to disable amd, but only for datatables.net package (not in webpack.config.js)
    After yarn add imports-loader you can use:

    // my-lib.js
    require('imports-loader?define=>false,this=>window!datatables.net')(window, $)
    require('imports-loader?define=>false,this=>window!datatables.net-bs4')(window, $)
    
  • Herz3hHerz3h Posts: 1Questions: 0Answers: 0
    edited June 2020

    For anyone stumbling upon this issue as I did trying to import datatables in webpack and having css not applying. I had to use the following for it to be working in webpack (obviously exclude plugins you don't want):

    import 'datatables.net'
    import 'datatables.net-bs'
    import 'datatables.net-bs/css/dataTables.bootstrap.css'
    import 'datatables.net-buttons'
    import 'datatables.net-buttons-bs'
    import 'datatables.net-buttons-bs/css/buttons.bootstrap.css'
    import 'datatables.net-buttons/js/buttons.colVis'
    import 'datatables.net-buttons/js/buttons.html5'
    import 'datatables.net-buttons/js/buttons.flash'
    import 'datatables.net-buttons/js/buttons.print'
    import 'datatables.net-colreorder'
    import 'datatables.net-colreorder-bs'
    import 'datatables.net-colreorder-bs/css/colReorder.bootstrap.css'
    import 'datatables.net-fixedcolumns'
    import 'datatables.net-fixedcolumns-bs'
    import 'datatables.net-fixedcolumns-bs/css/fixedColumns.bootstrap.css'
    import 'datatables.net-fixedheader'
    import 'datatables.net-fixedheader-bs'
    import 'datatables.net-fixedheader-bs/css/fixedHeader.bootstrap.css'
    import 'datatables.net-rowgroup'
    import 'datatables.net-rowgroup-bs'
    import 'datatables.net-rowgroup-bs/css/rowGroup.bootstrap.css'
    import 'datatables.net-rowreorder'
    import 'datatables.net-rowreorder-bs'
    import 'datatables.net-rowreorder-bs/css/rowReorder.bootstrap.css'
    import 'datatables.net-responsive'
    import 'datatables.net-responsive-bs'
    import 'datatables.net-responsive-bs/css/responsive.bootstrap.css'
    import 'datatables.net-scroller'
    import 'datatables.net-scroller-bs'
    import 'datatables.net-scroller-bs/css/scroller.bootstrap.css'
    import 'datatables.net-select'
    import 'datatables.net-select-bs'
    import 'datatables.net-select-bs/css/select.bootstrap.css'
    

    Note: In my case I have jQuery imported globally (legacy app). So you may have to adjust the way you import. But these files seem to be important to import if you want css to work (mainly the -bs for bootstrap + css file).

  • frontendplacefrontendplace Posts: 8Questions: 2Answers: 0
    edited July 2020

    This was my solution that worked:

    use

    import 'datatables.net';
    

    and in webpack config

    { test: /jquery.dataTables.js/, loader: 'imports?define=>false' }
    
  • frontendplacefrontendplace Posts: 8Questions: 2Answers: 0

    Have to correct: before I had import dt from 'datatables.net'; and dt(window, $); that did not work anymore now only import 'datatables.net'; had to remove the webpack test again

  • kmitovkmitov Posts: 6Questions: 1Answers: 0

    Stumbled upon this. Got to

    import 'datatables.net';
    $(document).ready( function () {
        $('#groups-datatable').DataTable();
    } );
    

    that gives

    Uncaught TypeError: $(...).DataTable is not a function
    

    while jquery is exposed

    environment.plugins.prepend(
      'Provide',
      new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery'
      })
    )
    

    I have tried
    import dt from 'datatables.net' and
    console.log(dt.version) returns a result. But still DataTable is not a function

  • colincolin Posts: 15,240Questions: 1Answers: 2,599

    There a few threads in the forum, like this and this and this, it would be worth looking at those and seeing if they help.

    Colin

  • kmitovkmitov Posts: 6Questions: 1Answers: 0

    Thanks @colin,
    I was looking at some of them with no success, but would move through them again.

  • kmitovkmitov Posts: 6Questions: 1Answers: 0

    Ok. Let's do this.

    1. Starting with https://datatables.net/forums/discussion/50003/datatables-with-webpack-fn-datatable-undefined
      Trying first solution - https://datatables.net/forums/discussion/comment/132471/#Comment_132471
    var DataTable = require('datatables.net');
     
    $.fn.dataTable = DataTable;
    $.fn.dataTableSettings = DataTable.settings;
    $.fn.dataTableExt = DataTable.ext;
    DataTable.$ = $;
     
    $.fn.DataTable = function ( opts ) {
        return $(this).dataTable( opts ).api();
    };
    

    It results in

    Cannot read property 'classes' of undefined
    

    when I try to do

    $.fn.DataTable.ext.classes.sFilterInput += "form-control g-py-15 g-px-15"
    

    So lets change the code to

    var DataTable = require('datatables.net');
     
    $.fn.DataTable = DataTable;
    $.fn.dataTableSettings = DataTable.settings;
    $.fn.dataTableExt = DataTable.ext;
    DataTable.$ = $;
     
    $.fn.DataTable = function ( opts ) {
        return $(this).dataTable( opts ).api();
    };
    

    Again there is an error for

    $.fn.DataTable.ext.classes.sFilterInput += "form-control g-py-15 g-px-15"
    

    that is

    Cannot read property 'classes' of undefined
    

    I am commenting the

    //$.fn.DataTable.ext.classes.sFilterInput += "form-control g-py-15 g-px-15"
    

    then the result is

    $(...).dataTable is not a function
    

    Status: First solution from https://datatables.net/forums/discussion/comment/132471/#Comment_132471 did not work

    1. Trying second solution - https://datatables.net/forums/discussion/comment/146128/#Comment_146128 from thread https://datatables.net/forums/discussion/50003/datatables-with-webpack-fn-datatable-undefined

    It says go for https://gist.github.com/jrunestone/2fbe5d6d5e425b7c046168b6d6e74e95#file-jquery-datatables-webpack
    And since gist tend to go missing sometimes here is the content of the gist (note, the in gist comments there is an update):

    Here's how to make jQuery DataTables work with npm and webpack. DT checks for AMD compatibility first 
    which breaks when you're using CommonJS with webpack.
    
    Install DT core: npm install datatables.net
    Install a DT style: npm install datatables.net-bs (bootstrap)
    Install the imports-loader webpack plugin: https://github.com/webpack/imports-loader#disable-amd
    Create a loader "exception" just for DT in webpack.config.js:
    
    module: {
      loaders: [
          {
              test: /datatables\.net.*/,
              loader: 'imports?define=>false'
          }
      ]
    }
    
    Then to initialize DT in your app, do this in your main entry point:
    
    // you can use import or require
    import 'datatables.net';
    import dt from 'datatables.net-bs';
    dt(window, $);
    
    Now you can use .DataTable():
    $('table[data-table]').DataTable(); // or whatever you want
    

    I would install imports-loader, and it does no work.

    1. Looking at a solution from a solution. Specifically - https://datatables.net/forums/discussion/57642/installation-issues-rails-yarn-webpacker/

    It is

    require('datatables.net-dt');   
    require('datatables.net-dt')( window, jQuery );
    

    This does not work. datatable is undefined.

    $(...).dataTable is not a function
    
    1. Looking at the forth solution https://datatables.net/forums/discussion/comment/157929/#Comment_157929

    This seems interesting. I also have jquery 2 as I depend on it. I have installed datatables, but it has not installed jquery 3 and there is not error. Let's try to upgrade.

    Now I am at 3.5.1

    info Direct dependencies
    └─ jquery@3.5.1
    info All dependencies
    └─ jquery@3.5.1
    
    

    I also have datatables

    info Direct dependencies
    └─ datatables.net@1.10.21
    info All dependencies
    └─ datatables.net@1.10.21
    Done in 13.80s.
    

    With require('datatables.net'); I can now successfully use datatables.

    Turns out it is the problem with jquery version. I depend on jquery2. Datatable seems to depend on a newer version of jquery without this being explicit about it. I was able to install datatable with jquery2 in package.json, but then datatables was taking another jquery and not using the one defined in the package json?

    Correct me if I am wrong but does datatables come with it's own jquery? I don't understand how does this happen?

  • allanallan Posts: 63,678Questions: 1Answers: 10,497 Site admin

    No - DataTables doesn't come with its own jQuery, and it is compatible back to 1.7. At least in terms of run time. I wasn't aware (or perhaps don't remember) a change in the jQuery 2 / 3 packaging, but DataTables should always just use what require('jquery') returns - source.

    Allan

  • icdebicdeb Posts: 20Questions: 5Answers: 0
    edited October 2020

    I used it like this:

    // Import jquery
    const jQuery = require('jquery')
    // Make it available globally
    // DT editor wants this apparently
    window.jQuery = jQuery
    
    // Datatables Core
    require('datatables.net')
    // Datatables Bootstrap 4
    require('datatables.net-bs4/js/dataTables.bootstrap4.js')
    require('datatables.net-bs4/css/dataTables.bootstrap4.css')
    // Datatables Editor
    require('datatables.net-editor/js/dataTables.editor.js')
    require('datatables.net-editor-bs4/js/editor.bootstrap4.js')
    require('datatables.net-editor-bs4/css/editor.bootstrap4.css').
    

    ... etc

    "datatables.net": "^1.10.22",
    "datatables.net-bs4": "^1.10.22",
    "datatables.net-editor": "^1.6.5",
    "datatables.net-editor-bs4": "^1.6.3",
    "datatables.net-editor-server": "^1.9.5",
    "jquery": "^3.5.1",
    
This discussion has been closed.