在 Rails 6 中使 jQuery UI 全局函数可用于 webpack

Make jQuery UI global functions available with webpack in Rails 6

jQuery UI 具有全局可用的便捷功能,例如Sine、Circ、Elastic、Back、Bounce 等。但是当使用 webpack 包含 jQuery UI 时,全局函数变得不可用。以下代码失败:

function setup_sidebar_menu()
{
    var $ = jQuery,
        $items_with_submenu   = public_vars.$sidebarMenu.find('li:has(ul)'),
        submenu_options       = {
            submenu_open_delay: 0.25,
            submenu_open_easing: Sine.easeInOut,
            submenu_opened_class: 'opened'
        },
        root_level_class      = 'root-level',
        is_multiopen          = public_vars.$mainMenu.hasClass('multiple-expanded');

因为正弦未定义。使用 webpack 时,有什么方法可以使这些 jQuery UI 函数全局可用?例如,$ 是全局可用的,jQuery 也是全局可用的。 $.ui 也可用。

配置如下:

environment.js

const { environment } = require('@rails/webpacker')

const webpack = require('webpack')
environment.plugins.prepend('Provide', new webpack.ProvidePlugin({
    $: 'jquery',
    JQuery: 'jquery',
    jQuery: 'jquery',
    jquery: 'jquery',
    'window.Tether': "tether",
    Popper: ['popper.js', 'default'], // for Bootstrap 4
}))

module.exports = environment

application.js

var jQuery = require("jquery")
// import jQuery from "jquery";
global.$ = global.jQuery = jQuery;
window.$ = window.jQuery = jQuery;

import 'webpack-jquery-ui'

如我所说,jQueryUI 库已正确加载并可通过 $.ui 访问,问题涉及全局函数。

更新: 看起来正确的解决方案是在 packs 目录中从头开始创建新的 js 脚本文件并重新编写有效的 ES6 / ES7。这种方法出现的问题是无法导入 jquery-ui 全局函数 Sine、Circ、Elastic、Back、Bounce:

全部失败,Sine 和任何其他类似的全局函数始终未定义:

import {Sine} from 'jquery-ui/ui/effect'
// or
import {Sine} from 'jquery-ui'
// or 
import {Sine} from 'webpack-jquery-ui'

console.log(Sine)

这里有什么问题?

你可能不想听到这个,但我的感觉是你在某种程度上违背了模块化的一般精神 javascript,这并不意味着(作为一项功能)鼓励像这样的全局代码。

你或许可以让它工作,但它看起来很像一种“老派”的编写 JS 的方法,其中库在全球范围内可用。

过去,当我真的需要一些全局的东西时,我会在 window 上创建一个对象,比如 JS 链顶部的 window.APP = {},然后把我真正需要的东西放在那里想要成为全球性的,就像一个事件发射器,以及来自服务器的 ENV 信息。我不知道我是否会推荐这种方法,我觉得代码有点臭,但我仍然在几个应用程序中这样做了。

但我的一般感觉是你在这里感受到的痛苦是与谷物背道而驰。并不意味着您不应该这样做,但不妨让您停下来考虑一下还有什么办法可以做到这一点。

也许你应该把它放在 /packs 中它自己的文件中并导入 Sine?

就是说,虽然我自己没有使用过,但我已经看到这可能有效:

import $ from 'jquery';
import 'jquery-ui-bundle';
import 'jquery-ui-bundle/jquery-ui.min.css';

这可能会在 $ 上添加 Sine?

正确的方法是在 packs 目录中定义一个新模块,然后在 ES6 中复制粘贴或重新编写所有需要的全局 jQuery-UI 函数。从该模块导出函数,然后将其导入到使用它的模块中。 例如,我创建了具有先前全局 jQuery-UI 函数的 ES6 模块:

app/javascript/packs/jquery-ui-es6-migrations.js

const Sine = (p) => {
  return 1 - Math.cos( p * Math.PI / 2 );
}

const Circ = (p) => {
  return 1 - Math.sqrt( 1 - p * p );
}

const Elastic = (p) => {
  return p === 0 || p === 1 ? p :
    -Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 );
}

const Back = (p) => {
  return p * p * ( 3 * p - 2 );
}

const Bounce = (p) => {
  var pow2,
    bounce = 4;

  while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
  return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
}

export {Sine, Circ, Elastic, Back, Bounce}

在另一个 ES6 模块中简单地导入这些函数:

import {Sine, Circ, Elastic, Back, Bounce} from './jquery-ui-es6-migrations'

就是这样。一切都很顺利!