Rails,webpacker:在哪里/何时在类中使用import语句,以及pack / application.js中要求的目的是什么?

问题描述 投票:0回答:1

我正在将较旧的应用程序升级到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",它都没有区别。

问题

我正试图了解正在发生的事情。

  1. 我需要在require("pikaday")文件中添加import Pikaday from "pikaday"还是app/javascript/pack/application.js?为什么或为什么不呢?

  2. 我熟悉全局变量不好的原则,应该避免使用,但是有没有一种方法可以避免必须在引用它的每个JS文件上使用import CLASS from "class_file"?在我的示例中,我想在多个地方使用Datepicker类。我问的原因是因为我有10多个这样的类,在每个要使用这些JS文件的顶部都有10多个import语句有点令人讨厌。我总是想要某些类进入。我已经使用了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")
javascript es6-modules webpacker ruby-on-rails-6
1个回答
0
投票

您问了几个问题:

  1. 您仅在引用导入变量import Pikaday from 'pikaday'的文件中需要Pikaday。在这种情况下,只需要在自定义datepicker模块中进行此导入。您可以从application.js包文件中删除require("pikaday")

    原因是Webpack将把您的application.js包作为依赖关系图的入口点;从那里开始,它将递归地遍历每个必需/导入的模块,找到那些模块的依赖关系,依此类推,直到捆绑包中包括所有声明的模块。由于您已经在application.js包中声明了import 'custom/datepicker',并且自定义datepicker导入了pikaday,因此它将作为依赖项包含在捆绑软件中。

  2. 您的自定义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

© www.soinside.com 2019 - 2024. All rights reserved.