【问题标题】:Architecture: Combine several JavaScript projects (modular) [closed]架构:结合几个 JavaScript 项目(模块化)[关闭]
【发布时间】:2016-09-27 01:13:01
【问题描述】:

我想为我的 JavaScript 项目创建一个干净的架构。该项目由一个 Node.js 服务器和两个具有不同用途的独立 Angular.js 前端组成。为了构建前端,我每个都使用自定义的 grunt 构建。构建结果为每个项目一个 HTML 文件和两个缩小/丑化的 CSS 和 JavaScript 文件。然后,每个前端都在单独的最小版本的 Node 服务器上运行(仅提供静态文件)。

到目前为止,很清楚。现在的目标是为三个核心项目中的每一个添加插件模块成为可能。模块应该扩展任一项目的 JavaScript。这意味着例如在一个前端的情况下,将一个额外的角度模块添加到角度配置中。我已经知道在哪里以及如何将角度模块代码添加到核心应用程序中。

现在的问题是:如何在多个项目上创建一个合理的构建过程,这也取决于插件模块?我想出了两个解决方案。

  1. 我可以将插件作为 NPM 依赖项添加到其中一个核心项目中。然而,这有一个缺点,模块中的每个更改都需要推送到 NPM,这样开发插件模块不是很方便。插件不能单独运行。
  2. 我可以在其中一个核心项目的 Gruntfile 中有一个插件列表。此列表将包含模块的本地文件路径。在核心模块的构建中,插件的构建将被执行。然而,这将包括观察插件构建文件的变化。这是一个不干净的解决方案。
  3. 我可以有另一个项目,其中包含对核心项目和所有插件的依赖关系,并将它们一起构建。如何添加依赖的问题依然存在(案例1或2)

你会如何解决这个问题?

【问题讨论】:

  • 可能想研究一下使用 webpack 而不是 grunt。
  • @charlietfl 你能解释一下如何在多个项目中使用 webpack 实现架构和良好的开发环境吗?
  • 恐怕我真的不精通使用它,因为它不适合我所做的大部分工作。我只通过它,因为我相信它会有所帮助,因为它是从节点模块中提取的
  • 对于解决方案 #1,我在开发通过 composer 提取的模块时遇到了类似的问题。我的解决方案是为了开发,我对这些模块进行符号链接。所以我有实时更新的依赖关系,但它们的位置就像是通过包管理器拉出来的一样。
  • @charlietfl grunt 比 webpack 有什么好处?

标签: javascript build architecture gruntjs multi-project


【解决方案1】:

恕我直言, 与任务管理器的工作无关(又名 gulp、grunt 甚至 webpack,这并不重要)。社区去了一个地方,你拥有许多(相对)微小的节点模块,它们做一件事并且做得很好,所以它与你的第一个建议非常相关。

VCS 存储库可能看起来像这样的结构:

my-repo/
  package-1/
    package.json
  package-2/
    package.json
  package-3/
    package.json
  ...

...然后您与npm link 合作在模块内部创建符号链接,这样您就不必发布模块来获取更新。

有一个名为lerna 的全新软件包,它会自动完成npm link 的工作(它会在“本地”模块中检测您的依赖关系图并在它们之间建立链接),您需要做的就是按照他们的结构体。此外,它使发布变得智能,您可以在所有包中运行命令以及一堆其他相关的东西。

BabelReact 是关注模块分离的很好例子。 Babel 与 lerna 一起使用以自动化包之间的链接,here are their reasons to have a monorepo

【讨论】:

  • 感谢您的回答!我看了看 Lerna,它看起来很有希望。您能否详细说明,如何使用它?官方文档很糟糕。据我了解:您有几个项目,然后将其复制/链接到 ./packages/ 文件夹。 Lerna 是如何认识到应该链接您的本地存储库副本而不是从 NPM 获取副本?我也没有真正理解模块-关注点分离和monorepo这两个术语之间的联系,因为听起来正好相反?
  • Lerna 映射您当前在您的存储库中拥有的模块并相应地链接。假设您有模块aba 依赖于b,它知道在b 中运行npm link,然后在a 中运行npm link b。关于这两个术语,它们将它们的模块聚合在一个 repo 中,repo 只是一种组织它们的方式,模块本身仍然是分开的。这是另一个关于 lerna btw 的资源(刚刚发布):blog.cloudflare.com/cf-ui/…
【解决方案2】:

几个月前我遇到了类似的问题。由于您熟悉 Grunt 或 Gulp 等流式构建系统,因此安装动态依赖项可以相当容易地解决。

  1. 您可以在 package.json 中分配一个属性,例如依赖项或 devdependencies,它将保存您需要的所有其他信息,bower.json 甚至自定义 JSON 文件也可以解决问题。我更喜欢 NPM 打包清单或 Bower 清单,因为它们为每个模块提供了一个有效的入口点。
  2. 使用grunt-auto-install,您可以为构建过程动态安装任何其他模块依赖项,您可以从项目的主package.json 文件中解析这些依赖项。
  3. 使用每个附加 package.json 中每个模块的 main 属性将为您提供一个文件列表来初始化 uglify 或连接任务。

