如何在运行时配置Nuxt.js环境变量的安装,或者如何做不像每个人都喜欢的事情并且不后悔


插图

高级网络开发人员Anton和Alexei继续讲述与Nuxt艰苦奋斗的故事。 在与此框架进行的上一轮抗争中 ,他们展示了如何在Nuxt上启动一个项目,以便每个人都很高兴。 在新文章中,我们将讨论框架的实际应用。

我们开始以巨大的技术债务来重写该项目。 每月的访问者为6-7百万唯一身份访问者,但是现有平台造成了太多问题。 因此,决定将她送去退休。 当然,性能是我们最大的担忧,但我也不想浪费SEO。

经过几轮讨论,他们决定不依赖仅使用服务器端渲染的传统方法-而不是将自己陷入客户端渲染中。 结果,我们开始构建基于Nuxt.js的解决方案。

好老的Nuxt.js


我们采用基于Vue.js的“框架框架” (在上一篇文章中已经为我们所知)来构建通用的客户端-服务器应用程序。 在我们的案例中,该应用程序与相当复杂的API(微服务的复杂性,但大约在其他时间)和多层缓存一起工作,它呈现可由编辑器编辑的内容,并返回已经静态的内容,以实现闪电般的快速性能。 太好了吧?

实际上,这里没有新内容。 但是使Nuxt.js变得有趣的是能够使用客户端-服务器渲染快速启动项目的能力。 有时您需要违背已建立的框架框架。 那就是我们所做的。

没有时间解释,一次构建,多次部署!


有一天,一个技术幻灯片接近我们并感到困惑:每当我们将更改推送到存储库时,我们都需要分别构建每个环境(开发环境,阶段环境和产品环境)。 太慢了 但是这些版本之间有什么区别? 是的,仅在环境变量中! 他要求做的事情听起来合情合理。 但是我们的第一个反应是:O_o

在软件开发领域,一次构建,部署多种策略是有意义的。 但是在Javascript世界中……我们拥有大量的编译器,编译器,预处理器和后处理器以及测试和查询器。 所有这些花费时间来为每个环境配置它们。 此外,还有许多潜在的机密数据泄漏问题(机密,API密钥等可以存储在配置中)。

然后我们开始


当然,我们首先从Google搜索开始。 然后,我们与Nuxt.js维护者进行了交谈,但是没有取得太大的成功。 怎么做-我不得不自己想出一个解决方案,而不是从StackOverflow复制它(这是我们活动的基础,对吗?)。

让我们弄清楚Nuxt.js是如何做到的。


Nuxt.js具有一个预期名称为nuxt.config.js的配置文件。 它用于以编程方式将配置传输到应用程序:

const config = require('nuxt.config.js') const nuxt = new Nuxt(config) 

可以通过env变量设置环境。 通常,一种相当普遍的做法是动态连接配置文件。 然后,所有这些都将传输到definePlugin Webpack并可以在客户端和服务器上使用,如下所示:

process.env.propertyName
//或
context.env.propertyName。

这些变量在组装过程中烘焙,有关更多信息,请参见Nuxt.js env页面
您是否注意到webpack? 是的,这意味着编译,而这不是我们想要的。

让我们尝试不同


了解Nuxt.js的工作方式对我们意味着:

  • 我们不能再在nuxt.config.js中使用env了;
  • 任何其他动态变量(例如,在head.meta内部)都应在运行时传递给nuxt.config.js对象。


服务器/ index.js中的代码:

 const config = require('../nuxt.config.js') 

更改为:

 //    Nuxt.js const config = require('./utils/extendedNuxtConfig.js').default 

其中utils / extendedNuxtConfig.js:

 import config from 'config' import get from 'lodash/get' //   Nuxt.js const defaultConfig = require('../../nuxt.config.js') //   const extendedConfig = {} //   Nuxt.js const nuxtConfig = { ...defaultConfig, ...extendedConfig } //     //       if (get(nuxtConfig, 'head.meta')) { nuxtConfig.head.meta.push({ hid: 'og:url', property: 'og:url', content: config.get('app.canonical_domain') }) } export default nuxtConfig 

我们甚至都没有注意到大象


好了,我们解决了从nuxt.config.js中配置对象的env属性外部获取动态变量的问题。 但是原来的问题仍然没有解决。

假设某些抽象的sharedEnv.js将用于:

  • 客户端-创建一个env.js文件,该文件将在全球范围内下载(window.env.envKey),
  • 服务器-必要时导入到模块中,
  • 同构代码,类似
    context.isClient? window.env [key]:global.sharedEnv [key]。

莫名其妙。 这种抽象将解决最严重的问题-机密数据泄漏到客户端应用程序中,因为有意识地增加价值是必要的。

Vuex将帮助我们


在调查问题时,我们注意到Vuex存储已导出到window对象。 该解决方案被迫支持Nuxt,js的同构。 Vuex是受Flux启发的数据仓库,专门为Vue.js应用程序设计。

好吧,为什么不将其用于我们的共享变量? 这是一种更有机的方法-全局存储库中的数据适合我们。

让我们从server / utils / sharedEnv.js开始:

 import config from 'config' /** *  ,      *  ,     *  ,       * * @type {Object} */ const sharedEnv = { // ... canonicalDomain: config.get('app.canonical_domain'), } export default sharedEnv 

上面的代码将在服务器启动期间执行。 然后将其添加到Vuex存储库中:

 /** *   . *        * .   * https://nuxtjs.org/guide/vuex-store/#the-nuxtserverinit-action * * @return {Object} Shared environment variables. */ const getSharedEnv = () => process.server ? require('~/server/utils/sharedEnv').default || {} : {} // ... export const state = () => ({ // ... sharedEnv: {} }) export const mutations = { // ... setSharedEnv (state, content) { state.sharedEnv = content } } export const actions = { nuxtServerInit ({ commit }) { if (process.server) { commit('setSharedEnv', getSharedEnv()) } } } 

我们将依靠这样的事实,即在服务器初始化期间启动nuxtServerInit。 有一些困难:注意getSharedEnv方法,此处添加了在服务器上重复执行检查的功能。

发生什么事了


现在我们有了可以从以下组件中提取的公共变量:
$ store.state.sharedEnv.canonicalDomain

胜利了!

哦不 插件呢?


一些插件需要环境变量来配置。 当我们想使用它们时:
Vue.use(MyPlugin,{someEnvOption:'无法访问vuex存储'})

很好的竞争条件是,Vue.js会在Nuxt.js在Vuex存储库中注册sharedEnvobject之前尝试初始化自身。

尽管注册插件的功能可以访问包含存储库链接的Context对象,但是sharedEnv仍然为空。 这很简单地解决了-让我们将插件设为异步函数,然后等待nuxtServerInit执行:

 import Vue from 'vue' import MyPlugin from 'my-plugin' /** *   MyPlugin . */ export default async (context) => { //  ,      sharedEnv await context.store.dispatch('nuxtServerInit', context) const env = { ...context.store.state.sharedEnv } Vue.use(MyPlugin, { option: env.someKey }) } 

现在是胜利。

Source: https://habr.com/ru/post/zh-CN429756/


All Articles