jQuery UI $(…).sortable is not a function with Web

2019-02-12 15:49发布

问题:

I believe I've set everything up correctly, but I'm getting an odd issue with Webpack.

Consider this simple app.ts file:

'use strict';

import $ = require('jquery');
import 'jquery-ui';

$(function() {
    $( "#sortable" ).sortable();
});

Everything compiles fine, but when the site is run it complains that the Uncaught TypeError: $(...).sortable is not a function. (sortable is a jQuery UI function).

Everything works fine when I instead link to a CDN hosted version of jQuery and jQuery UI, but it doesn't work when I use JS modules and Webpack. Why is this?

Why is the jQueryUI function sortable() not recognized?

回答1:

The problem is that jQuery UI normally automatically pulls in the components it needs (which is why it works when it's linked via a CDN), but that doesn't work when it's imported as a module (like with Webpack).

Thankfully as of jQuery UI 1.11 you can manually pull in any extra components you need like so:

'use strict';

import $ = require('jquery');

require('jquery-ui');
require('jquery-ui/ui/widgets/sortable');
require('jquery-ui/ui/disable-selection');

etc.

Here's some official documentation explaining this further.



回答2:

This answer is merely a summary of two helpfull other answers : Answer 1, Answer 2

First, better to know that jquery-ui-dist and jquery-ui-bundle are not maintained by the jquery-ui team. So you will probably want to avoid using it. Nevertheless, from jquery-ui version 1.11 you can require/import AMD, and from version 1.12 you can use the official package with npm.

Solution 1 :
The preferred way to go is then to import part of jquery-ui such as :

import 'jquery-ui/ui/widgets/draggable';

The only drawback is that if you previously used import 'jquery-ui', you now have to import each modules you want to use specifically. But this is better as it will only bundle the imports you really need.

Check the 1.11 AMD support documentation and the 1.12 npm documentation on their site.

Solution 2 :
But, if for any reason you want to use a single global jquery-ui import, you will have to adapt your webpack config:

First, ensure webpack knows about the jquery aliases :

...
plugins: [
    new webpack.ProvidePlugin({
      '$':'jquery',
      'jQuery':'jquery',
      'window.jQuery':'jquery',
      'global.jQuery': 'jquery'
    }),
...

Then, help webpack resolving the jquery-ui js location :

resolve : {
    alias: {
      // bind version of jquery-ui
      "jquery-ui": "jquery-ui/jquery-ui.js",      
      // bind to modules;
      modules: path.join(__dirname, "node_modules"),

Then, ensure the jquery-ui is loaded as soon as possible (maybe during startup ?)

var $ = require("jquery"),
        require("jquery-ui");

If you want to use a theme with jquery-ui, you will have to setup the css-loader and file-loader accordingly. (Don't forget to install those loaders):

module: {
    loaders: [
      { test: /\.css$/, loader: "style!css" },
      { test: /\.(jpe?g|png|gif)$/i, loader:"file" },

And below you imports of jquery and jquery-ui just add :

import 'modules/jquery-ui/themes/black-tie/jquery-ui.css';
import 'modules/jquery-ui/themes/black-tie/jquery-ui.theme.css';


回答3:

you use incorrect ES6 import syntax, but it still wouldn't work if it was right. sortable is not recognized because $ isn't avaliable inside jquery-ui module.

This solution isn't optimized because you import whole jquery-ui.

npm install --save jquery-ui-bundle

index.js

'use strict';

import 'jquery-ui-bundle';

$(function() {
    $( "#sortable" ).sortable();
});

webpack

  plugins: [
      new webpack.ProvidePlugin({
          $: 'jquery',
          jQuery: 'jquery',
          'window.jQuery': 'jquery',
          'window.$': 'jquery'
      })
  ]