我正在寻找一种方法来在我的开发机器上使用Laravel Mix构建我的资产,然后匹配生产中的参数。
例如,我的API有一个基本网址,本地开发为http://foo.test/api/v1
,生产服务器为https://foo.com/api/v1
。
所以在我的客户端代码中(例如http.js
)我想做这样的事情:
Vue.axios.defaults.baseURL = API_BASE_URL;
当我运行API_BASE_URL
或http://foo.test/api/v1
运行npm run dev
时,https://foo.com/api/v1
应该被npm run prod
替换。
我已经尝试了以下不起作用的方法。
webpack.mix.js
mix.webpackConfig(webpack => {
return {
plugins: [
new webpack.DefinePlugin({
API_BASE_URL: JSON.stringify('https://foo.com/api/v1'),
})
]
}
});
然后在 http.js
Vue.axios.defaults.baseURL = API_BASE_URL;
这编译为:
Object({"NODE_ENV":"production"}).API_BASE_URL;
我也尝试使用此process.env.API_BASE_URL
方法。
答案 0 :(得分:7)
有点晚了,我不知道它是否仍然适用,但我们可能不是唯一想要这个的人。 我花了很多时间在这上面,试图找出确切的问题。我将在这里分享我的故事,希望其他人可以避免浪费时间。
传递给客户端应用程序的内容基本上是process.env
的内容。
Laravel Mix试图保护您免于暴露整个.env
(通过dotenv
加载)
过滤变量并仅允许以MIX_
开头的变量。
此行为来自MixDefinitionsPlugin
。
组装webpack配置时,首先放置自定义插件,然后放置混合插件。
这意味着MixDefinitionsPlugin
将始终拥有最后一个字。
如果您可以使用该限制,那么一个简单的解决方案就是:
在.env
中添加以下内容:
MIX_API_URL=http://foo.test/api/v1
当您重新编译资产时,您将在客户端获得process.env.MIX_API_URL
。
就这么简单。
顺便说一下,因为使用dotenv-expand
加载你甚至可以使用其他变量(例如,如果你的api已经设置为后端):
MIX_API_URL=${API_URL}
如果您想为生产变体执行此操作,则最少量的麻烦(暂时)将您的.env
文件替换为生产文件。
只需创建一个shell脚本来构建生产变体:
.env
替换为您的作品.env
。npm run production
。.env
完成。还有第二个解决方案,它更加丑陋,但我更喜欢它,请继续阅读:)
我对此并不满意,因为我只想运行npm run production
并且它会起作用,所以我看得更远。
由于在javascript转换时仅使用最后定义的process.env
,因此最接近该插件的插件获胜。
如上所述,这是MixDefinitionsPlugin,你无能为力。
如果考虑其他几种方法来完成我们想要的事情
(除了替换.env的脚本,这是我能找到的唯一可行解决方案)
Mix在完成加载后立即以插件作为参数发出“loading-plugins”事件。 这意味着您将获得一组非常准备且非常漂亮的插件,这些插件即将发送到webpack。
最初我试图在数组的末尾推送一个插件,但是那个只在转换后执行,这样就什么也得不到了。 另一种方法是找出插件所在的位置并使用它。 如果您可以在那里修改其内容,理论上可以“动态”添加值,这些也将在您的浏览器中结束。 这就是我做的。
基本上归结为以下几点:
if (mix.inProduction()) {
Mix.listen('loading-plugins', plugins => {
const _ = require('lodash');
let define = _.find(plugins, plugin => {return plugin.constructor.name === 'DefinePlugin'});
define.definitions['process.env'].MIX_API_URL = 'http://foo.com/api/v1';
});
}
(注意我们在这里寻找一个DefinePlugin而不是MixDefinitionsPlugin,因为它已经完成了它的工作)
由于您可以在此处添加所需内容而无需使用MIX_
- 前缀,因此您也可以在此设置API_URL:
Mix.listen('loading-plugins', plugins => {
const _ = require('lodash');
let define = _.find(plugins, plugin => {return plugin.constructor.name === 'DefinePlugin'});
define.definitions['process.env'].API_URL = mix.inProduction() ?
'http://foo.com/api/v1' : 'http://foo.test/api/v1';
});
您还可以在此处加载另一个.env文件(通过dotenv.config()
)并将其合并到定义中,天空是限制。
.env
的其他名称?我想到的其他事情。
MixDefinitionsPlugin构造函数允许这种可能性(function MixDefinitionsPlugin(envPath)
),遗憾的是实际实现没有:
return new webpack.DefinePlugin(
new MixDefinitionsPlugin().getDefinitions(merge)
);
所以没有这样的运气,这是无法使用的。
接下来检查我是否可以使用生产.env
文件创建不同的文件夹。
Mix有一个存储根的Paths
对象。所以这里的想法是存储我的替代.env
在子目录中,更新root和presto。
Mix.paths.setRootPath(Mix.paths.root('./resources/assets/production'));
这适用于.env
,但它打破了很多其他事情。根用作webpack的上下文,如
purify-css插件的配置(css清理vue和刀片文件),最重要的是它还会破坏url加载器。
不要去这里(除非你想拦截webpack配置并在任何地方恢复root,不值得)
所以这里结束了我生命中大约5个小时的故事。 我远远不是一个javascript专家,所以也许我已经犯了错误或错过了东西,但这是我的故事:)