问题
在小程序端,不少开发者都有使用小程序原生自定义组件的需求,uniapp 也是支持使用小程序自定义组件的,只不过要放在根目录的 wxcomponents、mycomponents 等下面,详见官方文档。
但是,在 5.03 之前,uniapp 仅支持在根目录存放自定义组件,很多开发者面临着包体积超出的问题
从 5.03 起,uniapp 开始支持在分包的根目录添加 wxcomponents、mycomponents 等
源码
此部分为源码分析,感兴趣的掘友可以看下
在 uniapp 仓库 中,支持的每一个小程序都有一个专门的包
复制操作是通过内部的 vite 插件实现的,具体位置在 packages/uni-cli-shared/src/vite/plugins/copy.ts,感兴趣的掘友可以看下。
框架已经封装好了复制的插件,对于各端来说,只需要做好配置就行。我们是要支持分包能复制 wxcomponents、mycomponents,这看起来就很简单了,只需要处理好分包的路径就行,代码比较简单,直接贴出来了
/**
* 在将小程序组件相关资源(例如固定目录名下的静态文件)复制到构建产物时,
* 生成本次复制所需的目录路径与 glob 模式列表。
*
* 返回值始终包含:
* - 项目根(相对复制根目录)下名为 `dir` 的目录。
* - 每个 `uni_modules` 插件包下对应子目录的 glob:与本函数内局部变量 `uniModulesDir` 相同
* (前缀为 `uni_modules`、通配段、`dir`、以及递归匹配尾部)。
*
* 当已设置 `UNI_INPUT_DIR`、`UNI_PLATFORM`,且输入目录下存在 `pages.json` 时,会从
* `subPackages` 或 `subpackages` 读取分包根路径;对每个 `root` 再追加两项:
* `normalizePath(path.join(root, dir))` 与 `normalizePath(path.join(root, uniModulesDir))`。
*
* 若缺少环境变量或不存在 `pages.json`,则只返回上述项目根级别的两项。
*
* @param dir - 资源目录名称(例如 `wxcomponents`)
* @returns 非空数组,元素为规范化后的路径或 glob 字符串,供复制或监听工具使用。
*/
export function createCopyComponentDirs(dir: string) {
const dirs = [dir]
const uniModulesDir = 'uni_modules/*/' + dir + '/**/*'
dirs.push(uniModulesDir)
const inputDir = process.env.UNI_INPUT_DIR
const platform = process.env.UNI_PLATFORM
if (!inputDir || !platform) {
return dirs
}
const pagesJsonFile = path.resolve(normalizePath(inputDir), 'pages.json')
if (!fs.existsSync(pagesJsonFile)) {
return dirs
}
const { appJson } = parseMiniProgramPagesJson(
fs.readFileSync(pagesJsonFile, 'utf8'),
platform,
{ subpackages: true }
)
const roots: string[] = Object.values(
appJson.subPackages || appJson.subpackages || {}
)
.map(({ root }) => root)
.filter(Boolean)
roots.forEach((root) => {
dirs.push(
normalizePath(path.join(root, dir)),
normalizePath(path.join(root, uniModulesDir))
)
})
return dirs
}
注意事项
wxcomponents、mycomponents 等目录下方文件的处理是 全部拷贝到产物中,没有 treeShaking,因为需要开发者梳理组件的使用和存放。
交流群
我建了一个微信群(非官方),大家可以在群里和我沟通交流 uniapp 开发遇到的问题、uniapp 的源码等问题。