【讨论】:

  • 感谢您的回答!那么您是否建议像这样链接到 NPM 模块:"project_a": "file:../project_a" 或者您是否建议不使用 NPM 来检索依赖项,而是使用 Grunt 来代替?您如何以及在何处读取每个 package.json 的主要属性?在 Gruntfile 中?你会如何观察插件模块的变化?
  • 您好,我建议使用 NPM 或 Bower 来获取依赖项。您可以使用 Grunt 安装它们,版本号将跟踪您的更改。之后,一个新的 Grunt 任务将从已安装的属性中循环每个附加的 package.json 或 bower.json。使用每个的 main 属性将为您提供 JavaScript 文件的实际入口点。有关 main 属性的更多信息,请参阅 NPM 文档:docs.npmjs.com/files/package.json#main
  • 但是如何将 NPM 包链接到本地​​存储库,例如在开发过程中实时重新加载本地文件?如果您将项目链接到 git {"dependencies": { "project_a": "http://github.com/...." } } 您只能更新项目,如果您推送另一个版本。这在开发过程中很麻烦..
  • 使用 Bower 本地依赖项:stackoverflow.com/a/14571729/910701 或 NPM 本地依赖项:stackoverflow.com/a/14387210/910701 不过,您可以保留一个单独的文件与版本控制并轻松扩展您的项目。
【解决方案3】:

您在 MEAN 项目中添加了不必要的复杂性。
为什么要通过 grunt 连接两个 html 部分???
您应该使用 AngularJS 的 SPA 架构,他们采用这种架构是有原因的。其中一个没有在此类问题中运行。
无需连接文件,只需配置 SPA 的状态以从 html 文件调用所需的部分模板。就是这样!
并在您的后端使用 Web 服务(我认为您正在这样做),这样您就可以独立于数据的来源,因为无论它来自哪个服务器,您都在使用 URI。
关于依赖关系,您可以在前端或后端无缝使用 npm,并带有 --save 标志,以便将它们添加到 package.json 文件中,然后将该文件复制到相应的应用程序目录和 npm install 。
但是我真的不知道你将如何处理这一切,如果你能解释更多关于有助于理解它的功能要求的信息..

【讨论】:

  • 问题是关于构建过程,而不是关于以角度运行它。运行有角度的单页应用程序不是问题。此外,我不会将 HTML 文件合并为一个 HTML 文件。一个很小的 ​​index.html 结果,主要的 HTML 组件被构建在一起以使用 Grunt(grunt-html2js 和 grunt-contrib-htmlmin)缩小 JavaScript 字符串。这样,HTML 组件在初始页面加载后始终可用,并且应用程序以最快的方式做出反应。
  • 我猜,你没有理解主要问题。为了简化问题,有一个核心 GitHub 项目依赖于多个“插件”GitHub 项目。这些项目不是必需的,但可以添加到核心项目中,然后作为常规 Angular 模块添加。但首先,必须合并几个项目的代码(连接或复制到核心项目,该角度可以选择模块)。这可以通过 NPM 完成,如问题中所述,但它有一些缺点,我正在寻找更好的方法来做到这一点。
【解决方案4】:

我通常完全按照您在 1 中描述的操作。但我使用本地依赖项,这些依赖项将由我的构建链连接起来。

npm install ~/project_root/sub_project --save-dev

这样你就不需要一直推送它。您只需删除 node_module/sub_project 文件夹并在构建链中再次运行 npm install

使用 browserify,您可以将依赖项添加到您的 Angular 项目中。

插件不能单独运行。

我通常将我的服务或指令开发为常规的 JavaScript 类,并用 angular 封装它们。

var Service = require("./path/to/service.js")
module.exports = [function() {
    return {
        restrict: 'AC',
        link: function($scope, $element) {
            var someService = new Service();
            $scope.$watch("whatever",function(value){
                service.doSomething();
            })
        }
    };
}];

通过这种方式,您可以独立于 Angular 运行和测试它们。这在使用WebWorkers 时也很有优势。因为它们不能真正(完全)与 angular 1.X 一起使用。

【讨论】:

  • 感谢您的回答。我已经在 NPM 中找到了使用本地路径的解决方案,但对手动删除节点模块并重新运行 npm install 并不满意,因为我通常使用 livereloading 构建过程。你知道在开发插件?
  • 如果您使用 gulp-watch,您只能扫描您的最终构建以进行自动重新加载。 Gulp watch 有点将此功能转发给您的重新加载器。
  • 构建链的问题/优势在于它们是为测试驱动开发而设计的。我知道这不能满足您的问题,但值得考虑。
猜你喜欢
  • 2014-10-27
  • 1970-01-01
  • 2021-05-29
  • 1970-01-01
  • 1970-01-01
  • 2020-01-16
  • 2016-01-04
  • 1970-01-01
  • 2015-05-19
相关资源
最近更新 更多