npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@expo-harmony/metro-config

v55.0.27-harmony.2

Published

[**GitHub 仓库**](https://github.com/renbaoshuo/expo-harmony/tree/master/packages/metro-config)

Readme

@expo-harmony/metro-config

GitHub 仓库

用于将 Expo Metro 配置与 React Native OpenHarmony(RNOH)组合起来,使 Expo 项目能够同时支持 HarmonyOS。

安装

npm install @expo-harmony/metro-config @expo/metro-runtime@^55.0.0 @react-native-oh/[email protected] metro-config@^0.83.0

这个包会隔离 Expo 与 RNOH 的 resolver 调用链:

  • Android、iOS 和 Web 请求继续使用 Expo 原有的 resolver。
  • Harmony 请求先经过项目自定义的重定向规则,再进入 RNOH resolver。
  • 当 RNOH 需要解析具体文件或依赖时,会重新委托给原有的 Expo resolver,因而能够保留 Expo Router、TypeScript paths 等 Expo 能力。

基础用法

按照下面的逻辑修改项目的 metro.config.js:

'use strict';

const { getDefaultConfig } = require('expo/metro-config');
const { withHarmonyConfig } = require('@expo-harmony/metro-config');

const projectRoot = __dirname;
const isHarmony = process.env.EXPO_METRO_TARGET === 'harmony';
let config = getDefaultConfig(projectRoot);

config = withHarmonyConfig(config, {
  enabled: isHarmony,
  projectRoot,
});

module.exports = config;

当 enabled 为 false 时,withHarmonyConfig 会直接返回传入的配置,且不会加载 RNOH 依赖。因此,应用可以将 @react-native-oh/react-native-harmony 放在 optionalDependencies 中,没有安装 Harmony 工具链的 Android、iOS 开发者也不会受到影响。

安装 @expo-harmony/cli 后,使用 expo-harmony start 启动 Metro,它会自动设置 EXPO_METRO_TARGET=harmony,再由 Harmony 原生应用发起 Harmony bundle 请求:

{
  "scripts": {
    "start": "expo start",
    "start:harmony": "expo-harmony start"
  }
}

Harmony 原生端通过 Expo virtual entry 请求 bundle:

/.expo/.virtual-metro-entry.bundle?platform=harmony&dev=true&minify=false&modulesOnly=false&runModule=true

Expo Metro 会把这个 URL 重写到 package.json#main 解析出的实际入口。不要向 Expo CLI 传递 --harmony,这样会导致无法正常启动。

配置

配置项覆盖了实际 Expo/RNOH 项目常见的适配场景:

const path = require('node:path');

config = withHarmonyConfig(config, {
  // 是否启用 Harmony 配置,默认为 true。
  // false 时原样返回 config,且不会加载 RNOH 和 metro-config peer dependencies。
  enabled: isHarmony,

  // 项目根目录。
  // 默认依次使用 config.projectRoot 和 process.cwd()。
  projectRoot,

  // 指定 RNOH 用来替代 react-native 的包名。
  // 不配置时默认使用 @react-native-oh/react-native-harmony。
  reactNativeHarmonyPackageName: '@react-native-oh/react-native-harmony',

  // 向 RNOH createHarmonyMetroConfig 透传当前 RNOH 版本支持的额外参数。
  // 顶层 reactNativeHarmonyPackageName 会覆盖这里的同名配置。
  harmonyConfigOptions: {
    // 在这里填写 RNOH 的高级 Metro 配置。
  },

  // 追加 Harmony 平台的 package exports conditions。
  // 默认为 ['harmony', 'react-native'];原有 conditions 会被保留并去重。
  conditions: ['harmony', 'react-native'],

  // 加载配置时写入 process.env 的额外变量。
  // 仅在显式配置时写入;默认不会污染共享 Metro 进程的环境变量。
  // 也可设为 false,明确禁止本次调用修改环境变量。
  env: {
    IS_HARMONY: 'true',
  },

  // 模块前缀别名,支持普通对象或 Map、精确匹配和子路径匹配。
  // 多项同时匹配时使用最长前缀;例如:
  // react/jsx-runtime 会变成 react-harmony/jsx-runtime,
  // @/components 会变成 <projectRoot>/components。
  aliases: {
    '@': projectRoot,
    api: path.join(projectRoot, 'api'),
    components: path.join(projectRoot, 'components'),
    react: 'react-harmony',
  },

  // 精确模块重定向,支持普通对象或 Map。每个目标可以是:
  // - 字符串会交给原有的 Expo resolver 解析;
  // - false 会返回 Metro 的 empty 结果;
  // - Metro resolution 对象;
  // - 接收当前请求并返回上述结果的函数;
  // - null/undefined 会继续尝试 aliases,最后进入 RNOH resolver。
  redirects: {
    'expo-blur': path.join(projectRoot, 'harmony-adapters/expo-blur.harmony.js'),
    'react-native-screens/experimental': false,
    '@/components/toolbox-icons': {
      type: 'sourceFile',
      filePath: path.join(projectRoot, 'components/toolbox-icons.harmony.tsx'),
    },
  },

  // 将匹配项解析为空模块,可用于屏蔽 Harmony 不支持的依赖。
  // 每项可以是精确模块名、正则表达式,或接收当前请求并返回布尔值的函数。
  emptyModules: [/MaterialSymbols/u],

  // 只处理 Harmony 请求,适合根据导入来源进行动态重定向。
  // redirects 中的动态函数和 emptyModules 的函数项也会收到相同结构的请求。
  // 可以返回 Metro resolution、交给 Expo resolver 解析的模块名或 false;
  // 返回 null/undefined 会继续尝试 redirects、aliases,最后进入 RNOH resolver。
  // resolve() 可直接调用 Expo resolver;resolveHarmony() 可跳过自定义规则调用 RNOH resolver。
  resolveRequest({
    // 当前 Metro 解析上下文,可通过 originModulePath 判断导入来源。
    context,
    // 当前尚未解析的 import 模块标识符。
    moduleName,
    // 当前请求平台;这个 hook 被调用时始终为 harmony。
    platform,
    // withHarmonyConfig 最终使用的绝对项目根目录。
    projectRoot: root,
    // 使用原有的 Expo/Metro resolver 解析模块;platform 可选,默认使用当前请求值。
    resolve,
    // 跳过所有自定义规则直接调用 RNOH resolver;参数可选,默认使用当前请求值。
    resolveHarmony,
  }) {
    if (moduleName === './SplashScreen' && context.originModulePath.includes(`${path.sep}expo-splash-screen${path.sep}`)) {
      return {
        type: 'sourceFile',
        filePath: path.join(root, 'harmony-adapters/SplashScreen.native.js'),
      };
    }
  },
});

Harmony 请求的 resolver 匹配顺序如下:

  1. emptyModules
  2. resolveRequest
  3. 精确匹配的 redirects
  4. 前缀匹配的 aliases,优先使用最长匹配项
  5. RNOH resolver

声明了 harmony.alias 的适配包可以直接导入同名官方包或其子路径。

与其他 Metro enhancer 组合

通用的 Metro enhancer 应在 withHarmonyConfig 之后应用:

const { withNativeWind } = require('nativewind/metro');

config = withHarmonyConfig(config, harmonyOptions);
module.exports = withNativeWind(config, { input: './global.css' });

这样 env 中的 Harmony 环境变量也能在 NativeWind 等后续配置读取时生效。

Author

expo-harmony © Baoshuo, Released under the MIT License. Authored and maintained by Baoshuo with help from contributors.

Personal Website · Blog · GitHub @renbaoshuo · Twitter @renbaoshuo