mwouts / itables

Pandas DataFrames as Interactive DataTables
https://mwouts.github.io/itables/
MIT License
740 stars 55 forks source link

Offline mode #70

Closed BBassi closed 2 years ago

BBassi commented 2 years ago

At the moment itables does not have an offline mode. While the table data is embedded in the notebook, the jquery and datatables.net are loaded from a CDN, see require.config and table template, so an internet connection is required to display the tables.

Is there a way to add offline usage?

mwouts commented 2 years ago

Hi @BBassi , yes that is something that I would like to see supported in the future. Do you think you you could help us with this, I mean, do you think you could author a PR in that direction? Thanks

BBassi commented 2 years ago

@mwouts We do not have the bandwidth to do this internally BUT am happy to pay someone do it

mwouts commented 2 years ago

@mwouts We do not have the bandwidth to do this internally BUT am happy to pay someone do it

Oh that is very kind of you ! Let me invite @AllanJard in this issue. Allan is the founder of SpryMedia, and the author of the (Javascript) datatables library.

Allan, would you like to be working on this question of allowing the offline use of datatables in the context of Jupyter Notebooks ? If so, would you like to propose a quote to @BBassi ? I am happy to help with the python packaging (e.g. include the datatables files in the python package), but I don't have the know-how on how to build an offline web page.

Also, there are two other issues that we might have to address before this one, they are:

  1. How to address the presence or absence of requirejs - should we always use ES imports #60 or should we use an alternative to requirejs like in this PR #67
  2. How to activate datatables extensions (a WIP in the PR #67)
AllanJard commented 2 years ago

Hi :)

You'll need to forgive me, by I've not used a Jupyter Notebook yet (still on my list to fire up sometime!), so I'm not familar with how its offline mode works. Is there a package manager that installs packages for offline use or something? Are there other Javascript libraries (e.g. Bootstrap, jQuery, etc) that have an offline mode for Jupyter Notebooks?

mwouts commented 2 years ago

Hi @AllanJard , well sure no problem. I'll try to give a few pointers and they we'll see if there is any direction that looks easier than others.

  1. Until now I am loading datatables by displaying custom HTML code in a Python notebook. Displaying HTML or Javascript in a (Python) Jupyter notebook is quite easy, you just need to do e.g.
    
    from IPython.display import HTML, Javascript

HTML("""some html content""")


