Fix headless loading via. commonJS - #401
Conversation
The CommonJS loader, for both dataTables.js and variants that import it, will vary behaviour depending on whether a root window is defined or not. If no window is available (read: nodejs), then a factory function is returned. Previously, this factory function would require() the base dataTables.js at run time. However, by then a global window might exist, and the wrapper doesn't get the factory class it's expecting. Instead, require() all dependencies whilst the wrapper itself is being require()d, so they get the same environment. References: DataTables#385
In windowless environments (read: nodejs), location will not be defined. However, the CommonJS wrapper makes sure window & document are defined appropriately in these scenarios. References: DataTables#385
|
Interesting - many thanks for this. Is it specifically CommonJS that you want to use, or is that just a workaround as headless doesn't work with ES Modules (ESM, which is what I presume you mean by EJS)? Looking at the code above, finding some way to have the ESM loaded work for a headless environment looks more desirable (so you can use the styling packages). |
|
Out of interest, what is the use case for using DataTables headless - server-side rendering of the table? |
|
I've just been looking a bit more into using DataTables in a windowless environment, and I do have it setup to allow the import DataTable from 'datatables.net/js/dataTables.mjs';
import { JSDOM } from 'jsdom';
const jsd_window = new JSDOM(
`<!DOCTYPE html>
<html>
<body>
<table id="myTable"></table>
</body>
</html>`
).window;
DataTable.use(jsd_window);
const dt = new DataTable('#myTable');However, that very definitely doesn't work. I've got a handful of "pre-init" setup functions that use window properties, such as checking the locale number format. I'd really like to get this addressed so it does work in native ESM environments (it should also then work for CommonJS since it is loader independent), however while checking this I've also realised that my package.json doesn't use What I think I'll do is set this as a 3.1 target. The changes are a bit too extensive to get into 3.0.1 (or any 3.0 patch). That shouldn't be too far away. I want to get StateRestore and SearchPanes ported to v3, then consider this. Apologies it isn't going to be a super fast fix. |
I'm not fussed, anything that works (and yes, sorry for getting the names wrong!)
Unit-testing modules containing custom column renderer functions that build on The module is still browser code, so I'd like to keep doing Getting a factory back in some cases is something that caused head-scratching, but sounds like this is already something you're picking apart. An aside, jQuery deprecated theirs with 4.0.0 and have a separate factory import.
Yeah, that's more than fine. I did start looking at detangling the pre-init uses of window/document, but it clearly needed more structural thought. I've conflated 2 things a bit here, quick fixes needed to improve CommonJS support in nodeJS and the issue of using ESM in nodeJS. If you'd like me to do the issue gardening to separate the latter into it's own issue then can do. If you'd rather not merge the pull request that's also fine, I think I can work around everything at this stage. Thanks again for your help! |
|
Hi - many thanks for your reply and additional thoughts on this. Yes, I think it probably wouldn't be right to pull in this PR at the moment, knowing that a full fix for both issues (which go hand in hand) will be coming in 3.1. I'll leave this issue open for the moment though, as window-less is currently not going to work. I'll update when its done :) |
I've been tinkering with this on and off for a bit with DT 3 as suggested. The following fix #385 to the point that a script like this can run in nodeJS:
Using EJS however is a bit of a non-starter:
dataTables.bootstrap5.mjs) will load the.jsversion withouttype: "module"inpackage.json. How safe this is to add I'm not sure.window&documentobjects available to other code. In EJS-land, this doesn't happen, there's a long string of code (e.g. the line in the second commit) that runs on import that assumes that window or document are defined.There doesn't seem to be an obvious solution for the latter. Going round and doing
globalThis.window ? ...seems sisyphean, and wouldn't be the right window object anyway. Maybe a separate headless wrapper would work, but I've not looked into how to construct one of those yet.And thanks again for dataTables!
My contribution is offered under and will be made available under the project's existing license (MIT).