Skip to content

refactor(router)!: extract standalone @granite-js/router - #443

Draft
gronxb wants to merge 5 commits into
mainfrom
feat/standalone-router
Draft

gronxb wants to merge 5 commits into
mainfrom
feat/standalone-router

Conversation

@gronxb

@gronxb gronxb commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Extract @granite-js/router as a standalone package and make @granite-js/react-native depend on it. App registration only mounts the app with initial props and visibility lifecycle; the app renders Router below its providers so hook-derived screen defaults flow through normal React props.

  • The Router package owns file-based route definitions, typed navigation, the stack, and back-handler contexts. It has no dependency on app registration or host bridges; compatible @granite-js/native, React, and React Native peers supply the native implementations.
  • The React Native package re-exports the routing API and provides a thin Router adapter that forwards host activity. Standalone consumers use AppState by default or inject isActive, entry URLs, and onRootBack.
  • defaultScreenOptions receives route, navigation, theme, routeIndex, and onBack. Updating options preserves the mounted stack. The singular spelling remains a deprecated Router alias.
  • Existing imports share the same route registry and back-handler contexts. New generated route declarations target @granite-js/router; legacy @granite-js/react-native module augmentation remains supported.
  • Update app templates, examples, package metadata, and English/Korean migration documentation. Clean old declarations from builds so moved implementations are not retained in the published package.
import { Router } from '@granite-js/router';

function App({ initialUrl }: { initialUrl?: string }) {
  const dark = useColorScheme() === 'dark';
  return (
    <Router
      context={context}
      prefix="example://app"
      initialUrl={initialUrl}
      defaultScreenOptions={({ routeIndex }) => ({
        headerLeft: routeIndex === 0 ? () => <Pressable onPress={() => closeView()}><Text>X</Text></Pressable> : null
      })}
    />
  );
}

For registered apps, import the host-aware Router adapter from @granite-js/react-native or @granite-js/react-native/router and register with Granite.registerApp(App, { appName }).

Migration

Breaking change / major changeset: registration no longer accepts route context, router options, initial URL resolution, or gesture callbacks and no longer injects Navigator children. Render Router explicitly and supply those settings to it. Call hooks in the parent component, not inside the options callback. Supply onRootBack when the host view should close.

Add @granite-js/router as a direct dependency when importing it or using newly generated route declarations. React Navigation remains the underlying engine.

Validation

  • Router: 98 tests; React Native integration: 57 tests; router generator: 32 tests passed.
  • Router and React Native typechecks/builds, generator build, app generator typecheck, and immutable install passed. Changed-file lint has no errors; four existing hook-dependency warnings remain.
  • Installed the Router tarball in an isolated consumer with no @granite-js/react-native present and NODE_PATH empty. Both standalone route definitions and actual plugin-generated declarations typecheck.
  • Native rendering and host integration are mocked in tests; device validation has not been performed.

Remaining imperative options

The only production navigation.setOptions call in this repository remains in the iOS StatusBar implementation (statusBarStyle, statusBarHidden). Router references are a compatibility test and back-button documentation examples. This extraction does not remove those existing APIs.

@vercel

vercel Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
granite-docs Ready Ready Preview Nov 4, 2026 6:09am UTC

Request Review

@changeset-bot

changeset-bot Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9b9b6d7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 32 packages
Name Type
@granite-js/react-native Major
@granite-js/router Major
@granite-js/plugin-router Major
create-granite-app Major
@granite-js/micro-frontend Major
babel-preset-granite Major
@granite-js/blur-view Major
@granite-js/brownfield-module Major
@granite-js/cli Major
@granite-js/config Major
@granite-js/cookies Major
@granite-js/screen Major
@granite-js/image Major
@granite-js/jest Major
@granite-js/lottie Major
@granite-js/mpack Major
@granite-js/native Major
@granite-js/naver-map Major
@granite-js/plugin-core Major
@granite-js/plugin-env Major
@granite-js/plugin-hermes Major
@granite-js/plugin-micro-frontend Major
@granite-js/plugin-rozenite Major
@granite-js/plugin-sentry Major
@granite-js/rollipop Major
@granite-js/style-utils Major
@granite-js/utils Major
@granite-js/video Major
@granite-js/vitest Major
@granite-js/deployment-manager Major
@granite-js/forge-cli Major
@granite-js/pulumi-aws Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
@granite-js/deployment-manager

