簡體   English   中英

如何將動態導入與流星鏈接在一起?

[英]How can I chain dynamic imports with meteor?

我的用例

我在一個大型應用程序上工作,在該應用程序中,根據用戶角色,我加載/導入不同的模塊集。 這是一個流星應用程序,前端裝有Vue,vue-router和vue-i18n,但沒有像vuex這樣的商店。

每個模塊都有自己的路由,翻譯文件,API和UI。 這就是為什么在顯示主界面和導航之前,我需要檢查每個模塊及其翻譯是否已加載(否則,例如,與已卸載模塊相關的導航項標簽將不會被翻譯,或者本地化的路線將返回404) 。

是否有一種盡可能簡單的模式來確保所有內容都已加載?

我的代碼和邏輯

我的用例比使用Promise.all afaik所能實現的要復雜得多。

我試圖通過Promises.allthen()的組合來做出嵌套承諾。

總結起來,順序是:

  • 加載基本包
  • 登錄客戶端
  • 導入i18n語言文件(用於主捆綁包),然后導入每個模塊
  • 對於每個模塊, 加載其語言文件並將其合並到相關的i18n消息中之后,我需要加載模塊本身(本地化路由,UI ...)

主要裝載部分

Accounts.onLogin(function (user) {
    let userRoles = Roles.getRolesForUser(Meteor.userId())
    let promises = []
    let lang = getDefaultLanguage()
    promises.push(loadLanguageAsync(lang))
    this.modulesReady = false
    for (let role of userRoles) {
        switch (role) {
        case "user":
            import { loadUserLanguageAsync } from "/imports/user/data/i18n"
            promises.push(loadUserLanguageAsync(lang).then(import("/imports/user/")))
            break
        case "admin":
            import { loadAdminLanguageAsync } from "/imports/admin/data/i18n"
            promises.push(loadAdminLanguageAsync(lang).then(import("/imports/admin/")))
            break
        default:
            break
        }
    }

    return Promise.all(promises).then(function (values) {
        this.modulesReady = true // my green flag, attached to the window object
    })
})

主要語言加載功能

const loadedLanguages = []

// Load i18n
Vue.use(VueI18n)
export const i18n = new VueI18n()


export const getDefaultLanguage = () => {
    let storedLanguage = window.localStorage.getItem(
        Meteor.settings.public.brand + "_lang"
    )
    return Meteor.user() && Meteor.user().settings && Meteor.user().settings.language
        ? Meteor.user().settings.language
        : // condition 2: if not, rely on a previously selected language
        storedLanguage
            ? storedLanguage
            : // or simply the browser default lang
            navigator.language.substring(0, 2)
}
export const loadLanguage = (lang, langFile) => {
    console.log("LOAD LANGUAGE " + lang)

    // we store agnostically the last selected language as default, if no user is logged in.
    window.localStorage.setItem(
        Meteor.settings.public.brand + "_lang",
        lang
    )
    loadedLanguages.push(lang)
    if (langFile) {
        i18n.setLocaleMessage(lang, Object.assign(langFile))
    }
    i18n.locale = lang


    return lang
}

export const loadLanguageModule = (lang, langFile) => {
    console.log("LOAD LANGUAGE MODULE" + lang)
    i18n.mergeLocaleMessage(lang, Object.assign(langFile))
    return lang
}

export function loadLanguageAsync(lang) {
    if (i18n.locale !== lang) {
        if (!loadedLanguages.includes(lang)) {
            switch (lang) {

            case "en":
                return import("./lang/en.json").then(langFile => loadLanguage("en", langFile))

            case "fr":
                return import("./lang/fr.json").then(langFile => loadLanguage("fr", langFile))

            default:
                return import("./lang/fr.json").then(langFile => loadLanguage("fr", langFile))
            }
        } else {
            console.log("Already loaded " + lang)

        }
        return Promise.resolve(!loadedLanguages.includes(lang) || loadLanguage(lang))
    }
    return Promise.resolve(lang)
}

用戶模塊語言加載

const userLoadedLanguages = []

export default function loadUserLanguageAsync(lang) {
    if (i18n.locale !== lang || !userLoadedLanguages.includes(lang)) {
        switch (lang) {
        case "en":
            return import("./lang/en.json").then(langFile => loadLanguageModule("en", langFile))
        case "fr":
            return import("./lang/fr.json").then(langFile => loadLanguageModule("fr", langFile))
        default:
            return import("./lang/fr.json").then(langFile => loadLanguageModule("fr", langFile))
        }
    }
    return Promise.resolve(i18n.messages[lang].user).then(console.log("USER LANG LOADED"))
}
  • 加載完每個模塊后,我將切換一個標志,該標志允許路由器導航防護器繼續進行所需的路線(請參閱主要的加載部分)。

路由器保護並等待異步功能

router.beforeEach((to, from, next) => {
     isReady().then(
        console.log("NEXT"),
        next()
    )
})
async function isReady() {
    while (true) {
        if (this.modulesReady) { console.log("READY"); return }
        await null // prevents app from hanging
    }
}

我對異步邏輯還很陌生,因此我很難確定自己在做什么錯。 這里的代碼使瀏覽器崩潰,因為我猜我的Promise值不正確,並且發生在無限的isReady()循環中。

我非常歡迎關於更好/正確方法的建議或建議。 此外,如果缺少某些內容,請隨時索取更多詳細信息。

謝謝!

如何將動態導入與流星鏈接在一起?

首先在Promise鏈上考慮以下答案: 如何訪問.then()鏈中的先前的 Promise 結果?

如果您更喜歡異步/等待樣式,可以在這里進行后續操作:可以在async function使用await調用動態導入。 這使您有機會包裝代碼同步樣式並在最終的Promise中解決所有問題:

考慮相對項目路徑/imports/lang.json上的一個簡單JSON文件:

{
  "test": "value"
}

還有一些示例在/imports/testObj.js路徑上導出常量:

export const testObj = {
  test: 'other value'
}

您可以使用如下異步函數動態導入這些(例如client/main.js ):

async function imports () {
  const json = await import('../imports/lang.json')
  console.log('json loaded')
  const { testObj } = await import('../imports/test')
  console.log('testObj loaded')
  return { json: json.default, testObj }
}

Meteor.startup(() => {
  imports().then(({ json, testObj }) => {
    console.log('all loaded: ', json, testObj)
  })
})

這將按順序打印

json loaded
testObj loaded
all loaded: Object { test: "value" } Object { test: "other value" }

由於您的代碼示例非常復雜且幾乎不可重現,因此我建議您考慮采用此方案以更同步的方式重寫例程,以避免使用帶有數十個.then分支的Promises語法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM