Laravel Mix / Webpack环境相关变量的客户端代码

Ric*_*old 2 webpack laravel-mix

我正在寻找一种在开发机器上使用Laravel Mix构建资产的方法,该方法随后将与生产中的参数匹配。

例如,我的API有一个基本URL,http://foo.test/api/v1用于本地开发和https://foo.com/api/v1生产服务器上。

因此,在我的客户代码(例如http.js)中,我想执行以下操作:

Vue.axios.defaults.baseURL = API_BASE_URL;
Run Code Online (Sandbox Code Playgroud)

现在,API_BASE_URL应该会被替换成http://foo.test/api/v1我运行时npm run devhttps://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'),
        })
      ]
   }
});
Run Code Online (Sandbox Code Playgroud)

然后在http.js中

Vue.axios.defaults.baseURL = API_BASE_URL;
Run Code Online (Sandbox Code Playgroud)

编译为:

Object({"NODE_ENV":"production"}).API_BASE_URL;

我也尝试过这种方法process.env.API_BASE_URL

Bli*_*izz 10

有点晚了,我不知道它是否仍然适用,但是我们可能不是唯一寻求此方法的人。我在此上花了很多时间,试图找出确切的问题。我将在这里分享我的故事,希望其他人可以避免浪费时间。

传递给您的客户端应用程序的基本上是的内容process.env。Laravel Mix试图通过过滤变量并只允许以开头的变量来保护您免于暴露整个.env(通过加载dotenvMIX_。此行为来自MixDefinitionsPlugin

组装webpack配置后,它将首先放置您的自定义插件,然后是mix插件。这意味着MixDefinitionsPlugin遗嘱永远是硬道理。

如果可以解决该限制,那么一个简单的解决方案是:

在您的中添加以下内容.env

MIX_API_URL=http://foo.test/api/v1
Run Code Online (Sandbox Code Playgroud)

重新编译资产时,您会process.env.MIX_API_URL在客户端看到一个。就这么简单。

顺便说一句,因为使用此方法加载,dotenv-expand您甚至可以使用其他变量(即,如果您的api已经设置为后端):

MIX_API_URL=${API_URL}
Run Code Online (Sandbox Code Playgroud)

如果要针对生产变体执行此操作,则麻烦最少的是(临时)将.env文件替换为生产文件。只需创建一个shell脚本来构建您的生产变体:

  • .env用您的生产替换开发.env
  • 运行npm run production
  • 恢复您的开发 .env

做完了 有第二种解决方案,它很丑陋,但我更喜欢它,请继续阅读:)


还在?

我对此并不满意,因为我只想能够运行npm run production并且可以运行,所以我往前看。

由于在process.env转译javascript时仅使用最后一个定义,因此最接近该插件的插件将获胜。如上所述,这是MixDefinitionsPlugin,您对此无能为力。

如果研究实现我们想要的其他几种方式

在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';
  });
}
Run Code Online (Sandbox Code Playgroud)

(请注意,我们正在这里查找DefinePlugin而不是MixDefinitionsPlugin,因为它已经完成了工作)

由于您可以在此处添加所需的内容而无需MIX_-prefix,因此您可以在此处为这两个都设置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';
});    
Run Code Online (Sandbox Code Playgroud)

您还可以在此处(通过dotenv.config())加载另一个.env文件,然后将其合并到定义中,天空是极限。

?的其他名称.env

我在想其他事情。

MixDefinitionsPlugin构造函数允许这种可能性(function MixDefinitionsPlugin(envPath)),不幸的是,实际的实现不允许:

return new webpack.DefinePlugin(
  new MixDefinitionsPlugin().getDefinitions(merge)
);
Run Code Online (Sandbox Code Playgroud)

因此,没有这种运气,这是无法使用的。

不同的文件夹?

接下来是检查是否可以用生产.env文件创建其他文件夹。

Mix有一个Paths存储根的对象。所以这里的想法是将我的替代.env存储在一个子目录中,更新根目录和presto。

Mix.paths.setRootPath(Mix.paths.root('./resources/assets/production'));
Run Code Online (Sandbox Code Playgroud)

这适用于.env,但会破坏很多其他功能。根用作webpack的上下文,用作purify-css插件的配置(vs和blade文件的cs清理),最重要的是,它也破坏了URL加载器。也不要去这里(除非您想拦截Webpack配置并在任何地方恢复根,这都不值得)

到此结束我大约5个小时的故事。我距离JavaScript专家不远,所以也许我犯了一些错误或遗漏的东西,但这是我的故事:)