Rails, webpacker: where/when 在类中使用import语句,在pack/application.js中require的目的是什么?
Rails, webpacker: where/when to use the import statement in classes, and what's the purpose of requiring in the pack/application.js?
我正在将旧应用程序升级到 Rails 6,它使用 webpacker
进行所有 JS 资产管理。
我正在使用 pikaday
日历库,并已通过 yarn add pikaday
添加它,验证它显示在 packages.json
中,然后将其添加到我的 app/javascript/packs/application.js
通过 require("pikaday")
.
我有一个名为 Datepicker
的 JS class,我用它来抽象实际的 pikaday
日历。我这样做是因为有一天我可能会更改日期选择器的实现,这样我只需要更改一个 class 而不是更新我所有的 pikaday
调用。
不过,我在application.js
包文件里是否require("pikaday")
似乎并不重要;只要我在 class 中引用它 import Pikaday from "pikaday"
,就没有区别。
问题
我正在尝试了解正在发生的事情。
我需要在 app/javascript/pack/application.js
文件中添加 require("pikaday")
或 import Pikaday from "pikaday"
吗?为什么或为什么不?
我很熟悉全局变量不好并且应该避免的原则,但是有没有办法避免在每个引用它的 JS 文件上都必须 import CLASS from "class_file"
?在我的示例中,我想在多个地方使用 Datepicker
class。我问的原因是因为我有 10+ class 这样的,在我想使用这些的每个 JS 文件的顶部有 10+ import
语句有点烦人。那里某些 class 是我一直想访问的。我玩过 webpacker ProvidePlugin 功能,但它抱怨 Datepicker
不是构造函数,所以我可能遗漏了一些东西,但我没有足够的知识知道什么。
app/javascript/custom/datepicker.js
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
}
}
}
app/javascript/packs/application.js
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
。在这种情况下,您只需要在自定义日期选择器模块中进行此导入。您可以从 application.js 包文件中删除 require("pikaday")
。
原因是 Webpack 会将您的 application.js 包作为 依赖关系图 的入口点;从那里开始,它将递归遍历每个 required/imported 模块,找到这些模块的依赖关系,依此类推,直到所有声明的模块都包含在包中。由于您在 application.js 包中声明了 import 'custom/datepicker'
,并且自定义日期选择器导入 pikaday
,它将作为依赖项包含在包中。
您的自定义 Datepicker
被编译为 ES 模块(而不是 Webpack 的 ES 模块实现),因为您使用的是 ES 模块语法 export default ...
。这对于 ProvidePlugin 的工作方式很重要。来自 Webpack 4 documentation of ProvidePlugin
:
For importing the default export of an ES2015 module, you have to specify the default property of module.
这意味着 Datepicker
的插件条目的 Webpack 配置看起来像这样(使用 Rails Webpacker 环境 api):
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'
在引用 Datepicker
的每个模块中。即使重复,与 ESlint 等工具集成也会变得容易得多,ESlint 与某些代码编辑器一起,可以提供有关编译错误的内联反馈——在每个模块中声明显式依赖项更容易设置。
我在这里使用自定义日期选择器和 ProvidePlugin 组合了一个 Pikaday 的工作演示:https://github.com/rossta/rails6-webpacker-demo/commit/be3d20107c2b19baa8b9560bce05e0559f90086d
我正在将旧应用程序升级到 Rails 6,它使用 webpacker
进行所有 JS 资产管理。
我正在使用 pikaday
日历库,并已通过 yarn add pikaday
添加它,验证它显示在 packages.json
中,然后将其添加到我的 app/javascript/packs/application.js
通过 require("pikaday")
.
我有一个名为 Datepicker
的 JS class,我用它来抽象实际的 pikaday
日历。我这样做是因为有一天我可能会更改日期选择器的实现,这样我只需要更改一个 class 而不是更新我所有的 pikaday
调用。
不过,我在application.js
包文件里是否require("pikaday")
似乎并不重要;只要我在 class 中引用它 import Pikaday from "pikaday"
,就没有区别。
问题
我正在尝试了解正在发生的事情。
我需要在
app/javascript/pack/application.js
文件中添加require("pikaday")
或import Pikaday from "pikaday"
吗?为什么或为什么不?我很熟悉全局变量不好并且应该避免的原则,但是有没有办法避免在每个引用它的 JS 文件上都必须
import CLASS from "class_file"
?在我的示例中,我想在多个地方使用Datepicker
class。我问的原因是因为我有 10+ class 这样的,在我想使用这些的每个 JS 文件的顶部有 10+import
语句有点烦人。那里某些 class 是我一直想访问的。我玩过 webpacker ProvidePlugin 功能,但它抱怨Datepicker
不是构造函数,所以我可能遗漏了一些东西,但我没有足够的知识知道什么。
app/javascript/custom/datepicker.js
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
}
}
}
app/javascript/packs/application.js
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
。在这种情况下,您只需要在自定义日期选择器模块中进行此导入。您可以从 application.js 包文件中删除require("pikaday")
。原因是 Webpack 会将您的 application.js 包作为 依赖关系图 的入口点;从那里开始,它将递归遍历每个 required/imported 模块,找到这些模块的依赖关系,依此类推,直到所有声明的模块都包含在包中。由于您在 application.js 包中声明了
import 'custom/datepicker'
,并且自定义日期选择器导入pikaday
,它将作为依赖项包含在包中。您的自定义
Datepicker
被编译为 ES 模块(而不是 Webpack 的 ES 模块实现),因为您使用的是 ES 模块语法export default ...
。这对于 ProvidePlugin 的工作方式很重要。来自 Webpack 4 documentation ofProvidePlugin
:For importing the default export of an ES2015 module, you have to specify the default property of module.
这意味着
Datepicker
的插件条目的 Webpack 配置看起来像这样(使用 Rails Webpacker 环境 api):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'
在引用Datepicker
的每个模块中。即使重复,与 ESlint 等工具集成也会变得容易得多,ESlint 与某些代码编辑器一起,可以提供有关编译错误的内联反馈——在每个模块中声明显式依赖项更容易设置。
我在这里使用自定义日期选择器和 ProvidePlugin 组合了一个 Pikaday 的工作演示:https://github.com/rossta/rails6-webpacker-demo/commit/be3d20107c2b19baa8b9560bce05e0559f90086d