NX构建Angular可构建库封装JS库:脚本依赖加载失败配置咨询
我正在使用NX构建一个可构建的Angular库,目的是封装一个大型JavaScript库,目录结构如下:
> app > libs > my-lib > assets > js > script1.min.js > script2.min.js > script3.min.js > css > fonts > plugins > plugin1.min.js > plugin2.min.js > plugin3.min.js > src/lib/components > my-lib.module.ts
我在使用该库的应用的angular.json中进行了如下配置:
architect : { build : { options : { assets : [], scripts : [ "path_to_/script1.min.js", "path_to_/script2.min.js", "path_to_/script3.min.js", "path_to_/plugin1.min.js", "path_to_/plugin2.min.js", "path_to_/plugin3.min.js" ] } } }
目前该配置仅部分生效:script1和script2可正常执行,但script3执行失败,原因是它尝试加载plugin1、plugin2和plugin3,且我无法修改script3。
请问:
- 是否必须枚举库运行所需的所有脚本?
- 能否直接引用文件夹?
- 如何配置我的库,让脚本能够互相调用且无需修改脚本?
1. 是否必须枚举所有脚本?
不是必须,但脚本加载顺序与资源路径匹配是核心问题。你当前的故障并非因为枚举方式,而是script3按自身预期的路径(比如相对路径../plugins/plugin1.min.js)加载插件时,找不到正确的文件位置——直接将插件脚本全局引入破坏了它原本依赖的目录结构。
2. 能否直接引用文件夹?
Angular(含NX)的scripts配置不支持直接引用文件夹,但可以用通配符批量匹配文件,示例:
scripts: [ "libs/my-lib/assets/js/*.min.js", "libs/my-lib/assets/plugins/*.min.js" ]
注意:通配符按文件名排序加载,若script3依赖插件先加载,这种方式可能无法保证顺序,需手动调整或确认文件名排序符合依赖要求。
3. 让脚本互相调用无需修改的配置方法
核心思路是保留script3预期的目录结构,同时让构建工具正确复制资源并映射路径:
步骤1:配置库的资产复制规则
在库的project.json(NX项目配置文件)中,添加资产复制规则,将assets目录完整复制到构建输出目录,保持原层级:
"build": { "options": { "assets": [ { "input": "libs/my-lib/assets", "output": "assets/my-lib", "glob": "**/*" } ] } }
构建后,资源会被复制到dist/libs/my-lib/assets/my-lib下,保持js/与plugins/的同级结构,匹配script3的路径预期。
步骤2:调整应用的脚本加载路径
在应用的angular.json中,修改脚本路径为库构建后的输出路径,同时确保插件在script3之前加载:
"scripts": [ "dist/libs/my-lib/assets/my-lib/js/script1.min.js", "dist/libs/my-lib/assets/my-lib/js/script2.min.js", "dist/libs/my-lib/assets/my-lib/plugins/plugin1.min.js", "dist/libs/my-lib/assets/my-lib/plugins/plugin2.min.js", "dist/libs/my-lib/assets/my-lib/plugins/plugin3.min.js", "dist/libs/my-lib/assets/my-lib/js/script3.min.js" ]
此时script3在js/目录,插件在同级plugins/目录,完全匹配它的路径预期,可正常加载依赖。
步骤3:(可选)封装脚本加载逻辑,无需应用手动配置
在库的my-lib.module.ts中,通过APP_INITIALIZER动态加载脚本,让应用只需导入库模块即可,无需修改angular.json:
import { APP_INITIALIZER, NgModule } from '@angular/core'; function loadExternalScripts() { return () => new Promise(resolve => { const scriptUrls = [ './assets/my-lib/js/script1.min.js', './assets/my-lib/plugins/plugin1.min.js', './assets/my-lib/plugins/plugin2.min.js', './assets/my-lib/plugins/plugin3.min.js', './assets/my-lib/js/script3.min.js' ]; let loadedCount = 0; scriptUrls.forEach(url => { const script = document.createElement('script'); script.src = url; script.onload = () => { loadedCount++; if (loadedCount === scriptUrls.length) resolve(true); }; document.body.appendChild(script); }); }); } @NgModule({ providers: [ { provide: APP_INITIALIZER, useFactory: loadExternalScripts, multi: true } ] }) export class MyLibModule { }
内容的提问来源于stack exchange,提问作者Jax Teller

