共享上下文之间的共同依赖关系

Share common dependencies between contexts

本文关键字:依赖 关系 上下文 之间 共享      更新时间:2023-09-26

前提

假设我有两个不同的基于 AMD 的 AngularJS 应用程序,每个应用程序都有自己的一组控制器、指令、服务等。它们中的每一个都捆绑在自己的dist/{app-name}.min.js中,并加载在同一 HTML 页面中的<script>标签中(这一切都在 CMS 的上下文中,然后包含这些应用程序等(

现在应用程序最终共享了一些服务、指令和供应商库,如angular本身、momentjQuery 等,所以我为所有这些资源制作了另一个文件夹,这导致一个捆绑包将被添加到应用程序的 js 捆绑包之前的页面中:

<script src="/some-path/dist/shared-resources.min.js"></script>
<script src="/some-path/dist/first-app.min.js"></script>
<script src="/some-path/dist/second-app.min.js"></script>

这是生成的文件夹结构:

.
├── shared-resources/
│    ├── dist/
│    ├── src/
│    │     └── common/
│    │          ├── directives/
│    │          ├── modules/
│    │          ├── services/
│    │          └── vendor/
│    └── build.js
│
├── first-app
│    ├── dist/
│    ├── src/
│    │    ├── first-app/
│    │    │    ├── controllers/
│    │    │    ├── modules/
│    │    │    ├── services/
│    │    │    ├── directives/
│    │    │    └── app.js
│    │    └── first-app.js
│    └── build.js
│
└── second-app
     ├── dist/
     ├── src/
     │    ├── second-app/
     │    │    ├── controllers/
     │    │    ├── modules/
     │    │    ├── services/
     │    │    ├── vendor/
     │    │    └── app.js
     │    └── second-app.js
     └── build.js

这是常见模块的build.js文件的示例

({
    baseUrl: 'src',
    removeCombined: true,
    out: 'dist/shared-resources.min.js',
    paths: { // forcing a `common/{modulename}` convention
        'common/jquery': 'common/vendor/jquery.min',
        'common/moment': 'common/vendor/moment.min',
        'common/angular': 'common/vendor/angular/angular.min',
    },
    shim: {
        'common/angular': {
            exports: 'angular',
        }
    },
    include: [
        'common/modules/vendors', // Just a bundle of every vendor modules
        'common/directives/common-directive',
        'common/services/common-service'
    ],
})

现在我的目的是让所有共享模块都使用 common/ 命名,因此每个应用程序都可能需要 common/angularcommon/directives/common-directive 等,然后在创建其捆绑包时排除common路径(因为所有公共模块都已存在于shared-resources.js捆绑包中(,例如:

// first-app/src/first-app/controllers/app-controller.js
define([
    'first-app/modules/controllers',
    'first-app/services/app-service',
    'common/services/common-service'
], function (controllers) {
    'use strict';
    controllers.controller('AppController', ['CommonService', 'AppService', function (CommonService, AppService) {
        CommonService.call();
        AppService.call();
    }]);
});
// first-app/build.js
({
    baseUrl: 'src',
    out: 'dist/first-app.min.js',
    paths: {
        'common': 'empty:'
    },
    name: 'first-app',
    deps: ['first-app/app']
})

问题

问题是这两个应用程序,它们再次加载到页面上(这是无法避免的(,应该如何正确查找这些公共模块。

鉴于每个应用程序显然具有不同的baseUrl,它们被放置在不同的 RequireJS 上下文中,否则第二个应用程序的baseUrl将覆盖第一个应用程序的baseUrl,从而导致其模块加载不正确:

// first-app/src/first-app.js
require.config({
    context: 'first-app',
    baseUrl: 'first-app/src',
})(['fist-app/app']);
// first-app/src/second-app.js
require.config({
    context: 'second-app',
    baseUrl: 'second-app/src',
})(['second-app/app']);

但是将它们放在上下文中会导致对公共模块的查找失败,因为模块是在上下文baseUrl中查找的。实际上,这仅适用于第二个应用程序(按加载顺序排列的第二个应用程序(,而要包含在页面中的第一个应用程序可以很好地加载公共模块

问题

那么我应该如何使应用程序正确共享公共模块呢?我的做法错了吗?我应该使用RequireJS以外的其他东西吗?

RequireJS 的上下文功能实际上是用来处理您必须在同一页面上加载两个冲突的应用程序并且无法解决冲突的情况。到目前为止,您编写代码的方式可能导致您希望有两个baseUrl值,但您的问题中没有任何内容表明您必须有两个baseUrl值。有一些方法可以避免它:

  1. 作为逻辑模块集一部分的模块应使用相对路径相互加载。例如,您作为示例给出的模块可以是:

    // first-app/src/first-app/controllers/app-controller.js
    define([
        '../modules/controllers',
        '../services/app-service',
        'common/services/common-service'
    ], function (controllers) {
    
  2. paths可以设置为使其看起来像模块直接在baseUrl下,即使它不是。您可以拥有:

    paths: {
        'first-app': 'first-app/src'
        'second-app': 'second-app/src'
    }
    

    是的,加载first-app/app将起作用。RequireJS 会将路径转换为 first-app/src/app.js