今天在处理项目的时候,需要引入一个 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 下了。
总结: