我正在将较旧的应用程序升级到Rails 6,它将使用webpacker
进行所有JS资产管理。
我正在使用pikaday
日历库,并已通过yarn add pikaday
将其添加,验证它是否显示在packages.json
中,然后通过app/javascript/packs/application.js
将其添加到我的require("pikaday")
中。
我有一个名为Datepicker
的JS类,我正在使用该类抽象实际的pikaday
日历。之所以这样做,是因为有一天我可能会更改datepicker的实现,这样,我只需要更改一个类,而不用更新所有的pikaday
调用即可。
但是,我是否require("pikaday")
打包文件中的application.js
似乎无关紧要;只要我要在其中引用它的类中的import Pikaday from "pikaday"
,它都没有区别。
问题
我正试图了解正在发生的事情。
我需要在require("pikaday")
文件中添加import Pikaday from "pikaday"
还是app/javascript/pack/application.js
?为什么或为什么不呢?
我熟悉全局变量不好的原则,应该避免使用,但是有没有一种方法可以避免必须在引用它的每个JS文件上使用import CLASS from "class_file"
?在我的示例中,我想在多个地方使用Datepicker
类。我问的原因是因为我有10多个这样的类,在每个要使用这些JS文件的顶部都有10多个import
语句有点令人讨厌。我总是想要某些类进入。我已经使用了webpacker ProvidePlugin功能,但是它抱怨Datepicker
不是构造函数,因此我可能缺少了一些东西,但是我没有足够的知识来知道什么。
import Pikaday from "pikaday"
export default class Datepicker {
constructor(element, options) {
if (options == null) { options = {} }
// Store DOM element for reference
this.element = element
// Do not re-run on elements that already have datepickers
if (this.element.datepicker === undefined) {
options = Object.assign({},
this.defaultOptions(),
options
)
const picker = new Pikaday(options)
// Store picker on element for reference
this.element.datepicker = picker
return picker
} else {
console.log("Datepicker already attached")
return
}
}
// Overridden by `options` in constructor
defaultOptions() {
return {
field: this.element,
format: "M/D/YYYY",
bound: true,
keyboardInput: false,
showDaysInNextAndPreviousMonths: true
}
}
}
require("@rails/ujs").start()
require("turbolinks").start()
require("moment")
// Note: if using `@rails/ujs`, you do not need to use `jquery-ujs`.
import "jquery"
// Does not matter if I require this or not, as long as it is imported in the
// class file, I can remove this require statement and everything still works.
require("pikaday")
// StimulusJS
// Webpack's `require` looks for `controllers/index.js` by default
require("controllers")
require("custom/datepicker")
您问了几个问题:
您仅在引用导入变量import Pikaday from 'pikaday'
的文件中需要Pikaday
。在这种情况下,只需要在自定义datepicker模块中进行此导入。您可以从application.js包文件中删除require("pikaday")
。
原因是Webpack将把您的application.js包作为依赖关系图的入口点;从那里开始,它将递归地遍历每个必需/导入的模块,找到那些模块的依赖关系,依此类推,直到捆绑包中包括所有声明的模块。由于您已经在application.js包中声明了import 'custom/datepicker'
,并且自定义datepicker导入了pikaday
,因此它将作为依赖项包含在捆绑软件中。
您的自定义Datepicker
被编译为ES模块(而是Webpack的ES模块的实现),因为您正在使用ES模块语法export default ...
。这对于ProvidePlugin的工作方式很重要。从Webpack 4 documentation of ProvidePlugin
:
要导入ES2015模块的默认导出,必须指定模块的默认属性。
这意味着您的ProvidePlugin
插件条目的Webpack配置看起来像这样(使用Rails Webpacker环境api:]
Datepicker
Opinion:那是说,我鼓励您明确输入,例如每个引用了const { environment } = require('@rails/webpacker')
const webpack = require('webpack')
const {resolve} = require('path');
environment.plugins.append('Provide', new webpack.ProvidePlugin({
Datepicker: [resolve('app/javascript/custom/datepicker'), 'default']
}))
module.exports = environment
的模块中的import Datepicker from 'custom/datepicker'
。即使是重复的,与诸如ESlint之类的工具进行集成也将变得更加容易,该工具可以通过某些代码编辑器提供有关编译错误的内联反馈-更加容易在每个模块中声明的显式依赖项进行设置。
我在此处使用您的自定义Datepicker和ProvidePlugin编写了Pikaday的工作演示,Datepicker