添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

I am trying to migrate my project to Symfony 4. To do so I want to use webpack/encore instead of static assets. I am unsing the datatables plugin and now I am trying to make it work. After requiring the module I cannot use $.fn.dataTables.

TypeError: $.fn.dataTable is undefined

The module is imported via require('datatables.net');
I also tried to use AMD: require('datatables.net')(window, $); this resulted in TypeError: this is undefined (jquery.dataTables.js:132).

Writing the require output to $.fn.dataTable also doesn't work.
dataTable = require('datatables.net'); $.fn.dataTable = dataTable;

Of course it's no longer undefined but it also doensn't work because the module exports DataTable and not $.fn.dataTable. So the resulting error when unsing it is TypeError: $(...).DataTable is not a function

I would appreciate your help to finally make this work like I would use static assets.

Nope. I am afraight that didn't work.
I am not sure how datatables and webpack internally work. But I guess the package attaches itself to the jquery space (why we can use $.fn.dataTable ).
So when calling the package via require ... does webpack handle $ to the module so it can attach itself to jquery or isn't that even designated?

Ok I found a solution. Its not pretty but it works:

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

Simple: just adding all functions to $.fn manually. I just took the code lines from the actual code in the nodeJS module.

If somebody knows the proper solution to add such prototypes from inside the module: please let us know :smile:

That shouldn't be required... If you are AMD loading, which it appears you are, then DataTables does this:

        define( ['jquery'], function ( $ ) {
            return factory( $, window, document );

So as long as jquery is resolvable (it is case sensitive) then it should work.

Can you confirm both if you are use AMD and if jquery is resolvable in your loader?

Allan

I don't think there is a datatables.net-bt package. Perhaps you means dataTables.net-bs?

Allan

Well, I don't really know. I am a PHP dev, and I hate JS and it's weird behaviour. I am really forced to use it and loose patience very rapidly with it. But I love DataTables, and use it for years now. That thing, Webpack Encore, is a curse for us PHP developpers.

What I understood, is that Webpack Encore uses yarn in place of npm, so maybe the packages names are different. I also found that on a blank Symfony 4 project, DataTables works fine. But on my project, the only way I found to make it work is by redefining the $.fn.dataTable thing. and if i try to use plugins with it, they craches.

It is so frustrating to copy-paste obscur things found on the web and not understand why it would work or why it wouldn't. Having globals, not-so-globals, and maybe-globals variables ... For me JS is not a programming anguage. It isn't even build by the ones that specifies it. Each browsers make their own JS engine, respecting or not the specs ... It couldn't and shouldn't work.

It seems that I made it work. But I don't really know how, as I modified so much things in a week.

I've replaced all "require()" calls with "import" ones, and defined window.jQuery, and now it seems to work.

import $ from 'jquery';
window.jQuery = $;
import DataTable from 'datatables.net';
import 'datatables.net-bs';

No more need to redeclare $.fn.dataTable. Like we say in french "C'est tombé en marche". It works, but I can't explain why.

Edit: It looks like "window.jQuery = $;" isn't event required, thanks to Encore's autoProvidejQuery()

I just about gave up on using datatables via webpack until I came across the following:

https://gist.github.com/jrunestone/2fbe5d6d5e425b7c046168b6d6e74e95#file-jquery-datatables-webpack

Works 100% now using the imports-loader.

A couple of notes:

Installing from https://github.com/webpack/imports-loader is fine. https://github.com/webpack/imports-loader#disable-amd is not required.

Change loader: 'imports?define=>false' to loader: 'imports-loader?define=>false'

Excellent, glad all working, and thanks for the suggestions, I'm sure that'll help others,

I had the same problem as the OP. In my case, it turned out to be a problem with multiple versions of jQuery being referenced as dependencies. When I installed datatables.net, it included jquery 3.4.1. But my main jquery package was still at 3.3.1. So....

const $ = require('jquery');  // returns v3.3.1
var dt = require('datatables.net');  // Internally uses v3.4.1 via amd loader

If you attempt to use $.dataTable() in your code, it's going to fail because dataTable wasn't initialised on the older version of jQuery object.

My solution was to upgrade my jquery package via npm/yarn:

yarn upgrade jquery

So it matches the version of jquery used by datatables.net. Then $.dataTable() is defined and works as expected.

Thanks for that It almost work form me :)
It is working fine when I compile in development mode but not in production mode...

webpack.config.js :

const webpack = require('webpack');
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
let config = {
  entry: {
    check_process_nomenclature: path.join(
      __dirname,
      'src',
      'js',
      'toto.js'
    user_login: path.join(__dirname, 'src', 'js', 'tata.js')
  output: {
    path: path.join(__dirname, 'web', 'dist'),
    filename: '[name].[chunkhash].bundle.js'
  resolve: {
    extensions: ['.js'],
    alias: {
      style: path.resolve(__dirname, 'src', 'style')
  module: {
    rules: [
      { test: /datatables\.net.*/, loader: 'imports-loader?define=>false' },
        test: /\.js$/i,
        exclude: [/(node_modules)/, /(ckfinder)/],
        use: ['babel-loader']
        test: /\.(png|webp|jpe?g|gif|svg|eot|ttf|woff|woff2)$/i,
        use: [
            loader: 'file-loader',
            options: {
              publicPath: '/web/dist',
              name: '[name].[hash].[ext]'
        test: /\.css$/i,
        use: [
          'style-loader',
            loader: 'css-loader',
            options: {}
        test: /\.s[ac]ss$/i,
        use: [
          'style-loader',
            loader: 'css-loader',
            options: {}
          'sass-loader'
  plugins: [
    new MiniCssExtractPlugin(),
    new ManifestPlugin(),
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery'
    new CleanWebpackPlugin()
  optimization: {
    minimizer: [
      new TerserJSPlugin({
        test: /\.js$/i,
        exclude: /\/node_modules/,
        parallel: true,
        sourceMap: true
  stats: true,
  devtool: 'source-map'
module.exports = (env, argv) => {
  if (argv.mode === 'production') {
    config.mode = 'production';
    config.optimization.minimize = true;
  } else {
    config.mode = 'development';
    config.optimization.minimize = false;
  return config;

datatables.js :

import dt from 'datatables.net-bs';
import 'datatables.net-bs/css/dataTables.bootstrap.css';
import 'style/_datatables.css';
dt(window, $);

toto.js :

import { productInformation, alertMsg, autoLogout } from './_common';
import './datatables';
import { modalOnHide } from './_modal_onhide';
import 'style/toto.css';
const $table= $('#table');
$table.DataTable({
  autoWidth: true,
  paging: true,
  lengthMenu: [
    [25, 50, 100, 250],
    [25, 50, 100, 250]
  ordering: true,
  info: true,
  stateSave: true,

run :
webpack --mode=production

error :

If someone have any idea of how to solve this issue it would be great!!

It would be worthwhile comparing the different between prod and dev, especially the sources that you are including,

Colin

Did you set the global jQuery? I saw $.fn.dataTable defined, but $.fn.DataTable undefined before I did it. I see $ defined in Chrome. Either it is built in or some extension set it, but it does not come from jQuery. As soon as I set the global jQuery properly, DataTables started to work, including the plugins.

import $ from 'jquery'
window.jQuery = window.$ = $
import JSZip from 'jszip'
window.JSZip = JSZip
import 'pdfmake'
import dataTable from 'datatables.net-bs4'
dataTable(window, $)
import buttons from 'datatables.net-buttons-bs4'
buttons(window, $)
import columnVisibility from 'datatables.net-buttons/js/buttons.colVis.js'
columnVisibility(window, $)
import buttonsHtml5 from 'datatables.net-buttons/js/buttons.html5.js'
buttonsHtml5(window, $)
import buttonsPrint from 'datatables.net-buttons/js/buttons.print.js'
buttonsPrint(window, $)
import colReorder from 'datatables.net-colreorder-bs4'
colReorder(window, $)
import fixedColumns from 'datatables.net-fixedcolumns-bs4'
fixedColumns(window, $)
import scroller from 'datatables.net-scroller-bs4'
scroller(window, $)

I do not use webpack, but esbuild to bundle the JavaScript output.

In Chrome's inspector $ is an alias to document.querySelectorAll when something else hasn't already used $ (e.g. jQuery).

So without window.jQuery = window.$ = $ the above isn't building for you? Can you create a minimal repo reproducing that so I can take a look into it please?

Allan

Thanks for your answer!

jQuery is automatically provided through the following piece of code:

new webpack.ProvidePlugin({
  $: 'jquery',
  jQuery: 'jquery'

I have tried different variations by playing around with the plugins and optimization options (by following what is written here) without success...
I have also tried to to set globally jQuery as you did but that didn't change a thing. :(

For now I do create the bundle in development mode but that's not clean and it's annoyed me a little to not understand what's wrong...

I will try to create a minimal repo it seems better this way and much easier for everyone.

I have just finished the MOCK but it is working on it... :s
I will have another look on my main project to try again and find where I have an error...

I will find it...
"veni vidi vici" has he said... There is still some work for the vici part though.

I have finally found where was the error and has usual it was completely my fault...
but difficult to find because somewhere unexpected (for me at least).

So in fact the "only" error which was causing this was because as I am learning webpack I read the tree-shaking section of the manual and for some reason I copy and past a part of it in my package.json...

"sideEffects": false

Which was obviously a bad idea/error since everything is not in es6 in my modules (such as datatables but not only).

Thanks everyone for your help!

I got the same error and was able to resolve it after reading https://datatables.net/forums/discussion/32542/datatables-and-webpack

The solution was #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.

So inside my application.js, I have

// require datatables without invoking or passing arguments to make it work with webpack
require('datatables.net');
require('datatables.net-bs4');
require('datatables.net-responsive');
require('datatables.net-responsive-bs4');
				DataTables designed and created by SpryMedia Ltd.
© 2007-2023 MIT licensed. Privacy policy. Supporters.