【问题标题】:Dynamically loading a file based on an environment variable in Webpacker (Rails 6)在 Webpacker (Rails 6) 中基于环境变量动态加载文件
【发布时间】:2020-07-22 14:31:46
【问题描述】:

我第一次在 Stack Overflow 上,请善待;)我会尽力而为!

上下文:

我正在使用 webpacker 开发 Rails 6 应用程序。这是一个将由多家公司共享的程序,为了应用“一个代码,多个设置”范例,我们决定将所有与公司相关的配置文件移动到单独的文件夹中,并将公司名称作为变量放入我们的 .env 文件。我们需要更改一些配置变量以及一些地理围栏数据(以便我们的客户可以创建一个新的交付到某个地址)。基本上是这样的:

Project folder 
| config 
  | companies
    | a_first_company
      | rails_config.rb
      | geofencing.js
    | a_second_company
      | rails_config.rb
      | geofencing.js
    | ....

在 .env 文件中:

COMPANY=a_first_company

在 rails 配置 (application.rb) 中,我们使用的是简单的:

require_relative "companies/#{ENV['COMPANY']}/rails_config"

但是现在,JS 部分来了!我遇到了麻烦。

问题:

我想在现有脚本中动态包含 JSON 对象。示例geofencing.js 如下所示:

module.exports = {
  "countries": ["be"],
  "polygon": [
    50.8917729, 4.3004608,
    ...
    50.9162381, 4.3450928,
    50.8917729, 4.3004608
  ]
}

我正在尝试将其作为geofencing 变量导入我现有的地址自动完成脚本中:

/app/javascript/plugins/places.js

// I know it doesn't work that way, but basically that what I would like to do:
const geofencing = require(`/config/companies/${process.env.COMPANY}/geofencing`);
...

const initPlaceAutocomplete = () => {
  
    ...

    var placesAutocomplete = places(
            {
                // And use the variable here...
                insidePolygon: [geofencing.polygon],
                type: 'address',
                // And there...
                countries: geofencing.countries,
                templates: {
                    value: (suggestion) => {
                        return suggestion.name;
                    }
                },
                container: addressInput
            }
        );

     ...
}

export { initPlaceAutocomplete };

这个文件被导入到视图中,带有<%= javascript_pack_tag 'delivery_new' %>:

/app/javascript/packs/delivery_new.js

import { initPlaceAutocomplete } from '../plugins/places';
initPlaceAutocomplete();

...

解决方案(我还没有找到):

我尝试了几件事,比如在 webpack 配置 (/config/webpack/environment.js) 中导入文件,就像在 the ProvidePlugin documentation 中一样:

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

environment.plugins.prepend('Provide',
    new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        Popper: ['popper.js', 'default'],
        geofencing: path.resolve(path.join(__dirname, '..', '..', 'config', 'companies', process.env['COMPANY'], 'geofencing'))
    })
)

module.exports = environment

...但是没有用。

我还尝试了多个地方在多个地方导入“地理围栏”,在 Chrome 控制台中始终得到相同的结果:Uncaught ReferenceError: geofencing is not defined

不过,我注意到我可以访问 places.js 脚本中的 process.env 变量:当我在 Chrome 中重新加载页面时,在文件中写入 console.log(process.env['COMPANY']); 会提示我在开发控制台中输入公司名称。

除此之外,我不得不说我迷路了。我基本上是 Webpack '魔法' 的新手 ;)

如果您需要有关我的设置的更多信息,请告诉我。

提前感谢您的帮助!

【问题讨论】:

    标签: javascript ruby-on-rails webpack ruby-on-rails-6 webpacker


    【解决方案1】:

    您应该能够在类似于您的示例的 require() 表达式中使用插值来要求模块。尝试使用相对路径,例如(假设父目录是兄弟):

    require(`../config/${process.env.COMPANY}/geofencing`)
    

    上述表达式将将 COMPANY 地理围栏模块添加到包中。

    如果你希望这是动态的,webpack 可以在运行时解析插值,假设 require 路径的范围是一个目录;您已经在这里使用“../config/”执行此操作。因此,webpack 将在包中包含 所有 COMPANY 地理围栏模块。至于用法,我可能会在函数内部移动 require 语句:

    function initPlaceAutocomplete(company) {
      const geofencing = require(`../config/${company}/geofencing`)
      // ...
    }
    
    // usage
    import { initPlaceAutocomplete } from "../plugins/places"
    initPlaceAutocomplete(process.env.COMPANY)
    

    此时,这可能是 dynamic imports 的一个很好的用例,即 webpack 支持 TC39 proposal for dynamically loading modules at runtime

    您可以使用import() 函数语法来代替require("../config...")。与require() 不同,import() 函数语法是异步解析的。

    现在 webpack 将捆绑所有 COMPANY 地理围栏模块,但作为单独的“块”来保持初始脚本的大小。 webpack 将在运行时插入代码以异步解析这些“块”。为了支持这一点,import() 表达式返回一个 Promise,因此,我在这里使用 async/await 语法。

    async function initPlaceAutocomplete(company) {
      const geofencing = await import(`../companies/${company}/config`)
      
      // ...
    }
    

    【讨论】:

    • 非常感谢您的建议!我刚刚有时间回到这个问题,你的解决方案对我有用:)(至少使用require(),我稍后会尝试使用import())。
    猜你喜欢
    • 2016-01-17
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    • 2015-03-28
    • 2020-09-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-19
    相关资源
    最近更新 更多