在 Webpacker 中根据环境变量动态加载文件 (Rails 6)
Dynamically loading a file based on an environment variable in Webpacker (Rails 6)
我第一次使用 Stack Overflow,请多多关照 ;) 我会尽力而为!
上下文:
我正在使用 webpacker 开发 Rails 6 应用程序。这是一个将由几家公司共享的程序,为了应用 'one code, multiple setups' 范式,我们决定将所有与公司相关的配置文件移动到单独的文件夹中,并将公司名称作为变量放在我们的 .环境文件。我们需要更改一些配置变量以及一些地理围栏数据(以便我们的客户可以创建到某个地址的新交付)。基本上这就是它的样子:
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
...但是没用
我也尝试在不同的地方导入 'geofencing',在 Chrome 控制台中总是得到相同的结果:Uncaught ReferenceError: geofencing is not defined
.
不过,我注意到我可以访问 places.js
脚本中的 process.env
变量:在文件中写入 console.log(process.env['COMPANY']);
时会提示我在开发控制台中输入公司名称我在 Chrome.
中重新加载页面
除此之外,我不得不说我迷路了。我基本上是 Webpack 的新手 'magic' ;)
如果您需要有关我的设置的更多信息,请告诉我。
在此先感谢您的帮助!
您应该能够要求模块在类似于您的示例的 require()
表达式中使用插值。尝试使用相对路径,例如(假设父目录是兄弟目录):
require(`../config/${process.env.COMPANY}/geofencing`)
以上表达式将仅 COMPANY 地理围栏模块添加到包中。
如果你希望它是动态的,webpack 可以在运行时解析插值,假设需要的路径被限定在一个目录范围内;您已经在此处使用“../config/”执行此操作。因此,webpack 将在捆绑包中包含 all COMPANY 地理围栏模块。至于用法,我可能会将 require 语句移到函数中:
function initPlaceAutocomplete(company) {
const geofencing = require(`../config/${company}/geofencing`)
// ...
}
// usage
import { initPlaceAutocomplete } from "../plugins/places"
initPlaceAutocomplete(process.env.COMPANY)
在这一点上,这可能是 dynamic imports, i.e., webpack supports the TC39 proposal for dynamically loading modules at runtime 的一个很好的用例。
您可以使用 import()
函数语法代替 require("../config...")
。与 require()
不同,import()
函数语法是异步解析的。
现在 webpack 将捆绑所有 COMPANY 地理围栏模块,但作为单独的“块”以减少初始脚本的大小。 webpack 将插入代码以在运行时异步解析这些“块”。为了支持这一点,import() 表达式 returns 是一个 Promise,所以我在这里使用 async/await 语法作为结果。
async function initPlaceAutocomplete(company) {
const geofencing = await import(`../companies/${company}/config`)
// ...
}
我第一次使用 Stack Overflow,请多多关照 ;) 我会尽力而为!
上下文:
我正在使用 webpacker 开发 Rails 6 应用程序。这是一个将由几家公司共享的程序,为了应用 'one code, multiple setups' 范式,我们决定将所有与公司相关的配置文件移动到单独的文件夹中,并将公司名称作为变量放在我们的 .环境文件。我们需要更改一些配置变量以及一些地理围栏数据(以便我们的客户可以创建到某个地址的新交付)。基本上这就是它的样子:
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
...但是没用
我也尝试在不同的地方导入 'geofencing',在 Chrome 控制台中总是得到相同的结果:Uncaught ReferenceError: geofencing is not defined
.
不过,我注意到我可以访问 places.js
脚本中的 process.env
变量:在文件中写入 console.log(process.env['COMPANY']);
时会提示我在开发控制台中输入公司名称我在 Chrome.
除此之外,我不得不说我迷路了。我基本上是 Webpack 的新手 'magic' ;)
如果您需要有关我的设置的更多信息,请告诉我。
在此先感谢您的帮助!
您应该能够要求模块在类似于您的示例的 require()
表达式中使用插值。尝试使用相对路径,例如(假设父目录是兄弟目录):
require(`../config/${process.env.COMPANY}/geofencing`)
以上表达式将仅 COMPANY 地理围栏模块添加到包中。
如果你希望它是动态的,webpack 可以在运行时解析插值,假设需要的路径被限定在一个目录范围内;您已经在此处使用“../config/”执行此操作。因此,webpack 将在捆绑包中包含 all COMPANY 地理围栏模块。至于用法,我可能会将 require 语句移到函数中:
function initPlaceAutocomplete(company) {
const geofencing = require(`../config/${company}/geofencing`)
// ...
}
// usage
import { initPlaceAutocomplete } from "../plugins/places"
initPlaceAutocomplete(process.env.COMPANY)
在这一点上,这可能是 dynamic imports, i.e., webpack supports the TC39 proposal for dynamically loading modules at runtime 的一个很好的用例。
您可以使用 import()
函数语法代替 require("../config...")
。与 require()
不同,import()
函数语法是异步解析的。
现在 webpack 将捆绑所有 COMPANY 地理围栏模块,但作为单独的“块”以减少初始脚本的大小。 webpack 将插入代码以在运行时异步解析这些“块”。为了支持这一点,import() 表达式 returns 是一个 Promise,所以我在这里使用 async/await 语法作为结果。
async function initPlaceAutocomplete(company) {
const geofencing = await import(`../companies/${company}/config`)
// ...
}