暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Rushjs 构建 monorepo

程序猿研究所 2021-09-13
4476

构建 monorepo 有很多方式,比较流行的有 nx, yarn, pnpm。nx 主要用于 angular, 同时也支持 react 和 nodejs, 适合构建大型项目,提供一系列好用的样板代码生成工具,但是 nx 所支持的项目有限,并不是很通用,比如像 vue, 就需要额外安装社区提供的插件。还有像 yarn 和 pnpm 提供 workspace,可以满足基本的需求,但是对于 monorepo 项目内的依赖需要手动 link, CI/CD 也支持地不够完善,毕竟他们的定位是包管理工具,不是 build 工具, 但是好处也很明显,简单,上手容易,在可遇见的将来不用担心会没人维护,结合 gulp 使用的话也是不错的选择。

除了上面几种方式,个人比较喜欢和推荐的是微软开发的 rushjs 工具,相比于 yarn 和 pnpm,功能要完善许多,而且是微软开发管理 sharepoint 的,稳定性也应该是有所保障的。

下面介绍通过 rushjs 创建一个 monorepo。

1. 安装并初始化

安装比较简单,直接全局安装:

    npm install -g @microsoft/rush
    mkdir rushapp

    rush 提供 init 命令初始化项目:

      cd rushapp && rush init

      初始化完成之后会出现一个 rush.json 配置文件和一个 common 目录。

      2. 创建项目

      创建一个项目目录文件 apps:

        mkdir apps && cd apps

        创建一个 vue 项目:

          yarn create vite vueapp --template vue

          在 rush.json 的配置项文件里添加 vueapp 项目:

             "projects": [
            {
            "packageName": "vueapp",
            "projectFolder": "apps/vueapp",
            "reviewCategory": "production"
            }
            ]

            然后执行

              rush update

              rush 会通过默认的 pnpm 包管理器安装依赖,所有的依赖会安装在总项目目录下的 common 的 temp 文件夹下,而对应的子项目例如 vueapp 目录下同时会 出现 node_modules 目录,而里面的包都是软链接自最外层的 common 下的 temp 目录。

              在单个子项目中可以独立执行项目中的各种命令,安装独立项目来操作, 例如:

                npm run build
                npm run dev

                也可以使用 rushx:

                  rushx build
                  rushx dev

                  3. 添加更多项目

                  在 apps 目录下添加其他项目, 这次是手动添加:

                    mkdir server && cd server

                    初始化项目:

                      npm init

                      在在最外层 rush.json 添加项目信息:

                         "projects": [
                        {
                        "packageName": "vueapp",
                        "projectFolder": "apps/vueapp",
                        "reviewCategory": "production"
                        },
                        {
                        "packageName": "server",
                        "projectFolder": "apps/server",
                        "reviewCategory": "production"
                        }
                        ]

                        切换到 server 子项目目录,添加项目依赖:

                          rush add --package typescript --dev
                          rush add --package @types/node --dev
                          rush add --package fastify

                          添加 server.ts 文件:

                            import fastify from 'fastify'


                            const server = fastify()


                            server.get('/', async (request, reply) => {
                            return 'hello, world.';
                            })


                            server.listen(8080, (err, address) => {
                            if (err) {
                            console.error(err)
                            process.exit(1)
                            }
                            console.log(`Server listening at ${address}`)
                            })

                            并且配置好 tsconfig.json :

                              {
                              "name": "server",
                              "version": "1.0.0",
                              "description": "",
                              "main": "index.js",
                              "scripts": {
                              "start": "node index.js",
                              "build": "tsc -p tsconfig.json",
                              "test": "echo \"Error: no test specified\" && exit 1"
                              },
                              "author": "",
                              "license": "ISC",
                              "dependencies": {
                              "typescript": "~4.4.3",
                              "fastify": "~3.21.0",
                              "@types/node": "~16.9.1"
                              }
                              }

                              rush 的比较好的功能是提供了批量操作的功能,比如执行:

                                rush build

                                他会执行全部子项目的 build 命令:

                                  Found configuration in Users/TANGW197/apps/playground/rushapp/rush.json




                                  Rush Multi-Project Build Tool 5.52.0 - https://rushjs.io
                                  Node.js version is 14.17.5 (LTS)


                                  Found configuration in Users/TANGW197/apps/playground/rushapp/rush.json


                                  Starting "rush build"


                                  Executing a maximum of 12 simultaneous processes...


                                  ==[ server ]=======================================================[ 1 of 2 ]==
                                  "server" completed successfully in 1.40 seconds.


                                  ==[ vueapp ]=======================================================[ 2 of 2 ]==
                                  "vueapp" completed successfully in 3.09 seconds.






                                  ==[ SUCCESS: 2 projects ]======================================================


                                  These projects completed successfully:
                                  server 1.40 seconds
                                  vueapp 3.09 seconds




                                  rush build (3.10 seconds)

                                  因此 rush 对于自动化 CI/CD 比较友好, build 命令也提供其他参数来单独 build 指定的项目。

                                  4. 创建自引用的库

                                  当前创建的子项目都是相互独立,互不干涉的,但是有的时候需要创建一个 library, 而其他的项目恰好需要引入这个 library, 这时需要用到 link

                                  在 rushapp 总目录与 apps 同级的目录下创建一个 libraries 目录,在这个 libraries 下创建一个 helpers 库。

                                    {
                                    "name": "@rushapp/helpers",
                                    "version": "1.0.0",
                                    "description": "",
                                    "main": "index.js",
                                    "scripts": {
                                    "test": "echo \"Error: no test specified\" && exit 1"
                                    },
                                    "author": "",
                                    "license": "ISC"
                                    }

                                    为了不和 npm 线上仓库冲突,特意加上了命名空间作为区分,在 rush.json 文件里配置项目:

                                      "projects": [
                                      {
                                      "packageName": "vueapp",
                                      "projectFolder": "apps/vueapp",
                                      "reviewCategory": "production"
                                      },
                                      {
                                      "packageName": "server",
                                      "projectFolder": "apps/server",
                                      "reviewCategory": "production"
                                      },
                                      {
                                      "packageName": "@rushapp/helpers",
                                      "projectFolder": "libraries/helpers",
                                      "reviewCategory": "production"
                                      }
                                      ]

                                      我们在 helpers 库中创建一个最简单的函数并导出:

                                        function hello() {
                                        return "hello, world!";
                                        }


                                        export default hello;

                                        假如我们需要在 server 子项目中引入 helpers 库,只需要在 server 的 package.json 添加对应依赖即可:

                                          {
                                          "name": "server",
                                          "version": "1.0.0",
                                          "description": "",
                                          "main": "index.js",
                                          "scripts": {
                                          "start": "node index.js",
                                          "build": "tsc -p tsconfig.json",
                                          "test": "echo \"Error: no test specified\" && exit 1"
                                          },
                                          "author": "",
                                          "license": "ISC",
                                          "dependencies": {
                                          "typescript": "~4.4.3",
                                          "fastify": "~3.21.0",
                                          "@types/node": "~16.9.1",
                                          "@rushapp/helpers": "~1.0.0"
                                          }
                                          }

                                          然后执行 rush update
                                          , 在 server 代码里稍作更改:

                                            import fastify from 'fastify'
                                            import helpers from '@rushapp/helpers';


                                            const server = fastify()


                                            server.get('/', async (request, reply) => {
                                            reply.send(helpers());
                                            })


                                            server.listen(8080, (err, address) => {
                                            if (err) {
                                            console.error(err)
                                            process.exit(1)
                                            }
                                            console.log(`Server listening at ${address}`)
                                            })

                                            5. 部署

                                            执行 rush build
                                             就可以将三个子项目批量编译,编译完之后照理说可以直接将整个项目打包部署,但是这样整个包的体积会非常的大, 最好的方式是通过类似 npm pack 的方式将必要的文件和依赖提取出来,然后再将其打包,部署。

                                            rush 提供了 deploy 命令来实现对应的功能, 生成一个 deploy 配置, 在主目录下执行:

                                              rush init-deploy -p server

                                              会在 common/config/rush
                                               生成一个 deploy.json
                                               文件, 配置完需要打包的参数就可以执行:

                                                rush deploy

                                                进行打包了,但是这里需要注意的是 vueapp 是 dist 编译后的目录文件,但是 deploy.json 的配置没有提供复制文件夹的功能,但是通过命令行也很容易实现:

                                                  rush build && rush deploy --overwrite && mv apps/vueapp/dist common/deploy

                                                  此时打包出来的文件已经小了不止一个数量级了,只有不到 7M,因此可以直接将 common/deploy 文件夹部署到服务器上。

                                                  6. Rush stack

                                                  rush 是 rush stack 提供的一个 monorepo 管理工具,除了 rush, rush stack 还提供了其他像 heft build 工具, api 提取,文档生成等工具, 其中 heft 结合 rush, 可以实现更灵活和强大的工作流。

                                                  文章转载自程序猿研究所,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                                  评论