动态

详情 返回 返回

[Angular]單運行時多項目共享依賴方案 - 动态 详情

ngx-center

一箇中心,多個......

  • 使用介紹(視頻)

    這是什麼?

  • 一個 Angular 單運行時多項目共享依賴的解決方案
  • 只啓動一個 Angular 平台(PlatformRef),其他子項目進行導出(類 es6 module),通過資源文件清單(或單獨 js 文件)進行請求加載

功能

  • 支持子項目在開發時代碼變更的刷新
  • 支持子項目調用主項目導出的命名(export * from 'xxx')
  • 支持子項目及主項目的 splitChunks(包括懶加載等...)
  • 支持懶加載路由的子項目請求及其他動態模塊的請求
  • 支持可信遠程子項目開發
  • 不需要了解各種概念,因為導出導入處理完全遵循動態import的類處理方案
  • 子模塊構建速度極快,且在大多數時間不需要向 node 申請內存
  • 理論上子項目同時可以加載子項目,也就是可以存在多層級子項目的加載
  • 可以通過子項目嵌套其他框架支持的調用
  • 通過在編譯時構建構成關係,對源代碼無侵入性,不需要過多改造

依賴

  • Angular10 Angular11 Angular12
  • node12+

原理

依賴共享

  • 也就是node_modules中的依賴變成 dll(動態鏈接庫),主,子應用都使用這個 dll 保證實例的一致性

命名共享

  • 主項目的命名會導出,供子項目用,實現子項目調用主項目的組件/模塊/服務/管道等 ng 與非 ng 的導出

子項目資源啓動

  • 主項目通過啓動子項目的資源文件/資源配置,來加載子項目資源,並且在加載後實現自動獲得子項目的導出,可以作為懶加載路由,懶加載模塊等動態使用的地方調用

使用方法

  • 本項目依賴的是 Angular 的ng generate命令,快速生成開發骨架
  • 相關插件可在在webpack-ng-dll-plugin,'webpack-bootstrap-assets-plugin查看,或者可手動配置文件
  • 建議先在新項目中使用,待了解實現後,再使用到已有項目中

主項目初始化

  • 運行npx ng g ngx-center:main-init
  • 配置
/**
 * 主項目初始化
 */
declare interface MainInitSchematics {
  /**
   * 鏈接庫(lib)名稱,默認dll
   */
  dllName?: string;
  /**
   * 主項目的名字(為空讀取默認值)
   */
  projectName?: string;
  /**
   * 使用暴露webpack配置的方式(交互)
   */
  webpackMode?: string;
  /**
   * 將webpack提升到根依賴(yarn會默認提升)
   */
  webpackPromotion?: boolean;
}
  • 除了webpackMode外,其他配置均為靜默設置,除非使用-xxx yyy顯式設置
  • 運行完成後,可以先執行npm run build:center-dll生成 dll 庫,再運行npm run start:center-main啓動主項目

    如依賴無變更,每次可僅啓動npm run start:center-main
  • 主項目的依賴一旦變更,就需要重新生成dll(npm run build:center-dll).
  • 如果主項目想導出某些命名給子項目使用(包括不限於 ts 正常語法導出,組件,指令,管道,模塊,服務等),可以聲明在export-module.ts文件中,聲明方式為export * from './xxx',同時子項目使用可以使用相對路徑,但是也可以使用impot {a} from "@center-main/.../xxx"這種方式(@center-main 為配置 tsconfig 中的 paths,默認主項目的 sourceRoot)
  • 主項目的導出命名變化後(添加依賴),需要重啓子項目
  • 主項目使用子項目使用的是 ng 原生方法,懶加載,只不過懶加載的不是原來的 ts 文件,而是資源文件,示例:
RouterModule.forRoot([
  {
    path: 'sub1',
    loadChildren: () => {
      return fetch(`http://127.0.0.1:4201/bootstrap.json`)
        .then((item) => item.json())
        .then((res) => loadRemoteModuleManifest(res))
        .then((item) => item.module);
    },
  },
]);

子項目生成

  • 運行npx ng g ngx-center:sub
  • 配置
/**
 * 子項目生成
 */
declare interface SubSchematics {
  /**
   * 子項目的名字(交互)
   */
  name: string;
  /**
   * 主項目的名字(默認defaultProject)
   */
  mainProjectName?: string;
  /**
   * 使用暴露webpack配置的方式(交互)
   */
  webpackMode?: string;
  /**
   * 開發端口(交互,每一個子項目開發時獨立佔據一個端口)
   */
  port: number;
}
  • 先啓動主項目,等center-dll,center-main都啓動成功後,再啓動子項目
  • 子項目的開發,與普通的開發完全一致,可以理解為,就是一個獨立的項目開發,支持所有你日常開發的操作

遠程子項目生成

  • 新建項目
  • 安裝ngx-center
  • 在新建的項目中運行npx ng g ngx-center:remote-sub-init
  • 獲得主項目manifest.json(依賴),main-manifest.json(項目導出命名)
  • 如果需要使用主項目服務,則需要建立虛擬主項目(即建立與原主項目導出層級相同的文件),文件中只需要將類型配置正確即可.

    如導出一個文件,那麼就需要建立一個層級相同的路徑,使最後的資源引用上下文與資源文件 json 中的路徑結合時,能找到這個文件即可
    導出模塊組件(指令,管道)使用時,只需要指定下 selector 及公開屬性,方便提示即可,
    虛擬主項目相當於一個樁只要 ng 的 loader 通過,就沒有用了
  • 最後由主項目調用遠程子項目的資源清單(或者直接拿到資源內容)即可和普通的子項目一同使用