If you're never used a notebook before maybe you might want to try this directly on https://colab.research.google.com/.
Note that in `itables`, the HTML we display is created from [datatables_template.html](https://github.com/mwouts/itables/blob/main/itables/datatables_template.html)

2. One way to provide an offline mode is to inject the JS library in full in the web page, like is done by "plotly" for (one of) their offline mode. The JS library is in the [package_data](https://github.com/plotly/plotly.py/tree/master/packages/python/plotly/plotly/package_data) folder of the `plotly.py` python package, and the content of that file is injected in HTML documents (the "notebooks") by calling [`get_plotlyjs`](https://github.com/plotly/plotly.py/blob/2e7f322c5ea4096ce6efe3b4b9a34d9647a8be9c/packages/python/plotly/plotly/offline/offline.py#L46). The difficulty is that notebooks become very big (because they include the JS library), and also you need to pay attention to inject the library just once, not for every table.

3. I see that Altair (and probably also Plotly) can use JupyterLab extensions to render JS plots. I suppose this only works in Jupyter Lab, but the advantage is that the JS library does not need to be injected in all notebooks. @BBassi , do you need this offline mode just in Jupyter Lab, or also in notebooks exported with "nbconvert" ?
BBassi commented 2 years ago

Just Jupyterlab

AllanJard commented 2 years ago

Okay, so if I understand correctly, we'd need to package DataTables in a Python library? That would get installed on the notebook and can be referenced by the python package? Is it not possible to reference npm packages?

I guess another way of wording that is what is the end user installation of this? Presumably they aren't installing a python module, but rather a package that happens to contain Python software (and whatever else is needed - e.g. Javascript)?

mwouts commented 2 years ago

Hi @AllanJard , yes the fact that @BBassi wants this in Jupyter Lab only should allow us to provide the functionality through a "Jupyter Lab extension". Maybe we can do something like this: load datatables as a dependency of the jupyter lab extension, and detect in the notebook whether datatables is already available (in Jupyter Lab), or not (in other contexts).

I see this example Jupyter Lab extension: https://github.com/jupyterlab/extension-examples/tree/master/datagrid that might be of some inspiration to us (though I have not looked into the details)

@BBassi , would you mind to contact @AllanJard - maybe through his website (https://sprymedia.co.uk/) - to make him an offer for solving this issue ? Thanks !

BBassi commented 2 years ago

Done

AllanJard commented 2 years ago

@BBassi Many thanks - I've just replied back.

I'm not actually clear on what is needed from a DataTables point of view here. @mwouts Are you looking for DataTables to be wrapped up as a Jupyter Lab extension? Or is it itables that needs to be wrapped up as an extension?

mwouts commented 2 years ago

Awesome. Thank you both!

Allan, I think the next steps could be as follow:

  1. I document how to create a Python environment with Jupyter Lab so that you can test displaying HTML code in a notebook, and especially datatables_template.html (cf. my earlier comment)
  2. I do some research on what is the simplest 2022 way to create a Jupyter Lab extension. Then we create the extension, you and I. Maybe our extension will need no code - we just want it to provide datatables and jquery inside Jupyter Lab, so maybe we'll just have to set the right dependencies. See e.g. this other Jupyter Lab extension that I maintain.
  3. Then, you update datatables_template.html to detect whether datatables is loaded by the Jupyter Lab extension, and don't reload the library from a CDN in that case.

Does that seems alright to you?

AllanJard commented 2 years ago

Sounds good to me - let me know how you get on :-)

mwouts commented 2 years ago

I plan to start working on 1. and 2. soon, maybe tonight.

For 2. I'll try to follow this tutorial.

Maybe Allan you can help me with TypeScript - what would be the syntax for importing datatables in TypeScript ? I mean, when the tutorial says

import { ICommandPalette, MainAreaWidget } from '@jupyterlab/apputils';

what should we write to import datatables?

mwouts commented 2 years ago

@jptio, @fcollonval, the tutorial on Jupyter Lab extensions is great, but I am struggling to add the extension to the current itables project.

I moved parts of the setup.py generated by the cookie cutter to my root setup.py in this branch, but I am trying to keep the extension in the labextension folder.

The issue that I am facing is that the build process looks for the package.json file at the root at the project, while in fact it is in the labextension folder:

$ python -m build
/home/marc/miniconda3/envs/itables-dev/lib/python3.10/site-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
  warnings.warn(
* Creating virtualenv isolated environment...
* Installing packages in isolated environment... (jupyter_packaging~=0.10,<2, jupyterlab~=3.1)
* Getting dependencies for sdist...
running egg_info
writing itables.egg-info/PKG-INFO
writing dependency_links to itables.egg-info/dependency_links.txt
writing requirements to itables.egg-info/requires.txt
writing top-level names to itables.egg-info/top_level.txt
reading manifest file 'itables.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
warning: no files found matching 'package.json'
warning: no files found matching 'install.json'
warning: no files found matching 'ts*.json'
warning: no files found matching 'yarn.lock'
warning: no directories found matching 'itables/labextension'
warning: no directories found matching 'src'
warning: no directories found matching 'style'
no previously-included directories found matching '**/node_modules'
no previously-included directories found matching 'lib'
no previously-included directories found matching 'binder'
warning: no previously-included files matching '*~' found anywhere in distribution
warning: no previously-included files matching '*.pyc' found anywhere in distribution
warning: no previously-included files matching '*.pyo' found anywhere in distribution
warning: no previously-included files matching '.git' found anywhere in distribution
warning: no previously-included files matching '.ipynb_checkpoints' found anywhere in distribution
adding license file 'LICENSE'
writing manifest file 'itables.egg-info/SOURCES.txt'
* Building sdist...
yarn install v1.21.1
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 0.03s.
yarn run v1.21.1
error Couldn't find a package.json file in "/home/marc/GitHub/itables"

Could you please point out at what I need to change in my setup.py ?

Also, do you think creating an extension is the right thing to do to provide a npm library (here, datatables.net) offline in Jupyter?

mwouts commented 2 years ago

Hi @AllanJard , I am trying again to build a very simple extension. For simplicity I have created another project at https://github.com/mwouts/jupyterlab-itables2 (and when it starts working I will merge it with the main itables project). For now my objective is to do something very simple just to check that the extension works, say I'd like to display every HTML table using datatables.net.

So I wrote something like this: https://github.com/mwouts/jupyterlab-itables2/blob/3fc5c495fc50b45be592b05de09fd2e76e49bd35/src/index.ts#L17-L26

    initDataTables();

    // This is not the final code - but say that we want to turn
    // any HTML table into an interactive table
    $(document).ready(() => {
      const tables = document.getElementsByTagName('table');

      for (let i = 0; i < tables.length; i++) {
        const table = tables[i];
        table.DataTable();
       }
    });

but the problem is that I cannot build the package (pip install -ve .) because of these errors:

$ tsc
    src/index.ts(17,5): error TS2348: Value of type 'Api<any>' is not callable. Did you mean to include 'new'?
    src/index.ts(26,15): error TS2339: Property 'DataTable' does not exist on type 'HTMLTableElement'.

Do you see how should I change src/index.ts above?

mwouts commented 2 years ago

I may have found a syntactically correct fix at https://github.com/mwouts/jupyterlab-itables2/commit/fae71caf7eff8293bfae8627260eb1036e87a1ae.

Now the question is how I can use the $ object and .datatable extension in the datatables_template.html file...

mwouts commented 2 years ago

I see that this extension provides the mathjax library in Jupyter Lab, it might be a good starting point

mwouts commented 2 years ago

At some point I have been able to expose jquery and datatables.net-dt in Jupyter Lab with this tentative extension: https://github.com/mwouts/jupyterlab-itables3

With the extension enabled I have been able to load the libraries locally in Jupyter Lab with e.g.

from IPython.display import HTML

HTML("""
<link rel="stylesheet" type="text/css" href="/static/itables-jupyterlab/datatables.net-dt/css/jquery.dataTables.min.css">
<script type="module" src="/static/itables-jupyterlab/jquery/src/jquery.js"></script>
<script type="module" src="/static/itables-jupyterlab/datatables.net-dt/js/dataTables.dataTables.js"></script>
""")

I'll have to confirm that this really works (seems to be a slight issue at the moment), and also we will have to find out how to update datatables_template.html to import (with a real ES import if possible) the library from there if available...

AllanJard commented 2 years ago

Hi _ sorry I wasn't able to reply over the weekend. That looks good to me - statically including local files. I couldn't see the Javascript initialisation in the latest repo though, although I might just be clean missing it on a Monday morning!

mwouts commented 2 years ago

Hi @AllanJard ,

Yes you're right the JS files are not included in the repo - it is only when the python package is build that they are included. I have a few questions about this by the way:

Other than the above, what I need from you is a change to datatables_template.html that will let it use these static files. Maybe you can work under the assumption that these files are located locally as in the above (again, the content of these files is the same as in a local node_modules folder)?

I'd like the template file to work in three different settings:

  1. The static files are present and require is not available (Jupyter Lab with the extension)
  2. The static files are not present and require is not available (Jupyter Lab without the extension, VS Code, etc)
  3. The static files are not present and require is available (Jupyter Notebook, Jupyter Book etc)
AllanJard commented 2 years ago

Would you filter their content (since we're only going to use three files) or not?

It would certainly be cleaner to do so, yes. The only thing I can think of that might be an issue is if you decide to use Bootstrap or something else in future, you'd just need to remember to copy those files across as well.

Is that OK in terms of the jQuery and DataTables license to package them in another package?

I can't speak officially for jQuery, but yes, that is absolutely fine. As long as the copyright notice at the top of the Javascript files is retained, which it will be with a straight copy, then it is within the licensing requirements (MIT for both jQuery and DataTables).

The datatables_template.html isn't in that repo. Where is it? That said, doesn't what you have above (/static/itables-jupyterlab/jquery/src/jquery.js) do it?

Allan

mwouts commented 2 years ago

Hi Allan, thanks for the above. Then I'll package a first version of the extension (with just the static files) tonight or tomorrow.

The datatables template file is in this repository (itables). I am afraid I will have to keep the static files in another repo as they will have to be installed at a different location (static files on the jupyter server python environment , itables on the python environment used as a kernel), but maybe for you you just need to consider that you are working on a simple html file plus static libraries.

With the static files included as above I got a few errors, like require is not defined and $ is not defined - the only way I got datatables to work in Jupyter Lab being with the ES imports until now.

mwouts commented 2 years ago

Hi @AllanJard , I've tried to take a few more steps on this project...

AllanJard commented 2 years ago

Thanks! Given that the Javascript is just being run directly in the browser, and no bundler is being used, I wonder if you might be best just importing the static files in the same way as you do for the CSS files - e.g.:

<script src="/static/itables/datatables.net/js/jquery.dataTables.js"></script>

It will then work immediately, since when included by a browser it will make itself available on the global jQuery object.

mwouts commented 2 years ago

Well, I am afraid Javascript will always remain so mysterious for me...

As suggested, I have added datatables.net as a requirement to the Jupyter Lab extension at https://github.com/mwouts/jupyterlab-itables3/commit/356219e1b8c12ddb31377510b1f88d75c2a8d3ff and published jupyterlab-itables 0.1.0b0 at https://pypi.org/project/jupyterlab-itables/#files (BTW I have kept datatables.net-dt as that one provides the CSS file, but maybe that is something we should review?)

I have also updated the datatables_template.html file as suggested to import the jQuery and datatables.net libraries like this: https://github.com/mwouts/itables/pull/74/commits/4d8eb7c2e9ad0ae4f79d6e37d0000414b902feff

In some cases that works (restart kernel and run all cells?) image

but in some others (Ctrl+R on a saved notebook?) it does not: image

The problem is with the jQuery global variable: image

Here is the HTML for the reloaded notebook - it still seems to have the jQuery script: image

@AllanJard , do you see how to address this?

Last but not least I'd like the datatables_template.html file to work in absence of the static files, do you know if we can specify a fallback src for scripts and CSS directly in an HTML file?

mwouts commented 2 years ago

Part of the problem might be that the jquery and datatables.net libraries are injected in the middle of the HTML document rather than in the header... that might be an argument in favor of using local ES module imports - but for this I need help from an ESM expert!

Otherwise I am also aware of the addScript approach that dynamically adds a script to the document header, but I am wondering if that is a recommendable approach...

mwouts commented 2 years ago

I've spent long hours trying to make the addScript approach work (i.e. inject the script in the document header), I have had some success for loading the static files, but I find it too hard to cover the other cases (no static files, or require.js is present), and also I really think that there is way to much code just for loading the libraries (see this commit https://github.com/mwouts/itables/commit/7b1aa5ec4aa9b5f1856b1229f17a49332c01451b).

I would by much prefer to use local imports - @AllanJard , is it possible to use import on a recent release of datatables.net (see also https://github.com/DataTables/DataTablesSrc/issues/199) ?

AllanJard commented 2 years ago

Hi - sorry this is taking so much of your time!

is it possible to use import on a recent release of datatables.net

Unfortunately no - the esm file isn't included in the package. I'll get that in for the 1.12 release which is up coming. Since you have static files, you could just grap the content from here though. That might be a good option to get a PoC while I get the 1.12 release ready. I should note that I don't currently have esm plans for the extensions for DataTables though. As noted in the issue you linked, the dependency loading when using esm in the browser is not clear. So this approach would be limited until we can solve that.

I'm afraid I have no idea about the jQuery load issue. What you've done is what I would expect to work in a browser, so I suspect there is perhaps something specific about the Jupyter Notebook (perhaps the framework?) that is causing that issue. Is there a Jupyter support forum / channel?

mwouts commented 2 years ago

Thank you @AllanJard. Oh that's great news that you already have an ES module at https://cdn.datatables.net/1.11.5/js/jquery.dataTables.min.mjs ! Sure no problem I can add the file to the static files (done at https://github.com/mwouts/jupyterlab-itables/commit/36ec441af467e55196702687687e6d90a1430ce8).

I'll give a try to the import approach, I think it has the potential to make the table template short and self contained. Hopefully your ES module will work even when requirejs is available (unlike the one I previously got from https://esm.sh/datatables.net@1.11.3 ) - I'll report later in the day.

No worries if we cannot get the extensions immediately, I much prefer to have a simple and clear template !

mwouts commented 2 years ago

Well, we're not done yet...

At https://datatables.net/manual/installation#NPM the instructions to import datatables are

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

but in Jupyter Lab I don't have require.

So I tried this:

const { default: $ } = await import(jQuery_url);
const { default: initDataTables } = await import(datatables_url);

but then $ and initDataTables are undefined...

@AllanJard would you have an example for importing datatables.net from an URL?

BTW I noticed that

import 'https://cdn.datatables.net/1.11.5/js/jquery.dataTables.min.mjs'

or similar causes the following error:

Loading module from “https://cdn.datatables.net/1.11.5/js/jquery.dataTables.min.mjs” was blocked because of a disallowed MIME type (“”).

Maybe a MIME type for .mjs files should be set on the CDN?

mwouts commented 2 years ago

@AllanJard , do you have a minimal example that shows how to import the jquery.dataTables.min.mjs file? Please let me know when that is the case. Thanks!

AllanJard commented 2 years ago

Oof - sorry about loosing track of this one. Try this:

import 'https://cdn.datatables.net/1.12.1/js/jquery.dataTables.min.mjs'

(I've added the mime type handler for it now).

mwouts commented 2 years ago

Thank you @AllanJard . Actually I am afraid I also need some help on the example HTML... I've tried this minimal example:

<table id="table"><thead><tr><th>A</th></tr></thead></table>
<link href="https://cdn.datatables.net/1.12.1/css/jquery.dataTables.min.css" rel="stylesheet">
<script type="module">
    import 'https://code.jquery.com/jquery-3.5.1.min.js';
    import 'https://cdn.datatables.net/1.12.1/js/jquery.dataTables.min.mjs';

    $(document).ready(function () {
        $('#table').DataTable(dt_args);
    });
</script>

but I get this error:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://cdn.datatables.net/1.12.1/js/jquery.dataTables.min.mjs. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.

Module source URI is not allowed in this document: “https://cdn.datatables.net/1.12.1/js/jquery.dataTables.min.mjs”. [datatables_template.html:3:1](file:///home/marc/GitHub/itables/itables/datatables_template.html)

Is this something that you know how to fix?

Or more importantly, what should I import exactly from jQuery and dataTables? Should I write something more explicit like e.g.

import {$} from 'https://code.jquery.com/jquery-3.5.1.min.js';
import {initDataTables} from 'https://cdn.datatables.net/1.12.1/js/jquery.dataTables.min.mjs';
initDataTables($);

Thanks !

AllanJard commented 2 years ago

This is how to do it:

import 'https://code.jquery.com/jquery-3.5.1.min.js';
import dt from 'https://cdn.datatables.net/1.12.1/js/jquery.dataTables.mjs';

dt($);

$(document).ready(function () {
    $('#table').DataTable({});
});

http://live.datatables.net/yecukepe/1/edit

Live example.

It looks like the .min.js file we have isn't actually a valid module. The compressor we are using (an older version of closure compiler) doesn't have support for JS modules - hence the need to use the jquery.dataTables.mjs file in that example. I need to get that sorted out.

mwouts commented 2 years ago

Thanks @AllanJard ! I've tested the code snippet just above and I can confirm that it works (BTW may I suggest you had a new section on this at https://datatables.net/manual/installation ?)

Now I need to find out how to replace the fixed urls with dynamic ones (either distant or local). My naive attempt below results in an error "$ is not a function", so I guess the problem is with the jQuery import. Maybe on this point I can ask once more for @fwouts' help, he's so good at solving these kind of issues!

let jQuery_url = 'https://code.jquery.com/jquery-3.5.1.min.js';
let datatables_url = 'https://cdn.datatables.net/1.12.1/js/jquery.dataTables.mjs';

const { default: $ } = await import(jQuery_url);
const { default: dt } = await import(datatables_url);

// works
dt($);

// fails with error "$ is not a function"
$(document).ready(function () {$('#table_id').DataTable();});
AllanJard commented 2 years ago

BTW may I suggest you had a new section on this at https://datatables.net/manual/installation

Thanks! As soon as I figure out how to load in the extensions and styling integration files with ES modules, then yes, it will go up there as fully supported. I've made no progress or found a way to do dependencies with ES modules in a way that would be suitable (like we discussing in the other thread). Until something for that becomes available, it would require a big long list of import statements which isn't ideal.

Recarding the error - what happens if you console.log($);? I'm going to guess it is undefined?

mwouts commented 2 years ago

@AllanJard , yes when I do

const { default: $ } = await import(jQuery_url);
console.log($);

with jQuery_url as above, then the result is undefined.

If I interpolate with the current working version of itables, I see that we have let jQuery_url = 'https://esm.sh/jquery@3.5.0';, and this actually works!

Still I'd prefer to not use esm.sh if not necessary, I'll have a look at https://stackoverflow.com/questions/34338411/how-to-import-jquery-using-es6-syntax...

mwouts commented 2 years ago

Regarding your questions on how to load the extensions and styling with ES modules, I am afraid I can't help here, but maybe @fwouts will have a pointer for you?

The SO thread says

import {$,jQuery} from 'jquery';
// export for others scripts to use
window.$ = $;
window.jQuery = jQuery;

but if I replace the first line with const { $, jQuery } = await import(jQuery_url); then again I get undefined for $. Probably this is because in the context of the SO question 'jquery' refers to an ES module, while I am trying to import from a URL - anyone knows if an official ES module for jQuery is available online?

fwouts commented 2 years ago

@mwouts I think it should be:

import jQuery from 'jquery';
window.$ = jQuery;
window.jQuery = jQuery;
mwouts commented 2 years ago

I've spent some more time on this, here are a few findings:

mwouts commented 2 years ago

Hi again... good news, I think we're almost ready!

I have a release candidate ready, @BBassi would you like to test it? You will need to install the development version itables_0.5.0 with

pip install git+https://github.com/mwouts/itables.git@offline_mode_always_use_import

Also you will need to install separately the static files, which is documented at https://github.com/mwouts/itables/blob/offline_mode_always_use_import/docs/quick_start.md#offline-mode (@BBassi can you tell me if it is clear enough that one needs to install the extension in the Python env used to launch Jupyter Lab?)

Then I'd like to know who I can thank in the changelog... @BBassi, @AllanJard was then any sponsoring involved in the end?

Kind regards

AllanJard commented 2 years ago

That's awesome - nice one! Nope - no sponsoring in the end.

mwouts commented 2 years ago

Thanks Allan! Indeed getting rid of the switch between require and import is a great milestone, and so is the option to use the static files. @BBassi let me know if it works for you, and also if you are still considering sponsorship for this issue.

mwouts commented 2 years ago

@AllanJard, we are currently studying yet another option with @fwouts at #77 - we are considering to just inject the JS code in the notebook (=HTML file). I prefer this approach as the user will not need to install another Python package (but we still have to fix some issues probably related to the constraint that our scripts are injected in the HTML body, not head...)

When doing the above, we noticed that we can load jQuery (which does not have an ES version in production yet) with just

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

but we can't do that for datatables.net when require.js is present.

That seems to be the only reason why we want to import datatables using an ES import (the ES import is robust to the presence of require).

Is that something that you would be willing to fix? A MRE is this HTML file (it works when you delete the require.js script)

<!DOCTYPE html>
<html>
  <head>
    <title>DataTables</title>
  </head>
  <body>
    <link href="https://cdn.datatables.net/1.12.1/css/jquery.dataTables.css" rel="stylesheet" type="text/css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.datatables.net/1.12.1/js/jquery.dataTables.js"></script>
    <script>
      $(document).ready(function () {
    $('#table').DataTable({});
});
    </script>
    <div class="container">
      <table id="table" class="display nowrap" width="100%">
        <thead>
          <atr>
            <th>Name</th>
            <th>Position</th>
            <th>Office</th>
            <th>Age</th>
            <th>Start date</th>
            <th>Salary</th>
          </tr>
        </thead>

        <tfoot>
          <tr>
            <th>Name</th>
            <th>Position</th>
            <th>Office</th>
            <th>Age</th>
            <th>Start date</th>
            <th>Salary</th>
          </tr>
        </tfoot>

        <tbody>
          <tr>
            <td>Tiger Nixon</td>
            <td>System Architect</td>
            <td>Edinburgh</td>
            <td>61</td>
            <td>2011/04/25</td>
            <td>$3,120</td>
          </tr>
          <tr>
            <td>Donna Snider</td>
            <td>System Architect</td>
            <td>New York</td>
            <td>27</td>
            <td>2011/01/25</td>
            <td>$3,120</td>
          </tr>
        </tbody>
      </table>
    </div>
  </body>
</html>
AllanJard commented 2 years ago

I'm not sure that is going to be a "proper" change in DataTables. jQuery is somewhat unique in the AMD world in that is exports itself as a named module, and it looks like in an AMD environment it will also register to the browser's global scope. That rather goes against the modularisation that AMD tries to achieve.

This is what DataTables does if we detect that require.js is present (as an AMD loader):

    if ( typeof define === 'function' && define.amd ) {
        // AMD
        define( ['jquery'], function ( $ ) {
            return factory( $, window, document );
        } );
    }

Whereas with jQuery, if you look at their loader they only make a distinction between CommonJS and everything else, with an AMD / Require.js loader being added later on in their code:

if ( typeof define === "function" && define.amd ) {
    define( "jquery", [], function() {
        return jQuery;
    } );
}

When Require.js is present, I've assumed that DataTables will be used only via Require.js. I could change that, but I'm not convinced that it would be the correct decision to make.

AllanJard commented 2 years ago

If a remote URL is acceptable (perhaps at build stage) perhaps something like: ?

requirejs.config({
  paths: {
    'datatables.net': 'https://cdn.datatables.net/1.12.1/js/jquery.dataTables',
    jquery: '//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min',
  }
});

require(
  ['jquery', 'datatables.net'],
  function ($) {
    $('#table').DataTable({});
  }
)
mwouts commented 2 years ago

Hi @AllanJard , thank you for the detailed answer !

When Require.js is present, I've assumed that DataTables will be used only via Require.js. I could change that, but I'm not convinced that it would be the correct decision to make.

Yes that is exactly the problem that I am facing. In some environments the notebook will have require.js, in some others it won't, and I have no choice on that (and I cannot generate the notebook accordingly - I need that the same notebook works in both cases).

Thanks also for the suggestion to use requirejs.config. That's actually what we do in the current version (0.4.7). In the two PRs that are attached to this issue (#76 and #77 ) we are able to remove the fallback on that config file, and I do like this! This comes at the expense of using the module version of datatables.net (which is great!) but also this means, as you stated previously, that we won't be able to use extensions very soon.

Maybe what we can do is to document this issue on datatables' issue tracker and when you find the proper approach (sorry again for not being able to help you with this) I'll get a notification and will reconsider using the non-ES script ?

AllanJard commented 2 years ago

Sounds good to me!

I've just been reading about Import maps which would be the business for this I think. Chrome based browsers only for now though (is that an issue on Jupyter Notebooks - can they run Firefox?)

mwouts commented 2 years ago

Very good, thanks Allan! Done at https://github.com/DataTables/DataTablesSrc/issues/213.

I've just been reading about Import maps which would be the business for this I think. Chrome based browsers only for now though (is that an issue on Jupyter Notebooks - can they run Firefox?)

Oh I'm afraid that's still a long way to extensions then... Jupyter Notebooks are supposed to work in all browsers, and sometime in very exotic browsers like VS Code or PyCharm, so we might not be able to use import maps in all these environments for a while... That's a strong argument for going back to plain JS scripts when the require.js issue is solved, isn't it? :smile:

AllanJard commented 2 years ago

Its probably a strong argument to use a pre-processing bundler to generate a single Githubissues.

  • Githubissues is a development platform for aggregating issues.