import { CompileTypes, Config, EntryBuilderHelpers, EntryFileType, EntryItem, EntryReferType, EntrySources, EntryType, ModuleGraph, ObjectValues, Runner, RunnerContext, webpack, WebpackWrapper } from '@morjs/utils'; import { CompilerPlugin } from '../compilerPlugins'; import { CompileModes, CompilerUserConfig } from '../constants'; import { IAppConfig, IComponentsConfig, IPluginConfig, ISubPackageConfig } from '../types'; declare type ConditionalExtsPropName = keyof { [key in EntryFileType as `${key}WithConditionalExts`]: 0; }; /** * 普通后缀的属性名称类型 */ declare type ExtsPropName = keyof { [key in EntryFileType as `${key}Exts`]: 0; }; /** * 支持后缀的配置 */ declare type SupportExts = { [key in ConditionalExtsPropName | ExtsPropName]: string[]; }; declare type EntryName = string; declare type EntryNameWithoutExt = string; declare type EntryFullPath = string; declare type CompileType = ObjectValues; declare type CompileMode = ObjectValues; /** * 生成编译需要的 entry files * 页面或组件中的每个文件均为单独的 entry */ export declare class EntryBuilder implements SupportExts, EntryBuilderHelpers { config: Config; userConfig: CompilerUserConfig; webpackWrapper: WebpackWrapper; context: RunnerContext; runner: Runner; /** * 支持的文件类型 */ templateExts: string[]; configExts: string[]; styleExts: string[]; sjsExts: string[]; scriptExts: string[]; /** * 支持的文件类型, 含条件编译的文件后缀 */ templateWithConditionalExts: string[]; configWithConditionalExts: string[]; styleWithConditionalExts: string[]; sjsWithConditionalExts: string[]; scriptWithConditionalExts: string[]; /** * 用于 default 模式下的 glob 操作 */ globPatterns: string; /** * 所有的 entry 信息 * 这里的 EntryName 除 js 文件之外均包含后缀名 * EntryItem 中的 entryName 是不包含后缀名的 entry 相对路径 */ entries: Map; /** * 用于记录文件完整路径和 entry 名称 */ entryRecords: Map; /** * 文件及引用映射 * Record 的 key 为 引用路径, value 为 实际文件的完整路径 * 实际使用的时候 可以通过完整路径获取生成后的路径 */ referencesMap: Map>; /** * 自定义组件映射关系 * 用于记录每个 entry 使用的 自定义组件名称 * 在后续的模版解析和处理中用于识别 template 的自定义组件标签 */ usingComponentsMap: Map; /** * 记录文件修改时间和原始大小 */ fileStats: Map; /** * 用于记录 transform 编译模式中 script 的文件内容 */ replaceEntrySources: EntrySources; /** * 用于生成 json 文件 */ additionalEntrySources: EntrySources; /** * 条件编译后缀 */ conditionalFileExts: string[]; /** * 条件编译后缀规则,用于生成 RegExp */ conditionalFileExtsPattern: string; /** * 条件编译后缀正则 */ conditionalFileExtsRegExp: RegExp; /** * 源代码目录 */ srcPaths: string[]; /** * 后缀名映射 */ extMap: Record; /** * 支付宝小程序文件类型 */ alipayFileTypes: CompilerPlugin['fileType']; /** * 微信小程序文件类型 */ wechatFileTypes: CompilerPlugin['fileType']; /** * 目标文件类型 */ targetFileTypes: CompilerPlugin['fileType']; /** * app 入口 json 文件 */ appJson?: IAppConfig; /** * subpackage 入口 json 文件 */ subpackageJson?: ISubPackageConfig; /** * plugin 入口 json 文件 */ pluginJson?: IPluginConfig; /** * 独立分包配置 */ independentSubpackages: Map; /** * 全局脚本文件 */ globalScriptFilePath?: string; /** * 全局 app 名称 */ globalAppName?: string; /** * 全局样式文件 */ globalStyleFilePath?: string; /** * 全局配置文件 */ globalConfigFilePath?: string; /** * 项目名称 */ projectName?: string; /** * 模块依赖图, 用于 bundle 分析 和 分组 */ moduleGraph: ModuleGraph; /** * npm 组件的文件和包名映射 */ pathAndPackageNames: Map; /** * 用到的 npm 包 * key 为 包名 * value 为 包地址 */ usedNpmPackages: Map; /** * 针对当前 target * npm 包应当取用的 mainField 值 */ npmMainFields: Map; /** * template 引用标签名称 */ templateImportTagNames: string[]; /** * template 引用正则 */ tempalteImportTagRegExp: RegExp; /** * 初始化标记, 用于确保 lazyInitialize 只执行一次 */ private initialized; private fs; constructor(config: Config, userConfig: CompilerUserConfig, webpackWrapper: WebpackWrapper, context: RunnerContext, runner: Runner); private initialize; /** * 为每个配置生成独立文件夹, 避免发生冲突 */ private getEntryCacheFileName; /** * 尝试将 entryBuilder 保存至缓存 * 保存前检查已有缓存是否已过期 */ trySaveToCache(): Promise; /** * 获取 缓存 key * 支持 通过 runner.context 传递 entryCacheKey */ getCacheKey(): string; /** * 尝试从缓存中构建 EntryBuilder 以加快分析速度 */ tryRestoreFromCache(): Promise; /** * 获取引用路径对应的真实路径 * @param sourcePath - 源文件路径 * @param referencePath - 引用文件路径 * @param withExt - 是否携带后缀名, 默认为 false * @returns 返回 posix 类型的引用路径 */ getRealReferencePath(sourcePath: string, referencePath: string, withExt?: boolean): string | undefined; /** * 获取引用文件的真实路径 * @param sourcePath - 源文件 * @param referencePath - 引用路径 */ getFullPathOfReferenceFile(sourcePath: string, referencePath: string): string | undefined; /** * 获取 源 entry 和 目标 entry 的相对路径 * @param sourceEntry - 源 entry * @param targetEntry - 目标 entry * @param withExt - 是否携带后缀名 * @returns 返回 posix 类型的相对路径 */ getRelativePathFor(sourceEntry: EntryItem, targetEntry: EntryItem, withExt?: boolean): string; /** * 设置 entry 源码用于替换或额外输出 * @param entryName - entry 名称 * @param content - entry 内容 * @param aim - 目标, 可选值为 replace 或 additional * @param saveToMemFile - 需要输出为内存文件路径,aim 为 additional 时,如未提供 saveToMemFile, 则会基于 entryName 自动生成 */ setEntrySource(entryName: string, content: string, aim: 'replace' | 'additional', saveToMemFile?: string): void; /** * 初始化, Entry 会在比较早的时间进行实例化 * 如果初始化太早, 则 userConfig 中的配置不是最终配置 * 目前 entryBuilder 首次初始化的时机为 build 的时候 */ private lazyInitialize; /** * 解析需要支持的 exts * NOTE: 后缀顺序需要按照 EntryPriority 中定义的顺序来 * @param target - 编译目标 * @param conditionalExts - 条件后缀 */ chooseSupportExts(target: string, conditionalExts: string | string[]): SupportExts; /** * 构建 entry, 同时处理文件维度的条件编译 * bundle 和 transform 编译模式是通过 * app.json / subpackage.json / plugin.json / component.json 等入口来构建 entry * 区别是 bundle 会将 npm 组件文件拷贝至 outputPath/npm_components 中 * 而 transform 不强制 入口文件存在,入口文件存在时会从入口文件分析依赖树 * 入口文件不存在时,则通过 glob 的方式来获取所有文件 */ build(): Promise; /** * 清理无用的 entries * 基于 moduleGraph 来应用变更 */ private clearUnusedEntries; /** * watch 状态下 每次触发 build 前需要基于 modifiedFiles 和 removedFiles 清理 entry * NOTE: 后面可以考虑基于性能优化 将 modifiedFiles 中的 dir 进行处理 */ private invalidateModifiedOrDeletedFiles; /** * 删除和文件相关的所有信息 * @param filePath - 文件路径 */ private deleteAllFileInfos; /** * 通过文件地址获取使用的自定义组件名称数组 * @param filePath - 文件地址 * @returns 当前路径对应的 entry 可能使用到的自定义组件名称(包含全局组件) */ getUsingComponentNames(filePath: string): string[]; /** * 获取全局组件相对于当前引用文件的相对路径 * @param sourceEntry - 引用全局组件的 entry * @param globalComponentName - 全局组件的名称 * @returns 全局组件之于当前文件的相对路径 */ getGlobalComponentRelativePath(sourceEntry: EntryItem, globalComponentName: string): string | undefined; /** * 获取 完整的 entry 名称 * @param filePath - 文件完整路径 * @returns 完整的 entry 名称(含后缀名) */ getFullEntryName(filePath: string): string | undefined; /** * 基于路径获取 entry * @param filePath - 文件完整路径 */ getEntryByFilePath(filePath: string): EntryItem | undefined; /** * 判断是否是 entry 文件 * @param filePath - 文件地址 */ isEntryFile(filePath: string): boolean; /** * 提供 extname => entryFileType 转换 * @param extname - 文件后缀 */ private extToEntryFileType; /** * 读取并使用条件编译预处理类 JSON 文件 * 支持 json、 jsonc、json5 三种格式 * @param filePath - 类 json 文件 * @returns json 文件内容 */ private readAndPreprocessJsonLikeFile; /** * 保存文件最新的修改时间和大小 * 注意: 该方法为异步方法, 非实时更新 * @param filePath - 文件路径 */ private setOrUpdateFileStat; /** * 获取文件状态 * @param filePath - 文件路径 * @return 文件状态 */ private fetchFileStatDesc; /** * 判断是否需要继续分析当前文件的依赖 * @param filePath - 文件路径 */ private shouldAnalyzeFileDepenencies; /** * 基于分包优化调整 npm 中组件的路径 */ private alterEntryForSubpackageOptimize; /** * 获取相对于 srcPaths 的路径 * - 优先匹配 包含 srcPath 的相对路径 * - 如果没有包含的,则使用第一个 srcPath 计算 相对路径 * @param filePath - 文件完整路径 * @param srcPaths - 自定义 srcPaths 目录 * @returns 相对路径 */ getRelativePathToSrcPaths(filePath: string, srcPaths?: string[]): string; /** * 重命名 entry * @param prevEntryName - 旧的 entry 名称 * @param newEntryName - 新的 entry 名称 * @param filePath - 完整文件路径 * @param entry - entry 对象 */ private renameEntry; /** * 过滤并添加到 entries 中, 实现文件条件编译 * @param filePath - 文件完整路径 * @param entryType - Entry 类型 * @param entryReferType - 引用来源类型 * @param parentEntry - 父级 entry * @param groupName - 所在组 * @param customEntryName - 自定义 entry 名称, 不带后缀名, 如 pages/my/usercenter * @param srcPaths - 自定义 srcPaths 目录 */ addToEntry(filePath: string, entryType?: EntryType, entryReferType?: EntryReferType, parentEntry?: EntryItem, groupName?: string, customEntryName?: EntryName, srcPaths?: string[]): EntryItem | undefined; /** * 计算 entry 的优先级 * @param extname - 文件后缀名 * @param isConditionalFile - 是否为条件编译文件 * @param priorityAmplifier - 放大条件编译文件的优先级, 放大数字为 5 * priorityAmplifier * @param entryType - Entry 分类,根据类型返回既定值 */ private calculateEntryPriority; /** * 需要将查找文件的上下文转换为虚拟的目录地址 * @example * ``` * 例如: * 假设 rootDirs 为 ['/aaa/dir1', '/bbb/ccc/dir2'] * contexts 为 ['/aaa/dir1/mmm'] * 那么需要将 contexts 转换为 ['/aaa/dir1/mmm', '/bbb/ccc/dir2/mmm'] * 以确保 rootDirs 中不同根目录下的文件可以相互引用 * ``` * @param contexts - 文件的上下文 目录地址, contexts 的来源可能是 父文件的目录也可能是 srcPaths * @param rootDirs - 根目录 * @returns 转换后的上下文目录列表 */ private expandContextsAccordingToRootDirs; /** * ``` * 基于 后缀的顺序,返回第一个命中的文件路径 * 文件维度条件编译的核心逻辑 * fileExts 参数中需要确保条件编译文件后缀优先于普通文件后缀 * ``` * @param fileName - 文件名称, 不含后缀 * @param fileExts - 尝试获取的文件后缀列表 * @param contexts - 文件的上下文 目录地址, contexts 的来源可能是 父文件的目录也可能是 srcPaths * @param parentPath - 引用该文件的路径, 主要用于输出警告信息, 可选值 * @param rootDirs - 文件检索根目录, 默认为 srcPaths * @returns 返回第一个命中的文件 */ tryReachFileByExts(fileName: string, fileExts: string[], contexts: string[], parentPath?: string, rootDirs?: string[]): Promise; /** * 通过 glob 的方式构建 entry * * @param globPattern - 模式 */ buildByGlob(globPattern?: string): Promise; /** * 基于不同的 compileType 类型来解析入口的 entry 配置文件 * * 不同 compileType 对应的问题为: * - miniprogram: app.json * - subpackage: subpackage.json * - plugin: plugin.json * - component: component.json * * 注意: compileType 为 subpackage 时, 会优先从 context 中获取 subpackageJson * * 当 compileMode 为 transform 时, 不强制要求 entry 文件存在 * @param compileType - 编译类型 * @param compileMode - 编译模式 * @returns 是否需要额外编译支持, 仅用于 transform 模式下未找到 entry 文件的情况 */ buildByCompileType(compileType: CompileType, compileMode: CompileMode): Promise; /** * 加载小程序项目配置文件 */ private tryAddProjectConfigFile; /** * 尝试载入自定义的 entries */ private tryAddCustomEntries; /** * 处理 app.x 以及 mockAppEntry 逻辑 * 插件优先使用 mor.plugin.app * 分包优先使用 mor.subpackage.app */ private tryAddGlobalFiles; /** * 尝试载入其他配置文件 * - sitemap.json * - theme.json * - preload.json * - ext.json */ private tryLoadExtraConfigFiles; /** * 解析 app.json * 以及 从 app.json 推断 plugin.json 或 subpackage.json * @param appJson 小程序配置内容 * @param appJsonPath 小程序配置路径 * @param compileType 编译类型, 可以指定为 plugin 或 subpackage, 用于模拟对应的配置 */ buildByApp(appJson: IAppConfig, appJsonPath: string, compileType?: CompileType): Promise; /** * 解析 subpackage.json 并构建 entry * @param subpackageJson 分包配置内容 * @param subpackageJsonPath 分包配置路径 * @param parentEntry 父级 entry */ buildBySubPackage(subpackageJson: ISubPackageConfig, subpackageJsonPath?: string, parentEntry?: EntryItem): Promise; /** * 解析 plugin.json 并构建 entry * @param pluginJson - 插件配置内容 * @param pluginJsonPath - 插件配置路径 * @param parentEntry - 父级 entry */ buildByPlugin(pluginJson: IPluginConfig, pluginJsonPath?: string, parentEntry?: EntryItem): Promise; /** * 解析 component.json 并构建 entry * @param componentJson - 组件配置内容 * @param componentJsonPath - 组件配置路径 * @param parentEntry - 父级 entry */ buildByComponent(componentJson: IComponentsConfig, componentJsonPath?: string, parentEntry?: EntryItem): Promise; /** * 添加页面 entries * @param pages - 页面数组, 支持数组或对象, 对象可用于指定自定义 entry 名称 * @param parentEntry - 父级 entry * @param groupName - 分组名称 * @param rootDirs - 文件检索根目录, 可选, 默认为 srcPaths */ addPageEntries(pages: string[] | Record, parentEntry: EntryItem, groupName?: string, rootDirs?: string[]): Promise; /** * 获取路径中的 npm 包名 * @param filePath - 引用路径 */ getPackageName(filePath: string): string; /** * 添加组件 entries * @param components - 组件对象 * @param parentEntry - 上一级 EntryItem * @param rootDirs - 文件检索根目录, 可选, 默认为 srcPaths * @param preferRelative - 是否倾向于按照相对目录解析组件 * @param componentPlaceholder - 占位组件配置 * @param treatComponentNameAsCustomEntryName - 是否将组件名称作为作为自定义 entry 名称,默认为 false */ addComponentEntries(components: Record, parentEntry: EntryItem, rootDirs?: string[], preferRelative?: boolean, componentPlaceholder?: Record, treatComponentNameAsCustomEntryName?: boolean): Promise; /** * 基于引用的名称添加相关的 entries * @param referencePath - 不包含后缀的引用路径, 如 ./components/index * @param entryType - 代表当前页面组件被谁引用 * @param parentEntry - 父级别 entry, 即引用当前文件的文件 * @param fileType - 文件类型 * @param groupName - 文件所在组 * @param entryReferType - 引用类型, 用于标识直接引用或间接引用, 默认为 `direct` * @param customEntryName - 自定义 entry 名称, 不带后缀名, 如 `pages/my/usercenter` * @param rootDirs - 文件检索根目录, 可选, 默认为 srcPaths * @param preferRelative - 是否倾向于按照相对目录解析组件 */ tryAddEntriesFromPageOrComponent(referencePath: string, entryType: EntryType, parentEntry: EntryItem, fileType?: EntryFileType, groupName?: string, entryReferType?: EntryReferType, customEntryName?: string, rootDirs?: string[], preferRelative?: boolean): Promise; /** * 建立文件和文件之间的引用映射及引用真实路径关系 * @param parentPath - 父路径 * @param referencePath - 引用路径 * @param referenceRealPath - 引用真实路径 */ private linkReferenceRelationShip; /** * 处理 *xml 文件的依赖 * @param entry - 当前文件 entry * @param rootDirs - 文件检索根目录, 可选, 默认为 srcPaths */ private processXmlFileDependencies; /** * 解析 sjs 依赖 * @param entry - 当前文件 entry * @param content - 当前文件内容 * @param rootDirs - 文件检索根目录, 可选, 默认为 srcPaths */ private processSjsFileDependencies; /** * 解析 sjs 依赖 * @param entry - 当前文件 entry * @param content - 当前文件内容 * @param rootDirs - 文件检索根目录, 可选, 默认为 srcPaths */ private processJsFileDependencies; /** * 获取 webpack normal resolver * @param options - ResolverOptions 用于传递给 resolver */ private getResolver; /** * 解析 npm 文件的真实路径 * @param contextDir - 上下文所在的文件夹 * @param requestPath - 请求路径 * @param fromNodeModules - 是否查找 node_modules, 代表是否启用 多端组件规范 * @param suppressError - 是否忽略 错误 * @param options - ResolverOptions 用于传递给 resolver */ private resolveRealFilePath; /** * 替换文件路径为 构建目标 真正需要的文件路径 * 主要目的为: 支持多端组件库 * 路径替换需要遵从 《多端组件库规范》 * @param realPath - 文件真实路径 * @param requestPath - 实际请求的路径 * @param packageJson - package.json 文件内容 * @param packagePath - package.json 文件地址 */ private replaceRealPathByTarget; /** * 替换文件后缀为期望的后缀,用于解决源代码后缀和目标产物文件后缀不同的情况 * @param filePath - 原始文件路径 * @returns 替换过后缀的文件路径 */ replaceExtAsExpected(filePath: string): string; } export {};