Monorepo에서 app in toss 앱이 안켜집니다

이 글의 성격은 무엇인가요?

질문 / 문제 해결

내용을 설명해주세요

  • 개발환경: React Native
  • 문제:pnpm moonrepo 에서 초기 앱 셋팅만 한채로 켜도 작동하지 않습니다. (이미 expo app 사용중인 것이 있음), 어떻게 해결해야 할까요?
> @app-name/inapp-toss-test@ dev /Users/sarasinakei/Documents/app-name-workspace-02/packages/inapp-toss-dreame
> granite dev


 ██████╗ ██████╗  █████╗ ███╗   ██╗██╗████████╗███████╗
██╔════╝ ██╔══██╗██╔══██╗████╗  ██║██║╚══██╔══╝██╔════╝
██║  ███╗██████╔╝███████║██╔██╗ ██║██║   ██║   █████╗  
██║   ██║██╔══██╗██╔══██║██║╚██╗██║██║   ██║   ██╔══╝  
╚██████╔╝██║  ██║██║  ██║██║ ╚████║██║   ██║   ███████╗
 ╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝  ╚═══╝╚═╝   ╚═╝   ╚══════╝

                  Welcome to Granite

To reload the app press "r"
To open developer menu press "d"
To open debugger press "j"

Development server is running at http://0.0.0.0:8081
 BUNDLE  ./index.ts 

error: ../../node_modules/.pnpm/react-native-webview@13.6.2_react-native@0.81.5_@babel+core@7.28.6_@react-native-commun_557a86e07df7d9476547a08d4aab8128/node_modules/react-native-webview/lib/RNCWebViewNativeComponent.js: /Users/sarasinakei/Documents/app-name-workspace-02/node_modules/.pnpm/react-native-webview@13.6.2_react-native@0.81.5_@babel+core@7.28.6_@react-native-commun_557a86e07df7d9476547a08d4aab8128/node_modules/react-native-webview/lib/RNCWebViewNativeComponent.js: Could not find component config for native component

webview package 설치해도 증상은 같습니다.
react-native 0.81.5
react 19.1.0
@apps-in-toss/framework”: “1.9.4”,
@granite-js/react-native”: “0.1.34”,
@granite-js/native”: “0.1.34”,

저는 이 패치 적용해서 해결했습니다. 토스에서 머지해 주시면 좋겠네요 ㅎㅎ

1개의 좋아요

@starlight 헉.. 감사합니다. 혹시 패치 파일 가지고 계신 것이 있으실까요?! 몇 버전 쓰고 작동 하셨는지도 궁금합니다.

패치 파일을 업로드하려니 첨부가 안 되네요.

patches/@granite-js__mpack@0.1.33.patch를 아래 내용으로 생성하고

