Thursday 10th November, 2022
By Allan Jardine

ES modules | DataTables 1.13

If you have been following along with Javascript development in recent years, you'll have noticed a sea change in the tooling surrounding the ecosystem. This is fractal in nature, with many tools being created and used, but I think it can be boiled down to two major points:

With the release of DataTables 1.13 we focus on these two points, with the aim of making DataTables easy to use with modern tooling for Javascript. While there are a few bug fixes in 1.13, there are no new end user facing features. It's all about the tooling in this release!

Without further ado, let's dig deeper into DataTables 1.13 and what it brings to the table.

ES modules

To date, DataTables has supported loading in three different methods: AMD loaders (such as RequireJS), CommonJS (typically used in Node.js) and global registration in the browser. We use a common block, called a Universal Module Definition (UMD) to support all three in a single file.

ES modules were developed to bring an official and standardized module system to Javascript which is now supported by all current browsers. Even more importantly for us, they are used extensively by modern Javascript bundlers such as Vite, Parcel and esbuild. If you are interested in learning more details about ES modules this cartoon deep dive is a great introduction.

DataTables 1.13 brings full support for ES modules, through the addition of new .mjs files in our packages (and a module attribute in the NPM package.json file). Unfortunately, it isn't possible to create a UMD which supports ES modules as well as AMD, CommonJS and global registration. So if you are puzzled as to why the number of files in our distribution repos has doubled - this is the reason. Depending on the tooling you are using, either the UDM (.js) or ES module (.mjs) file will be used.

Backwards compatibility

The original .js files remain and their UMD signature is unchanged. If you continue to use the .js files, no changes are needed. Indeed, our download builder will continue to use the .js files by default as they are really easy to embed into a browser.

Where you may run into a problem is if you are using a bundler that automatically changes from the CommonJS loader to ES modules when it detects the new files. The signatures of the two are slightly different. With our CommonJS loader you would typically do:

const DataTable = require( 'datatables.net' )();

or using import syntax that the bundler converts to CommonJS:

import DT from 'datatables.net';

const DataTable = DT();

If you do that with the ES module, you will get an error such as "Connot set properties of undefined (setting '$')". The fix is to not execute the imported module as a function - e.g. just do:

import DataTable from 'datatables.net';

Modules in the browser

While you will most likely wish to continue using the UMD loader if you are working without a bundler, you can use the new DataTables ES module files in the browser as well. However, you will need to use an up-to-date browser that supports import maps. This is because DataTables uses import $ from 'jquery' to obtain jQuery, and the browser must know how to resolve that. For example:

<script type="importmap">
    {
        "imports": {
            "datatables.net": "https://cdn.datatables.net/1.13.1/js/jquery.dataTables.mjs",
            "jquery": "https://esm.sh/jquery@3.5.0"
        }
    }
</script>
<script type="module">
    import DataTable from 'datatables.net';

    new DataTable('#example');
</script>

You can see that example live here. As noted above, you must be using browser that supports import maps:

  • Chrome 89+,
  • Firefox 108+,
  • Edge 107+, or
  • Safari technical preview.

Expanding upon this will be the topic of a future blog post.

Exports

For consistency, all DataTables extensions and their styling components (except Editor and DateTime) will now return the core DataTables module, with the extension properties accessible under that module. For example, consider Bootstrap 5 with Buttons and Excel export:

import JSZip from 'jszip';
import DataTable from 'datatables.net-bs5';
import 'datatables.net-buttons-bs5';
 
DataTable.Buttons.jszip( JSZip );

TypeScript

We've already embraced TypeScript here at SpryMedia, with all recent DataTables extensions being written in TypeScript, and CloudTables using it on both the front and backends. While we've shipped TypeScript definitions with DataTables in previous versions, they have been namespace based and not easy to extend, either for our own extensions or your own API additions to DataTables.

With DataTables 1.13 that has changed to use module based typing (interestingly the TypeScript team did this recently as well). All DataTables extensions have also been updated today to support this module system for type definitions, with the single exception of Editor. Editor 2.1 will follow soon with various other updates.

Use

For the most part, this change will be transparent to you, with the only change in type checking and code completion in your editor. When you now import DataTable from 'datatables.net'; you will have full definitions for DataTables immediately available.

Extending the API definitions

You may have your own API plug-in methods for DataTables that you wish to add to the type definitions. That can be done by extending the Api<T> interface of the datatables.net module. For example, consider the average() plug-in - its type definition would be:

declare module 'datatables.net' {
    interface Api<T> {
        average(): number;
    }
}

For a full list of the interfaces that can be extended please refer to the exported properties of the DataTables types definition file.

Conclusion

It is an information heavy post this one, with little in the way of client facing examples, but hopefully it has demonstrated how DataTables is getting ready for the next generation of Javascript tooling. It is all about making your life as a developer easier!