16

关于从 Grails(REST-API、AngularJS 的一部分、MongoDB、Tomcat、Spock、几个插件)迁移到 Node.js + Angular.js,我有几个(软件)架构问题。我可能要解释一下 Grails 项目拳头的结构,所以我们开始吧:

有一个主要的 Grails 应用程序(除了几个其他应用程序),它建立在几个插件之上。这些插件中的每一个都能够自行执行——这意味着它有自己的 UI、单独的模板、服务、控制器、路由、测试等。它还托管在不同的存储库中。这是由 Grails 插件机制完成的。好处是更少的测试工作、更少的编译时间、模块化、单一职责等。

但是,编译和测试的时间仍然太昂贵。我也不喜欢 API 提供部分模板/视图的事实。我希望后端 API“只是作为后端 API”,而前端“只是作为前端”。所以每个 AngularJS 应用程序/插件都会提供自己的视图、路由、服务等。但它们也可能依赖于其他插件。

所以我想要实现的目标如下:

  • 一个主要的 AngularJS 应用程序,它包括几个插件(一个插件可以是报告生成器、留言簿或其他任何东西,它指的是应用程序的单个独立部分,或者具有特定的路由,或者只是页面的一小部分)。
  • 每个插件必须是一个独立的 AngularJS 应用程序(可能在开发过程中通过 grunt 执行)。这样 UI 开发人员不需要启动整个后端应用程序,而且我们可以只使用 JavaScript 运行功能测试
  • 仅通过 REST 进行通信,前端必须从 API 检索所有数据
  • 每个插件都必须是可独立测试的
  • 插件可能需要其他插件才能工作
  • 主要的 index.html(和 app.js?)可能由 Nginx 服务器提供,它与后端 (API) 的其余部分分离

虽然我脑子里有一幅特定的画面,但我在如何设置这个架构上苦苦挣扎。

在 Grails 中,插件机制以某种方式将插件相关设置(如 URL 映射、依赖项等)合并到包含/注入它们的主应用程序中——这也是我想用 AngularJS 实现的。所以:

  • AngularJS 是否有某种相同的机制?
  • 如何将每个插件的路由提供/合并到主应用程序中?
  • 如何声明应用程序和插件依赖项?
  • 哪些工具可能对构建过程有用?
  • 如何建立插件资源(css/less 文件、视图、服务等)的惰性检索?
  • 阻止应用程序在启动时提供插件的所有资源(我猜在启动时需要路由)

由于这不仅仅是一个如何做这个或那个问题,如果我遗漏了重要部分或某些部分不够清楚,我会原谅自己。只要问我,我会深入回答每个问题。

4

2 回答 2

4

**此答案不完整**

在深入研究之前,我想确保我理解你。

这是一个加载器模块的快速实现,用于管理延迟加载(插件、供应商资产、管理内容等)。

这有帮助吗?

angular.module('Bizcoin.loader')
.service('Loader', Loader);

function Loader($injector, $ocLazyLoad, User) {
  var Loader = {
    load: load,
    get: get,
    plugins: {},
    flags: {}
  };

  init();

  return Loader;

  function init() {
    load('vendors');
    if (userIsAdmin)
      load('admin');
  }

  function load(plugin) {
    Loader.plugins[plugin] = Loader[plugin] || $ocLazyLoad.load('path/to/'+plugin+'.js');
    return Loader.plugins[plugin].then(setFlag);

    function setFlag() {
      return Loader.flags[plugin] = true;
    }
  }

  function get(plugin) {
    return load(plugin).then(function() {
      return $injector.get(plugin);
    });
  }

}
于 2015-08-11T23:46:54.547 回答
3

我在一个大型 .Net/AngularJS 应用程序上工作,该应用程序由 20 多个独立的区域(或模块)和一些在所有区域中通用和重用的核心功能组成。

让我详细介绍一下我如何针对我的特定情况执行此操作,它可能会提供一些想法。我使用 .Net 的事实在这里无关紧要,因为这可以通过任何框架实现。

每个区域都充当一个独立的应用程序,仅依赖于始终存在的核心功能。每个区域都有自己的 ASP.Net MVC 路由。每个区域向核心应用程序注册它想要提供的菜单链接。当客户进入应用程序仪表板时,只有应用程序的核心部分。当用户点击菜单中的链接时,它将导航到其中一个区域提供的内容,并且仅加载该区域的核心和资产。

让我们看看这是如何做到的。

在应用程序的主页中,我加载如下脚本:

<script type="text/javascript">
    // a JS object with all the necessary app data from the server.
    // e.g.: menu data, etc
    window.appContext = @Html.Action("ApplicationContext", "Portal")); 
</script>

@Scripts.Render("~/bundles/angular-main")

@RenderSection("AngularAreas", required: false)

我使用点 .Net 包和部分。

应用程序的主要(核心)AngularJS 部分由 Angular 配置、国际化服务、全局通知服务、可重用的 UI 组件等组成。加载的是@Scripts.Render("~/bundles/angular-main").

当用户导航到该区域时,该@RenderSection("AngularAreas", required: false)部分将由每个区域填充。

让我们看看一些 AngularJS 代码。这是主要 app.ts 的一部分。

// If user is visiting an Area, the NgModules array will be augmented.
// with the modules the Area wants to provide (to be bootstrapped)
export var LoadNgModules = [
    NgModules.Config,
    NgModules.Core
];

angular.module(NgModules.Bootstraper, LoadNgModules);

angular.element(document).ready(function () {
    angular.bootstrap(document, [NgModules.Bootstraper]);
});

现在让我们看一个示例区域。

这是一个区域如何提供其资产,以输出@RenderSection("AngularAreas", required: false)

@section AngularAreas {
    @Scripts.Render("~/bundles/areas/staff-management")
}

它是一个简单的包,包含该区域的所有脚本。现在,让我们看看这个区域的 AngularJS 代码的重要部分。

var StaffManagementNgModule = 'areas.staff-management';

// Push our self into the modules to be bootstrapped
LoadNgModules.push(StaffManagementNgModule );

// Define the module
angular
    .module(StaffManagementNgModule , ['ngRoute', NgModules.Core])
    .config([
        '$routeProvider', '$locationProvider', ($routeProvider: ng.route.IRouteProvider, $locationProvider) => {

            $routeProvider
                .when(staff', { template: '<staff></staff>' })
                .when('staff/details/:id', { template: '<staff-details></staff-details>' });
        }
    ]);;

就是这样,从这里开始,Area 就是一个普通的 Angular 应用程序。

总而言之,我们加载主要(核心)AngularJS 功能并提供 LoadNgModules 数组,一个区域可以用它自己的模块填充。

我们将 Area 脚本和“我们的自我”加载到 LoadNgModules 数组中。

最后运行 angular.bootstrap。

为了完整起见,这里是 C# 的片段,展示了一个区域如何向主应用程序指示它是可用的

public class ItemManagementModuleRegistration : IModuleRegistration
{
    public void Register(ModuleContext moduleContext)
    {
        string thisAreaName = "Staff";

        moduleContext.RegisterMenu(menuContext =>
        {
            var ItemsMenu = menuContext.Items(thisAreaName);

            // add urls and stuff...
        });

        // register more stuff with the moduleContext
    }
}

使用反射可以很容易地找到“安装”了哪些区域。

这些是设置的主要移动部分。每个区域都可以有自己的 API 和测试。它非常灵活。

于 2016-05-27T19:18:48.903 回答