diff --git a/dist/metro/enhancedResolver.js b/dist/metro/enhancedResolver.js
index ecc4ee02fd28b612c5dd0ecb5d3126de8c1df4dc..a3258680eb08677b18203f0b9825712433716c72 100644
--- a/dist/metro/enhancedResolver.js
+++ b/dist/metro/enhancedResolver.js
@@ -66,7 +66,11 @@ function createResolver(rootPath, options) {
       mainFields: context.mainFields,
       conditionNames: options?.conditionNames ?? [...import_constants.RESOLVER_EXPORTS_MAP_CONDITIONS, "require", "node", "default"],
       mainFiles: ["index"],
-      modules: ["node_modules", import_path.default.join(rootPath2, "src")]
+      modules: ["node_modules", import_path.default.join(rootPath2, "src")],
+      alias: {
+        "react-native": import_path.default.join(rootPath2, "node_modules", "react-native"),
+        react: import_path.default.join(rootPath2, "node_modules", "react")
+      }
     });
     function resolve(context2, request) {
       for (const nativeModule of NATIVE_MODULES) {
diff --git a/dist/metro/getMetroConfig.js b/dist/metro/getMetroConfig.js
index df272ce099bed94483da009e1ec446a710c489d2..d769377a92dfdd69600e54ab88473daec6712a24 100644
--- a/dist/metro/getMetroConfig.js
+++ b/dist/metro/getMetroConfig.js
@@ -31,14 +31,14 @@ __export(getMetroConfig_exports, {
   getMetroConfig: () => getMetroConfig
 });
 module.exports = __toCommonJS(getMetroConfig_exports);
-var import_path = __toESM(require("path"));
 var import_utils = require("@granite-js/utils");
-var import_enhancedResolver = require("./enhancedResolver");
-var import_getMonorepoRoot = require("./getMonorepoRoot");
+var import_path = __toESM(require("path"));
 var import_constants = require("../constants");
 var import_defaults = require("../vendors/metro-config/src/defaults");
 var import_exclusionList = __toESM(require("../vendors/metro-config/src/defaults/exclusionList"));
 var import_loadConfig = require("../vendors/metro-config/src/loadConfig");
+var import_enhancedResolver = require("./enhancedResolver");
+var import_getMonorepoRoot = require("./getMonorepoRoot");
 const INTERNAL_CALLSITES_REGEX = new RegExp(
   [
     "/Libraries/Renderer/implementations/.+\\.js$",
@@ -100,12 +100,12 @@ async function getMetroConfig({ rootPath }, additionalConfig) {
       resolveRequest,
       // metro-file-map
       sourceExts: [...import_constants.SOURCE_EXTENSIONS.map((extension) => extension.replace(/^\.?/, "")), "cjs", "mjs"],
-      blockList: (0, import_exclusionList.default)(
-        additionalConfig?.resolver?.blockList ? asArray(additionalConfig.resolver.blockList) : []
-      ),
-      nodeModulesPaths: additionalConfig?.resolver?.nodeModulesPaths || [],
+      blockList: (0, import_exclusionList.default)([
+        ...additionalConfig?.resolver?.blockList ? asArray(additionalConfig.resolver.blockList) : []
+      ]),
+      nodeModulesPaths: [import_path.default.join(rootPath, "node_modules"), ...additionalConfig?.resolver?.nodeModulesPaths || []],
       extraNodeModules: additionalConfig?.resolver?.extraNodeModules || {},
-      disableHierarchicalLookup: additionalConfig?.resolver?.disableHierarchicalLookup,
+      disableHierarchicalLookup: additionalConfig?.resolver?.disableHierarchicalLookup ?? true,
       resolverMainFields: additionalConfig?.resolver?.resolverMainFields ?? import_constants.RESOLVER_MAIN_FIELDS
     },
     serializer: {
diff --git a/dist/vendors/metro/src/node-haste/DependencyGraph.js b/dist/vendors/metro/src/node-haste/DependencyGraph.js
index 5e1f0aa49ab102a3556fd4dd1df95f5cdd238438..886d2c2569209894dce7558b50debd87ca02c022 100644
--- a/dist/vendors/metro/src/node-haste/DependencyGraph.js
+++ b/dist/vendors/metro/src/node-haste/DependencyGraph.js
@@ -141,14 +141,24 @@ class DependencyGraph extends EventEmitter {
     const containerName = splitIndex !== -1 ? filename.slice(0, splitIndex + 4) : filename;
     const realpath = fs.realpathSync(containerName);
     const resolvedPath = (pnpapi ? pnpapi.resolveVirtual(realpath) : realpath) ?? realpath;
-    const sha1 = this._hasteFS.getSha1(resolvedPath);
+    let sha1 = this._hasteFS.getSha1(resolvedPath);
+    if (!sha1 && resolvedPath !== filename) {
+      sha1 = this._hasteFS.getSha1(filename);
+    }
     if (!sha1) {
-      throw new ReferenceError(
-        `SHA-1 for file ${filename} (${resolvedPath}) is not computed.
-         Potential causes:
-           1) You have symlinks in your project - watchman does not follow symlinks.
-           2) Check \`blockList\` in your metro.config.js and make sure it isn't excluding the file path.`
-      );
+      try {
+        const crypto = require("crypto");
+        const content = fs.readFileSync(resolvedPath);
+        sha1 = crypto.createHash("sha1").update(content).digest("hex");
+      } catch (error) {
+        throw new ReferenceError(
+          `SHA-1 for file ${filename} (${resolvedPath}) is not computed.
+           Potential causes:
+             1) You have symlinks in your project - watchman does not follow symlinks.
+             2) Check \`blockList\` in your metro.config.js and make sure it isn't excluding the file path.
+           Error: ${error.message}`
+        );
+      }
     }
     return sha1;
   }

pnpm-workspace.yaml

patchedDependencies:
  '@granite-js/mpack@0.1.33': patches/@granite-js__mpack@0.1.33.patch

추가하시면 됩니다.

다른 의존성들 버전은

catalog:
  '@apps-in-toss/framework': 1.9.4
  '@granite-js/native': 0.1.33
  '@granite-js/react-native': 0.1.33
  '@granite-js/plugin-hermes': 0.1.33
  '@granite-js/plugin-router': 0.1.33
  '@toss/tds-react-native': 1.3.8
  'babel-preset-granite': 0.1.33
  'react': 18.2.0
  'react-native': 0.72.6
  'typescript': 5.9.3

이렇게 사용하고 있습니다.

감사합니다!! 적용 + bablel rn 기본으로 하니 이제 번들링 중 RNC native 에러가 나네요 ..ㅠㅠ
rn 0.81 , react 19 랑 제대로 호환이 안되는것처럼 보이네요.

나중에 시간날때 다시 해봐야겠네요;;

도와주셔서 감사합니다 ㅎㅎ

아직 RN 0.72, React 18 쓰셔야 해요! Granite 1.x부터 RN 0.84 지원되는 것 같아요

아 그렇군요! 감사합니다..! 아직 버전은 안올라왔군요.. ㅜㅜ 0.72는 지원 끊긴지가 너무 오래되서 그냥 기다려야 겠네요