Vue.js 和本地 NPM 包的应用程序模块化

Application modularity with Vue.js and local NPM packages

我正在尝试通过 vue-cli-service 在 Vue 中构建模块化应用程序。主应用程序和模块是位于不同文件夹中的独立项目,结构如下所示:

-- app/package.json
      /src/**
-- module1/package.json
          /src**
-- module2/package.json
          /src**

想法是让 Vue 应用程序完全不知道运行时可能存在的应用程序模块,模块本身是用 vue-cli-service build --target lib 在本地 moduleX/dist 文件夹中编译的,用package.json“主要”和“文件”节点。

我的第一个想法(现在只是为了提高开发速度)是将模块作为本地 NPM 包添加到应用程序中,使用观察者构建它们并使用观察者本身为应用程序提供服务,以便对依赖项的任何更改模块会(我认为)自动分发到主应用程序。

因此应用程序的 package.json 包含如下依赖项:

...
"module1": "file:../module1",
"module2": "file:../module2",
...

这个依赖项意味着可以随时删除,或者通常根据我们的需要进行组合,应用程序只需重新编译,一切都应该可以正常工作。

我现在正试图了解如何在应用程序中动态加载和激活模块,因为我不能像这样使用动态导入:

import(/* webpackMode: "eager" */ `module1`).then(src => {
    src.default.boot();
    resolve();
});

因为基本上我不知道'module1'、'module2'等...

在 OOP 世界中,我只会使用依赖注入检索 类 实现特定接口,但在 JS/TS 中我不确定它是否可行。

有办法做到这一点吗?

In an OOP world I would just use dependency injection retrieving classes implementing a specific interface, but in JS/TS I'm not sure it is viable.

为什么不呢?

除此之外,使用 JS/TS 您不限于使用 类 实现特定接口:您只需要定义模块的接口(即 module.exports)并在库条目 (vue build lib) 中尊重它。

编辑:阅读评论可能我理解了请求。

每个模块都应该遵循以下接口(在作为 vue 库入口的文件中)

export function isMyAppModule() {
  return true;
}

export function myAppInit() {
  return { /* what you need to export */ };
}

比在您的应用中:

require("./package.json").dependencies.forEach(name => {
  const module = require(name);

  if(! module.isMyAppModule || module.isMyAppModule() !== true) return;

  const { /* the refs you need */ } = module.myAppInit();

  // use your refs as you need
});

package.json 杂耍对我来说听起来不是个好主意 - 无法扩展。我会做什么:

  1. package.json
  2. 中保留所有可用的“模块”
  3. 创建单独的 js 文件(或在 package.json 中拥有自己的道具),其中包含所有可用的配置(例如,针对不同的客户端)
module.exports = {
   'default': ['module1', 'module2', 'module3'],
   'clientA': ['module1', 'module2', 'module4'],
   'clientB': ['module2', 'module3', 'module4']
}
  1. 进入 VueCLI 构建过程 - 我发现的最佳示例是 here and create js file which will run before each build (or "serve") and using simple template (for example lodash) 生成新的 js 文件,该文件将根据某些 ENV 变量的值启动配置的模块。请参阅以下(伪)代码(记住它在构建期间在节点内运行):
const fs = require('fs')
const _ = require('lodash')
const modulesConfig = require(`your module config js`)

const configurationName = process.env.MY_APP_CONFIGURATION ?? 'default'
const modules = modulesConfig[configurationName]

const template = fs.loadFileSync('name of template file')
const templateCompiled = _.template(template)
const generatedJS = templateCompiled({ `modules`: modules })
fs.writeFileSync('bootModules.js', generatedJS)
  1. bootModules.js 编写模板。最简单的是:
<% _.forEach(modules , function(module) { %>import '<%= module %>' as <%= module %><% }); %>;
  1. bootModules.js 导入您的应用程序
  2. 使用 MY_APP_CONFIGURATION ENV 变量来切换所需的模块配置 - 不仅在开发期间有效,而且您还可以设置不同的 CI 进程以不同的 MY_APP_CONFIGURATION

这样您就可以将所有配置放在一个地方,您无需在每次构建之前更改 package.json,您可以通过简单的机制在不同的模块配置之间切换,并且每个构建(包)仅包含需要模块....