注意事項

  • 子項目的依賴要和主項目保持一樣(最好是指定版本)
  • 主項目資源清單變化時(增加/減少依賴),需要同步子項目資源清單保持一致

構建生成

  • 參考命令,先構建,再講子項目複製進主項目文件夾中
{
  "deploy": "yarn build:center-dll:prod&&yarn build:center-main:prod&&yarn build:sub1:prod&&cpx \"dist/sub1/**/*\" dist/ng-cli-plugin/sub1"
}
  • 如果你的部署文件存放有要求,可以修改angular.json中子項目的deployUrl配置,改為你要放的子文件夾位置,然後再將命令修改為複製到對應的位置即可,當然主項目中的請求路徑也要相應修改

    比如,原項目為deployUrl:'sub1',想放到主文件夾中的router/sub1中,那麼就要修改deployUrl:'router/sub1',同時,代碼請求部分也改成fetch('router/sub1/bootstrap.json'),複製到cpx \"dist/sub1/**/*\" dist/ng-cli-plugin/router/sub1
    如果沒有要求,默認子項目名與部署地址位置相同

demo 參考

  • 源碼地址:https://github.com/wszgrcy/ng-cli-plugin-demo
  • 演示地址:https://wszgrcy.github.io/ng-cli-plugin-demo/
  • 遠程子項目演示:https://wszgrcy.github.io/ng-window/

注意事項

  • tsconfig 有獨立進行配置的開發者,請自行修改由原理圖(schematics)生成的相關配置,因為可能與您具體使用場景不同
  • 聲明文件名如果與默認不同(typings.d.ts),也需要自行復制或添加到 tsconfig 中
  • 如果使用非@angular-builders/custom-webpack作為 webapck 配置的導出,也請自行根據生成的文件修改為您自身的 builder 需要的格式,暫時沒有安排適配其他 builder.

常見問題

  1. 主項目路由聲明瞭子項目訪問,也點擊訪問子項目路由了,導航地址已經變化,但是沒有任何報錯,也沒有任何反應

    可能需要重新構建center-dll,因為 ng 項目初始化時,如果你沒有選擇生成路由,這就導致了構建center-dll時,@angular/router沒有在center-dll中,所以子項目,主項目用的兩套路由依賴,所以出的問題
  2. 構建警告,如下:
Warning: /Users/chen/my-project/ng-cli-plugin-demo/src/polyfills.ts is part of the TypeScript compilation but it's unused.
Add only entry points to the 'files' or 'include' properties in your tsconfig.
當聲明瞭polyfills,styles等文件(可能也有導出依賴),但是在構建時將入口去掉後,ng 的自身檢查機制,目前通過ngx-center構建的,基本上已經規避這個問題,即使不規避也沒問題,只不過警告看的難受
  1. 構建警告,如下:
/Users/chen/my-project/ng-cli-plugin-demo/src/app/show-in-main/show-in-main.component.ts  not export from main project!
這個是檢查插件NgNamedImportCheckPlugin在起作用,因為主項目和子項目並不是強關聯,有時候開發可能不自覺的引用了一些沒有到導出的,雖然構建不會報錯,但是會直接引用主項目的代碼,也就是生成了兩份,這時就需要將報警告的文件加入到export-module.ts中,不需要加絕對路徑,只需要相對引用就 ok 了
  1. 在主項目加入一個導出到export-module.ts中後,子項目引用沒有找到.
重啓子項目即可,如果重啓依然復現,請檢查其他原因
  1. 子項目出現某些模塊,明明引入了,但是不知道為啥使用對應組件時報錯
重啓子項目,具體原因未知,似乎是使用導出這種方式後,ng 沒有對應的檢查更新,但是重啓就會好了,出現概率較低,已知就是如果使用自定義表單控件模塊,先使用,再引入就有可能發生...,但是,如果重啓後依舊出現問題,那麼就不是這個問題導致的,請排查其他問題
  1. 構建異常,如下:
An unhandled exception occurred: Dll Reference Plugin Invalid Options

options.manifest.content should NOT have fewer than 1 properties
options.manifest.content should match some schema in anyOf
options.manifest should be string
options.manifest should match exactly one schema in oneOf
options should NOT have additional properties
options should have required property 'content'
options should have required property 'name'
options should match some schema in anyOf
導出模塊export-module.ts未導出任何命名,請添加一個,或者移除這個功能(搜索export-module,移除相關代碼及文件即可)
user avatar guochenglong 头像 nihaojob 头像 jcguanqi 头像 jingdongkeji 头像 littlelyon 头像 huajianketang 头像 inslog 头像 qian5201314 头像 zero_dev 头像 solvep 头像 woniuseo 头像 yqyx36 头像
点赞 115 用户, 点赞了这篇动态!
点赞

Add a new 评论

Some HTML is okay.