yarn add https://pkg.pr.new/toss/granite/@granite-js/deployment-manager@443.tgz

@granite-js/forge-cli

yarn add https://pkg.pr.new/toss/granite/@granite-js/forge-cli@443.tgz

@granite-js/pulumi-aws

yarn add https://pkg.pr.new/toss/granite/@granite-js/pulumi-aws@443.tgz

babel-preset-granite

yarn add https://pkg.pr.new/toss/granite/babel-preset-granite@443.tgz

@granite-js/blur-view

yarn add https://pkg.pr.new/toss/granite/@granite-js/blur-view@443.tgz

@granite-js/brownfield-module

yarn add https://pkg.pr.new/toss/granite/@granite-js/brownfield-module@443.tgz

@granite-js/cli

yarn add https://pkg.pr.new/toss/granite/@granite-js/cli@443.tgz

@granite-js/config

yarn add https://pkg.pr.new/toss/granite/@granite-js/config@443.tgz

@granite-js/cookies

yarn add https://pkg.pr.new/toss/granite/@granite-js/cookies@443.tgz

create-granite-app

yarn add https://pkg.pr.new/toss/granite/create-granite-app@443.tgz

@granite-js/screen

yarn add https://pkg.pr.new/toss/granite/@granite-js/screen@443.tgz

@granite-js/image

yarn add https://pkg.pr.new/toss/granite/@granite-js/image@443.tgz

@granite-js/jest

yarn add https://pkg.pr.new/toss/granite/@granite-js/jest@443.tgz

@granite-js/lottie

yarn add https://pkg.pr.new/toss/granite/@granite-js/lottie@443.tgz

@granite-js/micro-frontend

yarn add https://pkg.pr.new/toss/granite/@granite-js/micro-frontend@443.tgz

@granite-js/mpack

yarn add https://pkg.pr.new/toss/granite/@granite-js/mpack@443.tgz

@granite-js/native

yarn add https://pkg.pr.new/toss/granite/@granite-js/native@443.tgz

@granite-js/naver-map

yarn add https://pkg.pr.new/toss/granite/@granite-js/naver-map@443.tgz

@granite-js/plugin-core

yarn add https://pkg.pr.new/toss/granite/@granite-js/plugin-core@443.tgz

@granite-js/plugin-env

yarn add https://pkg.pr.new/toss/granite/@granite-js/plugin-env@443.tgz

@granite-js/plugin-hermes

yarn add https://pkg.pr.new/toss/granite/@granite-js/plugin-hermes@443.tgz

@granite-js/plugin-micro-frontend

yarn add https://pkg.pr.new/toss/granite/@granite-js/plugin-micro-frontend@443.tgz

@granite-js/plugin-router

yarn add https://pkg.pr.new/toss/granite/@granite-js/plugin-router@443.tgz

@granite-js/plugin-rozenite

yarn add https://pkg.pr.new/toss/granite/@granite-js/plugin-rozenite@443.tgz

@granite-js/plugin-sentry

yarn add https://pkg.pr.new/toss/granite/@granite-js/plugin-sentry@443.tgz

@granite-js/react-native

yarn add https://pkg.pr.new/toss/granite/@granite-js/react-native@443.tgz

@granite-js/rollipop

yarn add https://pkg.pr.new/toss/granite/@granite-js/rollipop@443.tgz

@granite-js/router

yarn add https://pkg.pr.new/toss/granite/@granite-js/router@443.tgz

@granite-js/style-utils

yarn add https://pkg.pr.new/toss/granite/@granite-js/style-utils@443.tgz

@granite-js/utils

yarn add https://pkg.pr.new/toss/granite/@granite-js/utils@443.tgz

@granite-js/video

yarn add https://pkg.pr.new/toss/granite/@granite-js/video@443.tgz

@granite-js/vitest

yarn add https://pkg.pr.new/toss/granite/@granite-js/vitest@443.tgz

commit: 9b9b6d7

@gronxb gronxb changed the title refactor(react-native)!: decouple app registration from Router refactor(router)!: extract standalone @granite-js/router Nov 4, 2026
@gronxb
gronxb marked this pull request as draft November 4, 2026 11:10

This branch was successfully deployed

1 active deployment
Preview — 9b9b6d77 Deployed Nov 4, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant