Skip to content

Commit

Permalink
feat: using next app router
Browse files Browse the repository at this point in the history
  • Loading branch information
huuquyet committed Jun 10, 2024
1 parent 97ddd0a commit 64ca961
Show file tree
Hide file tree
Showing 35 changed files with 346 additions and 213 deletions.
12 changes: 12 additions & 0 deletions .gitpod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This configuration file was automatically generated by Gitpod.
# Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml)
# and commit this file to your remote git repository to share the goodness with others.

# Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart

tasks:
- command: |
curl -fsSL https://bun.sh/install | bash
source /home/gitpod/.bashrc
bun install
bun web
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2021 Stefan H.
Copyright (c) 2024

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ The main apps are:

You can add other folders inside of `packages/` if you know what you're doing and have a good reason to.

> [!TIP]
> Switching from `app` to `pages` router:
>
> - remove `app` folder from `apps/next`
> - move `index.tsx` from `pages-example` to `pages` folder
> - rename `pages-example-user` to `user` and be sure to update `linkTarget` in `screen.tsx` to `user` as well
> - delete `SwitchRouterButton.tsx` component and remove it from `screen.tsx` and `packages/ui/src/index.tsx`
> - search for `pagesMode` keyword and remove it
## 🏁 Start the app

- Install dependencies: `bun install`
Expand Down Expand Up @@ -71,7 +80,7 @@ If you're installing a library with any native code, you must install it in `exp
```sh
cd apps/expo
bun add react-native-reanimated
cd ..
cd ../..
bun install
```

Expand Down
1 change: 1 addition & 0 deletions apps/expo/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,6 @@ buck-out/
.expo/
web-build/
dist/
expo-env.d.ts

# @end expo-cli
7 changes: 5 additions & 2 deletions apps/expo/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Minimal Todo App",
"slug": "minimaltodo",
"scheme": "minimaltodo",
"version": "0.3.0",
"version": "0.3.1",
"owner": "quyet",
"orientation": "portrait",
"icon": "./assets/icon.png",
Expand Down Expand Up @@ -48,6 +48,9 @@
}
],
"expo-font"
]
],
"experiments": {
"typedRoutes": true
}
}
}
33 changes: 28 additions & 5 deletions apps/expo/app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,46 @@
import { Provider } from 'app/provider'
import { useFonts } from 'expo-font'
import { Stack } from 'expo-router'
import { SplashScreen, Stack } from 'expo-router'
import { StatusBar } from 'expo-status-bar'
import { useEffect } from 'react'

