JavaScript 解决在 webpacker 里引入 lightGallery 的问题

jicheng1014 · 2020年12月21日 · 最后由 xinyuewaisong 回复于 2021年01月02日 · 614 次阅读

今天在处理项目的时候,需要引入一个 lightGallery 的库,这个东西是 jquery 的一个插件,作用是点击放大图片,也可以支持左右选择,下载等。

因为是一个 rails 6.1 的项目,用的 webpacker 管理

遇到的第一个问题是 lightGallery 的 css 引入的问题,这个家伙引入了自己的 img 和 font,我如果直接在 scss 里引入

// @import 'lightgallery/dist/css/lightgallery.css';

在编译 js 的时候会报错,

ModuleNotFoundError: Module not found: Error: Can't resolve '../fonts/lg.svg?22t19m' in '/Users/atpking/ohio_about/ohio/app/javascript/packs/admin'

这种问题比较典型,是相对路径的引入错误 打开源码,发现这货是相对目录引入了 fonts img 等文件夹,在 webpacker 的这种处理方式下,就会出错。

解决这类问题其实都十分简单,有两种思路,第一就是在 /public 文件夹构建对应的相对目录,第二种是修正相对定位引用。

第一种可以迅速解决,但是缺乏灵活性,而且在以后升级的时候可能有问题,故选择第二种方案 我们查看 node_modules 的 lightgallery,发现 src 里有 sass, 里面包含了所有文件的引用

// Core variables and mixins
@import "lg-variables";
@import "lg-mixins";
@import "lg-fonts";
@import "lg-theme-default";
@import "lg-thumbnail";
@import "lg-video";
@import "lg-autoplay";
@import "lg-zoom";
@import "lg-pager";
@import "lg-fullscreen";
@import "lg-share";
@import "lg-rotate";

// Core
@import "lg-core";

打开 lg-variables,可以发现有句

// paths
$lg-path-fonts: '../fonts'!default;
$lg-path-images: '../img'!default;

这里可以看到作者给我们留下了 !default 的 path 变量, !default 意思为 之前如果没有这个变量,就赋值,如果有就忽略

于是我们可以在代码里先赋值这俩变量即可解决相对路径问题

$lg-path-images: '~lightgallery/src/img';
$lg-path-fonts: '~lightgallery/src/fonts';
@import '~lightgallery/src/sass/lightgallery.scss';

我以为我就这么解决了这个问题,然而继续运行之后,我遇到了第二个问题 运行页面,没有反映,之后再 chrome 控制台发现

TypeError: $(...).lightGallery is not a function

再次检查 application.js 看是否引入了 lightgallery 发现是引入了的,没问题


window.$ = jquery;
require('lightgallery/dist/js/lightgallery-all')
window.toastr = toastr;
var Turbolinks = require("turbolinks")
Turbolinks.start()
window.Turbolinks = Turbolinks;
document.addEventListener("turbolinks:load", function () {
  $("#body-content").lightGallery({
    selector: '.zoom-image',
    subHtmlSelectorRelative: true
  });
  ...

我猜想是因为在 webpack 编译的时候,因为 lightgallery 作为模块引入的时候,因为 webpack 的 module 的要求只对自己有可见域,没办法穿透自身的 module, 引入依赖 jquery

解决这个问题,仍然有俩方案,第一个方案,放弃从 application.js 引入 lightgallery,而是在 layout 的 application.html.erb 中,直接引入编译好的 js 即可

<%= javascript_pack_tag 'admin/application', 'data-turbolinks-track': 'reload' %>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/lightgallery.min.js"></script>

因为 application.js 已经确保了 jquery 被加载进来,且明确了 jquery 可以被全局访问,所以此时再加载 lightgallery 就没问题

另一种方式,是将 node_module 在编译的时候,打穿到 jquery 中,这里参看一些资料后,我取了个巧,我在 environment.js 里使用了 aliasconfig 来解决这个问题

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

const webpack = require('webpack')
environment.plugins.prepend('Provide', new webpack.ProvidePlugin({
  $: 'jquery/src/jquery',
  jquery: 'jquery/src/jquery',
  jQuery: 'jquery/src/jquery',
  Popper: ['popper.js', 'default']
}))

const aliasConfig = {
  'jquery': 'jquery/src/jquery',
  '$': 'jquery/src/jquery',

};

environment.config.set('resolve.alias', aliasConfig);


module.exports = environment

这样,在编译 lightgallery 的时候就可以顺利的加载 jquery 本身了(因为 $ 会被替换为 jquery/src/jquery 的内容)

经过一番折腾,lightgallery 即可顺利的跑在 webpacker 下了。

总结:

  1. 相对目录引用的问题,翻翻源码,一般都有收获
  2. 如果 npm 的组件有依赖,可以通过 aliasConfig 打穿 modules 的可见域的问题(好像 expose-loader 也可以解决这个问题,但是没研究)
jicheng1014 稍微折腾了一下 FontAwesome 提及了此话题。 12月26日 03:16

webpack 的各种项目之间的相互引用,实在是太麻烦了。

根源在于 webpack 没有 window 对象。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号