export default function HomeLayout() {
const [loaded] = useFonts({
export const unstable_settings = {
// Ensure that reloading on `/user` keeps a back button present.
initialRouteName: 'Home',
}

// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync()

export default function App() {
const [interLoaded, interError] = useFonts({
Inter: require('@tamagui/font-inter/otf/Inter-Medium.otf'),
InterBold: require('@tamagui/font-inter/otf/Inter-Bold.otf'),
InterMedium: require('@tamagui/font-inter/otf/Inter-Medium.otf'),
})

if (!loaded) {
useEffect(() => {
if (interLoaded || interError) {
// Hide the splash screen after the fonts have loaded (or an error was returned) and the UI is ready.
SplashScreen.hideAsync()
}
}, [interLoaded, interError])

if (!interLoaded && !interError) {
return null
}

return <RootLayoutNav />
}

function RootLayoutNav() {
return (
<Provider>
<Stack
screenOptions={{
headerShown: false,
headerTitleStyle: {
fontFamily: '$body',
},
}}
/>
<StatusBar style="auto" hidden />
Expand Down
6 changes: 1 addition & 5 deletions apps/expo/babel.config.js → apps/expo/babel.config.cjs
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
// Don't forget to specify your TAMAGUI_TARGET here or ideally in the command to run / .env files
process.env.TAMAGUI_TARGET = 'native'

module.exports = (api) => {
api.cache(true)
return {
presets: [['babel-preset-expo', { jsxRuntime: 'automatic' }]],
plugins: [
require.resolve('expo-router/babel'),
[
require.resolve('babel-plugin-module-resolver'),
{
Expand All @@ -30,10 +26,10 @@ module.exports = (api) => {
components: ['@my/ui', 'tamagui'],
config: '../../packages/ui/src/tamagui.config.ts',
logTimings: true,
disableExtraction: process.env.NODE_ENV === 'development',
},
],
]),
'transform-inline-environment-variables',
],
}
}
14 changes: 7 additions & 7 deletions apps/expo/metro.config.js → apps/expo/metro.config.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { resolve } from 'node:path'
import { withTamagui } from '@tamagui/metro-plugin'
// Learn more https://docs.expo.dev/guides/monorepos
// Learn more https://docs.expo.io/guides/customizing-metro
/** @type {import('expo/metro-config').MetroConfig} */
const { getDefaultConfig } = require('expo/metro-config')
const path = require('node:path')
import { getDefaultConfig } from 'expo/metro-config'

// Find the project and workspace directories
const projectRoot = __dirname
// This can be replaced with `find-yarn-workspace-root`
const workspaceRoot = path.resolve(projectRoot, '../..')
const workspaceRoot = resolve(projectRoot, '../..')

const config = getDefaultConfig(projectRoot, {
// [Web-only]: Enables CSS support in Metro.
Expand All @@ -18,8 +19,8 @@ const config = getDefaultConfig(projectRoot, {
config.watchFolders = [workspaceRoot]
// 2. Let Metro know where to resolve packages and in what order
config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, 'node_modules'),
path.resolve(workspaceRoot, 'node_modules'),
resolve(projectRoot, 'node_modules'),
resolve(workspaceRoot, 'node_modules'),
]
// 3. Force Metro to resolve (sub)dependencies only from the `nodeModulesPaths`
config.resolver.disableHierarchicalLookup = true
Expand All @@ -32,8 +33,7 @@ config.transformer = { ...config.transformer, unstable_allowRequireContext: true
config.transformer.minifierPath = require.resolve('metro-minify-terser')

// add nice web support with optimizing compiler + CSS extraction
const { withTamagui } = require('@tamagui/metro-plugin')
module.exports = withTamagui(config, {
export default withTamagui(config, {
components: ['tamagui'],
config: '../../packages/ui/src/tamagui.config.ts',
outputCSS: './tamagui-web.css',
Expand Down
11 changes: 6 additions & 5 deletions apps/expo/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "expo-app",
"version": "0.3.0",
"version": "0.3.1",
"main": "index.ts",
"private": true,
"scripts": {
Expand All @@ -11,17 +11,16 @@
"start": "bunx expo start -c"
},
"dependencies": {
"@my/ui": "*",
"app": "*",
"@my/ui": "workspace:*",
"app": "workspace:*",
"burnt": "^0.12.2",
"expo": "~50.0.18",
"expo-font": "~11.10.3",
"expo-linking": "~6.2.2",
"expo-router": "~3.4.10",
"expo-splash-screen": "~0.26.5",
"expo-status-bar": "~1.11.1",
"expo-system-ui": "~2.9.4",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.73.6",
"react-native-gesture-handler": "~2.14.1",
"react-native-mmkv": "^2.12.2",
Expand All @@ -36,6 +35,8 @@
"@tamagui/babel-plugin": "latest",
"@tamagui/font-inter": "latest",
"@tamagui/metro-plugin": "latest",
"@types/react": "~18.2.79",
"@types/react-native": "^0.73.0",
"babel-plugin-module-resolver": "^5.0.2",
"babel-plugin-transform-inline-environment-variables": "^0.4.4",
"metro-minify-terser": "^0.80.9"
Expand Down
6 changes: 3 additions & 3 deletions apps/expo/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"extends": "../../tsconfig",
"extends": "expo/tsconfig.base",
"compilerOptions": {
"composite": true,
"strict": true,
"noEmit": true
},
"include": ["**/*.ts", "**/*.tsx"]
"include": ["app/**/*.ts", "app/**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
}
59 changes: 59 additions & 0 deletions apps/next/app/NextTamaguiProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
'use client'

import '@tamagui/core/reset.css'
import '@tamagui/font-inter/css/400.css'
import '@tamagui/font-inter/css/700.css'
import { config } from '@my/ui'
import { Provider } from 'app/provider'
import { useServerInsertedHTML } from 'next/navigation'
import type { ReactNode } from 'react'
import { StyleSheet } from 'react-native'

if (process.env.NODE_ENV === 'production') {
require('../public/tamagui.css')
}

export function NextTamaguiProvider({ children }: { children: ReactNode }) {
useServerInsertedHTML(() => {
// @ts-ignore
const rnwStyle = StyleSheet.getSheet()
return (
<>
<style dangerouslySetInnerHTML={{ __html: rnwStyle.textContent }} id={rnwStyle.id} />

<style
dangerouslySetInnerHTML={{
// the first time this runs you'll get the full CSS including all themes
// after that, it will only return CSS generated since the last call
__html: config.getNewCSS(),
}}
/>

<style
dangerouslySetInnerHTML={{
__html: config.getCSS({
// if you are using "outputCSS" option, you should use this "exclude"
// if not, then you can leave the option out
exclude: process.env.NODE_ENV === 'production' ? 'design-system' : null,
}),
}}
/>

<script
dangerouslySetInnerHTML={{
// avoid flash of animated things on enter:
__html: `document.documentElement.classList.add('t_unmounted')`,
}}
/>

<style jsx global>{`
html {
font-family: 'Inter';
}
`}</style>
</>
)
})

return <Provider>{children}</Provider>
}
63 changes: 63 additions & 0 deletions apps/next/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Analytics } from '@vercel/analytics/next'
import type { Metadata } from 'next'
import type { ReactNode } from 'react'
import { NextTamaguiProvider } from './NextTamaguiProvider'

const APP_TITLE = 'Tamagui Expo Next.js Monorepo App'
const APP_TITLE_TEMPLATE = '%s - Tamagui App'
const APP_DESCRIPTION = 'Tamagui, Expo, Next.js & Solito monorepo'
const APP_URL = 'https://expo-next-tamagui-monorepo.vercel.app/'
const APP_TWITTER = '@HuuQuyetNg'

export default function RootLayout({ children }: { children: ReactNode }) {
return (
// You can use `suppressHydrationWarning` to avoid the warning about mismatched content during hydration in dev mode
<html lang="en" suppressHydrationWarning>
<body>
<NextTamaguiProvider>{children}</NextTamaguiProvider>
<Analytics />
</body>
</html>
)
}

export const metadata: Metadata = {
applicationName: APP_TITLE,
title: {
default: APP_TITLE,
template: APP_TITLE_TEMPLATE,
},
description: APP_DESCRIPTION,
manifest: '/manifest.json',
metadataBase: new URL('https://${process.env.VERCEL_URL}'),
appleWebApp: {
capable: true,
statusBarStyle: 'default',
title: APP_TITLE,
// startUpImage: [],
},
formatDetection: {
telephone: false,
},
openGraph: {
type: 'website',
siteName: APP_TITLE,
title: {
default: APP_TITLE,
template: APP_TITLE_TEMPLATE,
},
description: APP_DESCRIPTION,
url: APP_URL,
images: ['/vercel.svg'],
},
twitter: {
card: 'summary',
title: {
default: APP_TITLE,
template: APP_TITLE_TEMPLATE,
},
description: APP_DESCRIPTION,
site: APP_TWITTER,
},
keywords: ['Todo', 'Tamagui', 'Expo', 'Solito', 'Next.js', 'zustand', 'monorepo'],
}
5 changes: 5 additions & 0 deletions apps/next/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use client'

import { TodoApp } from 'app/features/home'

export default TodoApp
2 changes: 1 addition & 1 deletion apps/next/next.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/** @type {import('next').NextConfig} */
const { withTamagui } = require('@tamagui/next-plugin')
const { withExpo } = require('@expo/next-adapter')
const { join } = require('node:path')
Expand All @@ -21,6 +20,7 @@ const plugins = [
withTamagui({
config: '../../packages/ui/src/tamagui.config.ts',
components: ['tamagui', '@my/ui'],
appDir: true,
importsWhitelist: ['constants.js', 'colors.js'],
outputCSS: process.env.NODE_ENV === 'production' ? './public/tamagui.css' : null,
logTimings: true,
Expand Down
Loading

0 comments on commit 64ca961

Please sign in to comment.