Merge pull request #2 from movie-web/setup

Added basic expo skeleton app
This commit is contained in:
Jorrin
2024-01-15 13:48:23 +01:00
committed by GitHub
69 changed files with 16334 additions and 9 deletions

View File

@@ -1,8 +1,13 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

4
.eslintignore Normal file
View File

@@ -0,0 +1,4 @@
# Add files here to ignore them from prettier formatting
/dist
/coverage
/.nx/cache

81
.eslintrc.js Normal file
View File

@@ -0,0 +1,81 @@
module.exports = {
extends: [
'airbnb',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
ignorePatterns: [
'dist/*',
'plugins/*',
'tests/*',
'/*.cjs',
'/*.js',
'/**/*.test.ts',
'test/*',
],
parser: '@typescript-eslint/parser',
settings: {
'import/resolver': {
typescript: {
project: './tsconfig.json',
},
},
},
plugins: ['@typescript-eslint', 'import', 'prettier'],
rules: {
'no-underscore-dangle': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'no-console': 'off',
'@typescript-eslint/no-this-alias': 'off',
'import/prefer-default-export': 'off',
'@typescript-eslint/no-empty-function': 'off',
'no-shadow': 'off',
'@typescript-eslint/no-shadow': ['error'],
'no-restricted-syntax': 'off',
'import/no-unresolved': ['error', { ignore: ['^virtual:'] }],
'consistent-return': 'off',
'no-continue': 'off',
'no-eval': 'off',
'no-await-in-loop': 'off',
'no-nested-ternary': 'off',
'no-param-reassign': ['error', { props: false }],
'prefer-destructuring': 'off',
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'import/extensions': [
'error',
'ignorePackages',
{
ts: 'never',
tsx: 'never',
},
],
'import/order': [
'error',
{
groups: [
'builtin',
'external',
'internal',
['sibling', 'parent'],
'index',
'unknown',
],
'newlines-between': 'always',
alphabetize: {
order: 'asc',
caseInsensitive: true,
},
},
],
'sort-imports': [
'error',
{
ignoreCase: false,
ignoreDeclarationSort: true,
ignoreMemberSort: false,
memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
allowSeparatedGroups: true,
},
],
},
};

2
.github/CODEOWNERS vendored
View File

@@ -1 +1 @@
* @movie-web/project-leads
* @movie-web/core

15
.github/SECURITY.md vendored Normal file
View File

@@ -0,0 +1,15 @@
# Security Policy
## Supported Versions
The movie-web maintainers only support the latest version of movie-web published at https://movie-web.app.
This published version is equivalent to the master branch.
Support is not provided for any forks or mirrors of movie-web.
## Reporting a Vulnerability
There are two ways you can contact the movie-web maintainers to report a vulnerability:
- Email [security@movie-web.app](mailto:security@movie-web.app)
- Report the vulnerability in the [movie-web Discord server](https://discord.movie-web.app)

6
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,6 @@
This pull request resolves #XXX
- [ ] I have read and agreed to the [code of conduct](https://github.com/movie-web/movie-web/blob/dev/.github/CODE_OF_CONDUCT.md).
- [ ] I have read and complied with the [contributing guidelines](https://github.com/movie-web/movie-web/blob/dev/.github/CONTRIBUTING.md).
- [ ] What I'm implementing was assigned to me and is an [approved issue](https://github.com/movie-web/movie-web/issues?q=is%3Aopen+is%3Aissue+label%3Aapproved). For reference, please take a look at our [GitHub projects](https://github.com/movie-web/movie-web/projects).
- [ ] I have tested all of my changes.

143
.github/workflows/build-mobile.yml vendored Normal file
View File

@@ -0,0 +1,143 @@
name: build mobile app
on:
push:
branches:
- master
workflow_dispatch:
permissions:
contents: write
jobs:
build-android:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 21
- uses: pnpm/action-setup@v2
name: Install pnpm
with:
version: 8
run_install: false
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Install dependencies
run: pnpm install
- name: Build native Android modules
run: pnpm exec nx run mobile:prebuild --platform=android
- name: Build Android app
run: cd apps/mobile/android && ./gradlew assembleRelease
- name: Rename apk
run: mv apps/mobile/android/app/build/outputs/apk/release/app-release.apk apps/mobile/android/app/build/outputs/apk/release/movie-web.apk
- name: Upload movie-web.apk as artifact
uses: actions/upload-artifact@v4
with:
name: apk
path: ./apps/mobile/android/app/build/outputs/apk/release/movie-web.apk
build-ios:
runs-on: macos-13
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Xcode Select Version
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '15.1.0'
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 21
- uses: pnpm/action-setup@v2
name: Install pnpm
with:
version: 8
run_install: false
- name: Install dependencies
run: pnpm install
- name: Build native iOS modules
run: pnpm exec nx run mobile:prebuild --platform=ios
- name: Build iOS app
run: cd apps/mobile/ios && xcodebuild archive -workspace movieweb.xcworkspace -scheme "movieweb" -sdk iphoneos -configuration "Release" -archivePath "build/app.xcarchive" -destination generic/platform=iOS CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
- name: Export .ipa from .xcarchive
run: |
mv apps/mobile/ios/build/app.xcarchive/Products/Applications apps/mobile/ios/build/app.xcarchive/Products/Payload
cd apps/mobile/ios/build/app.xcarchive/Products
zip -r ../../movie-web.ipa Payload
- name: Upload movie-web.ipa as artifact
uses: actions/upload-artifact@v4
with:
name: ipa
path: ./apps/mobile/ios/build/movie-web.ipa
release-app:
runs-on: ubuntu-latest
needs: [build-android, build-ios]
if: github.ref == 'refs/heads/master'
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Automated Version Bump
uses: phips28/gh-action-bump-version@v10.1.1
with:
skip-tag: 'true'
commit-message: 'chore: bump version to {{version}} [skip ci]'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PACKAGEJSON_DIR: 'apps/mobile'
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
- name: Get package version
id: package-version
uses: martinbeentjes/npm-get-version-action@v1.3.1
with:
path: apps/mobile
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ steps.package-version.outputs.current-version }}
files: |
movie-web.apk
movie-web.ipa
fail_on_unmatched_files: true
token: ${{ env.GITHUB_TOKEN }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

59
.gitignore vendored Normal file
View File

@@ -0,0 +1,59 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
dist
tmp
/out-tsc
# dependencies
node_modules
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# System Files
.DS_Store
Thumbs.db
.nx/cache
# Expo
node_modules/
.expo/
.yarn/
dist/
npm-debug.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
*.orig.*
web-build/
cache/
apps/mobile-e2e/artifacts

3
.npmrc Normal file
View File

@@ -0,0 +1,3 @@
strict-peer-dependencies=false
auto-install-peers=true
node-linker=hoisted

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
20.10

4
.prettierignore Normal file
View File

@@ -0,0 +1,4 @@
# Add files here to ignore them from prettier formatting
/dist
/coverage
/.nx/cache

3
.prettierrc Normal file
View File

@@ -0,0 +1,3 @@
{
"singleQuote": true
}

8
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,8 @@
{
"recommendations": [
"dbaeumer.vscode-eslint",
"editorconfig.editorconfig",
"esbenp.prettier-vscode",
"firsttris.vscode-jest-runner"
]
}

11
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"eslint.format.enable": true,
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
}
}

View File

@@ -1,6 +1,70 @@
# native-app
# movie-web native-app
The native app version of movie-web
Native-app for movie-web.
> [!IMPORTANT]
> This is work in progress, not even remotely close to being ready for use.
## Getting started
```bash
pnpm install
// Having nx installed globally is recommended
pnpm install -g nx
// If you don't want nx installed globally, you can use the following command
(pnpm exec or npx) nx <command>
```
## Running tasks
To execute tasks with Nx use the following syntax:
```bash
nx <target> <project> <...options>
```
For example, to run the mobile app:
### Android
```bash
nx run mobile:android
```
### iOS
```bash
nx run mobile:ios
```
## Building archives
### Android .apk
```bash
nx run mobile:prebuild --platform=android
cd apps/mobile/android && ./gradlew assembleRelease
```
### iOS .app
#### Real device
```bash
nx run mobile:prebuild --platform=ios
cd apps/mobile/ios && xcodebuild archive -workspace movieweb.xcworkspace -scheme "movieweb" -sdk iphoneos -configuration "Release" -archivePath "build/app.xcarchive" -destination generic/platform=iOS CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
```
#### Simulator
```bash
nx run mobile:prebuild --platform=ios
cd apps/mobile/ios && xcodebuild archive -workspace movieweb.xcworkspace -scheme "movieweb" -sdk iphonesimulator -configuration "Release" -archivePath "build/app.xcarchive" -destination "generic/platform=iOS Simulator" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
```
## Repository information
This project uses Nx to manage the monorepo. For more information about Nx, visit [nx.dev](https://nx.dev).
### Mobile app
The mobile app is built with React Native and Expo. For more information about Expo, visit [expo.io](https://expo.io).

11
apps/mobile-e2e/.babelrc Normal file
View File

@@ -0,0 +1,11 @@
{
"presets": [
[
"@nx/react/babel",
{
"runtime": "automatic",
},
],
],
"plugins": [],
}

View File

@@ -0,0 +1,89 @@
{
"testRunner": {
"args": {
"$0": "jest",
"config": "./jest.config.json"
},
"jest": {
"setupTimeout": 120000
}
},
"apps": {
"ios.debug": {
"type": "ios.app",
"build": "cd ../../apps/mobile/ios && xcodebuild -workspace movieweb.xcworkspace -scheme movieweb -configuration Debug -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 14' -derivedDataPath ./build -quiet",
"binaryPath": "../../apps/mobile/ios/build/Build/Products/Debug-iphonesimulator/movieweb.app"
},
"ios.release": {
"type": "ios.app",
"build": "cd ../../apps/mobile/ios && xcodebuild -workspace movieweb.xcworkspace -scheme movieweb -configuration Release -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 14' -derivedDataPath ./build -quiet",
"binaryPath": "../../apps/mobile/ios/build/Build/Products/Release-iphonesimulator/movieweb.app"
},
"ios.local": {
"type": "ios.app",
"build": "pnpm exec nx run mobile:build --platform ios --profile preview --wait --local --no-interactive --output=../../apps/mobile/dist/movieweb.tar.gz",
"binaryPath": "../../apps/mobile/dist/movieweb.app"
},
"android.debug": {
"type": "android.apk",
"build": "cd ../../apps/mobile/android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug",
"binaryPath": "../../apps/mobile/android/app/build/outputs/apk/debug/app-debug.apk"
},
"android.release": {
"type": "android.apk",
"build": "cd ../../apps/mobile/android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release",
"binaryPath": "../../apps/mobile/android/app/build/outputs/apk/release/app-release.apk"
},
"android.local": {
"type": "android.apk",
"build": "pnpm exec nx run mobile:build --platform android --profile preview --wait --local --no-interactive --output=../../apps/mobile/dist/movieweb.apk",
"binaryPath": "../../apps/mobile/dist/movieweb.apk"
}
},
"devices": {
"simulator": {
"type": "ios.simulator",
"device": {
"type": "iPhone 14"
}
},
"emulator": {
"type": "android.emulator",
"device": {
"avdName": "Pixel_4a_API_30"
}
}
},
"configurations": {
"ios.sim.release": {
"device": "simulator",
"app": "ios.release"
},
"ios.sim.debug": {
"device": "simulator",
"app": "ios.debug"
},
"ios.sim.local": {
"device": "simulator",
"app": "ios.local"
},
"android.emu.release": {
"device": "emulator",
"app": "android.release"
},
"android.emu.debug": {
"device": "emulator",
"app": "android.debug"
},
"android.emu.local": {
"device": "emulator",
"app": "android.local"
}
}
}

View File

@@ -0,0 +1,18 @@
{
"extends": ["../../.eslintrc.js"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}

View File

@@ -0,0 +1,22 @@
{
"preset": "../../jest.preset",
"rootDir": ".",
"testMatch": [
"<rootDir>/src/**/*.test.ts?(x)",
"<rootDir>/src/**/*.spec.ts?(x)"
],
"testTimeout": 120000,
"maxWorkers": 1,
"globalSetup": "detox/runners/jest/globalSetup",
"globalTeardown": "detox/runners/jest/globalTeardown",
"reporters": ["detox/runners/jest/reporter"],
"testEnvironment": "detox/runners/jest/testEnvironment",
"verbose": true,
"setupFilesAfterEnv": ["<rootDir>/test-setup.ts"],
"transform": {
"^.+\\.(ts|js|html)$": [
"ts-jest",
{ "tsconfig": "<rootDir>/tsconfig.e2e.json" }
]
}
}

View File

@@ -0,0 +1,76 @@
{
"name": "mobile-e2e",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/mobile-e2e/src",
"projectType": "application",
"targets": {
"build-ios": {
"executor": "@nx/detox:build",
"options": {
"detoxConfiguration": "ios.sim.local"
},
"configurations": {
"bare": {
"detoxConfiguration": "ios.sim.debug"
},
"production": {
"detoxConfiguration": "ios.sim.release"
}
}
},
"test-ios": {
"executor": "@nx/detox:test",
"options": {
"detoxConfiguration": "ios.sim.local",
"buildTarget": "mobile-e2e:build-ios"
},
"configurations": {
"bare": {
"detoxConfiguration": "ios.sim.debug",
"buildTarget": "mobile-e2e:build-ios:bare"
},
"production": {
"detoxConfiguration": "ios.sim.release",
"buildTarget": "mobile-e2e:build-ios:production"
}
}
},
"build-android": {
"executor": "@nx/detox:build",
"options": {
"detoxConfiguration": "android.emu.local"
},
"configurations": {
"bare": {
"detoxConfiguration": "android.emu.debug"
},
"production": {
"detoxConfiguration": "android.emu.release"
}
}
},
"test-android": {
"executor": "@nx/detox:test",
"options": {
"detoxConfiguration": "android.emu.local",
"buildTarget": "mobile-e2e:build-android"
},
"configurations": {
"bare": {
"detoxConfiguration": "android.emu.debug",
"buildTarget": "mobile-e2e:build-android:bare"
},
"production": {
"detoxConfiguration": "android.emu.release",
"buildTarget": "mobile-e2e:build-android:production"
}
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"]
}
},
"tags": [],
"implicitDependencies": ["mobile"]
}

View File

@@ -0,0 +1,11 @@
import { device, element, by, expect } from 'detox';
describe('movieweb', () => {
beforeEach(async () => {
await device.reloadReactNative();
});
it('should display welcome message', async () => {
await expect(element(by.id('heading'))).toHaveText('Welcome movie-web 👋');
});
});

View File

@@ -0,0 +1,5 @@
import { device } from 'detox';
beforeAll(async () => {
await device.launchApp();
});

View File

@@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"sourceMap": false,
"outDir": "../../dist/out-tsc",
"allowJs": true,
"types": ["node", "jest", "detox"]
},
"include": ["src/**/*.ts", "src/**/*.js"]
}

View File

@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.base.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.e2e.json"
}
]
}

31
apps/mobile/.eslintrc.js Normal file
View File

@@ -0,0 +1,31 @@
module.exports = {
extends: ['../../.eslintrc.js'],
ignorePatterns: ['/*.js', '/*.d.ts'],
overrides: [
{
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
rules: {},
},
{
files: ['*.ts', '*.tsx'],
rules: {},
},
{
files: ['*.js', '*.jsx'],
rules: {},
},
],
rules: {
'react/jsx-uses-react': 'off',
'react/react-in-jsx-scope': 'off',
'react/require-default-props': 'off',
'react/destructuring-assignment': 'off',
'react/jsx-filename-extension': [
'error',
{ extensions: ['.js', '.tsx', '.jsx'] },
],
'react/jsx-props-no-spreading': 'off',
'react/no-unstable-nested-components': 'off',
'no-use-before-define': 'off',
},
};

View File

@@ -0,0 +1,18 @@
{
"extends": ["../../.eslintrc.js"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}

44
apps/mobile/.gitignore vendored Normal file
View File

@@ -0,0 +1,44 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
# dependencies
node_modules/
# Expo
.expo/
dist/
web-build/
android/
ios/
# Native
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
# Metro
.metro-health-check*
# debug
npm-debug.*
yarn-debug.*
yarn-error.*
# macOS
.DS_Store
*.pem
# local env files
.env*.local
# typescript
*.tsbuildinfo
# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
# The following patterns were generated by expo-cli
expo-env.d.ts
# @end expo-cli

View File

@@ -1 +0,0 @@
This will be the folder the mobile native app.

53
apps/mobile/app.json Normal file
View File

@@ -0,0 +1,53 @@
{
"expo": {
"name": "movie-web",
"slug": "mw-mobile",
"version": "1.0.0",
"orientation": "portrait",
"scheme":"dev.movieweb.app",
"icon": "./assets/images/icon.png",
"splash": {
"image": "./assets/images/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"jsEngine": "jsc",
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true,
"bundleIdentifier": "dev.movieweb.app"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
},
"package": "dev.movieweb.app"
},
"web": {
"favicon": "./assets/images/favicon.png",
"bundler": "metro"
},
"plugins": [
"expo-router",
[
"@config-plugins/detox",
{
"skipProguard": false,
"subdomains": [
"10.0.2.2",
"localhost"
]
}
]
],
"experiments": {
"typedRoutes": true
}
}
}

View File

@@ -0,0 +1,56 @@
import FontAwesome from '@expo/vector-icons/FontAwesome';
import { Link, Tabs } from 'expo-router';
import { Pressable, useColorScheme } from 'react-native';
import Colors from '../../constants/Colors';
/**
* You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/
*/
function TabBarIcon(props: {
name: React.ComponentProps<typeof FontAwesome>['name'];
color: string;
}) {
return <FontAwesome size={28} style={{ marginBottom: -3 }} {...props} />;
}
export default function TabLayout() {
const colorScheme = useColorScheme();
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
}}
>
<Tabs.Screen
name="index"
options={{
title: 'Tab One',
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
headerRight: () => (
<Link href="/modal" asChild>
<Pressable>
{({ pressed }) => (
<FontAwesome
name="info-circle"
size={25}
color={Colors[colorScheme ?? 'light'].text}
style={{ marginRight: 15, opacity: pressed ? 0.5 : 1 }}
/>
)}
</Pressable>
</Link>
),
}}
/>
<Tabs.Screen
name="two"
options={{
title: 'Tab Two',
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
}}
/>
</Tabs>
);
}

View File

@@ -0,0 +1,35 @@
import { StyleSheet } from 'react-native';
import EditScreenInfo from '../../components/EditScreenInfo';
import { Text, View } from '../../components/Themed';
export default function TabOneScreen() {
return (
<View style={styles.container}>
<Text style={styles.title}>Tab One</Text>
<View
style={styles.separator}
lightColor="#eee"
darkColor="rgba(255,255,255,0.1)"
/>
<EditScreenInfo path="app/(tabs)/index.tsx" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
separator: {
marginVertical: 30,
height: 1,
width: '80%',
},
});

View File

@@ -0,0 +1,35 @@
import { StyleSheet } from 'react-native';
import EditScreenInfo from '../../components/EditScreenInfo';
import { Text, View } from '../../components/Themed';
export default function TabTwoScreen() {
return (
<View style={styles.container}>
<Text style={styles.title}>Tab Two</Text>
<View
style={styles.separator}
lightColor="#eee"
darkColor="rgba(255,255,255,0.1)"
/>
<EditScreenInfo path="app/(tabs)/two.tsx" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
separator: {
marginVertical: 30,
height: 1,
width: '80%',
},
});

46
apps/mobile/app/+html.tsx Normal file
View File

@@ -0,0 +1,46 @@
import { ScrollViewStyleReset } from 'expo-router/html';
// This file is web-only and used to configure the root HTML for every
// web page during static rendering.
// The contents of this function only run in Node.js environments and
// do not have access to the DOM or browser APIs.
export default function Root({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
{/*
This viewport disables scaling which makes the mobile website act more like a native app.
However this does reduce built-in accessibility. If you want to enable scaling, use this instead:
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
*/}
<meta
name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1.00001,viewport-fit=cover"
/>
{/*
Disable body scrolling on web. This makes ScrollView components work closer to how they do on native.
However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line.
*/}
<ScrollViewStyleReset />
{/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
<style dangerouslySetInnerHTML={{ __html: responsiveBackground }} />
{/* Add any additional <head> elements that you want globally available on web... */}
</head>
<body>{children}</body>
</html>
);
}
const responsiveBackground = `
body {
background-color: #fff;
}
@media (prefers-color-scheme: dark) {
body {
background-color: #000;
}
}`;

View File

@@ -0,0 +1,40 @@
import { Link, Stack } from 'expo-router';
import { StyleSheet } from 'react-native';
import { Text, View } from '../components/Themed';
export default function NotFoundScreen() {
return (
<>
<Stack.Screen options={{ title: 'Oops!' }} />
<View style={styles.container}>
<Text style={styles.title}>This screen doesn&apos;t exist.</Text>
<Link href="/" style={styles.link}>
<Text style={styles.linkText}>Go to home screen!</Text>
</Link>
</View>
</>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
padding: 20,
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
link: {
marginTop: 15,
paddingVertical: 15,
},
linkText: {
fontSize: 14,
color: '#2e78b7',
},
});

View File

@@ -0,0 +1,62 @@
import FontAwesome from '@expo/vector-icons/FontAwesome';
import {
DarkTheme,
DefaultTheme,
ThemeProvider,
} from '@react-navigation/native';
import { useFonts } from 'expo-font';
import { SplashScreen, Stack } from 'expo-router';
import { useEffect } from 'react';
import { useColorScheme } from 'react-native';
export {
// Catch any errors thrown by the Layout component.
ErrorBoundary,
} from 'expo-router';
// eslint-disable-next-line camelcase
export const unstable_settings = {
// Ensure that reloading on `/modal` keeps a back button present.
initialRouteName: '(tabs)/index',
};
// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
const [loaded, error] = useFonts({
// eslint-disable-next-line global-require
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
...FontAwesome.font,
});
// Expo Router uses Error Boundaries to catch errors in the navigation tree.
useEffect(() => {
if (error) throw error;
}, [error]);
useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
}
}, [loaded]);
if (!loaded) {
return null;
}
return <RootLayoutNav />;
}
function RootLayoutNav() {
const colorScheme = useColorScheme();
return (
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="modal" options={{ presentation: 'modal' }} />
</Stack>
</ThemeProvider>
);
}

39
apps/mobile/app/modal.tsx Normal file
View File

@@ -0,0 +1,39 @@
import { StatusBar } from 'expo-status-bar';
import { Platform, StyleSheet } from 'react-native';
import EditScreenInfo from '../components/EditScreenInfo';
import { Text, View } from '../components/Themed';
export default function ModalScreen() {
return (
<View style={styles.container}>
<Text style={styles.title}>Modal</Text>
<View
style={styles.separator}
lightColor="#eee"
darkColor="rgba(255,255,255,0.1)"
/>
<EditScreenInfo path="app/modal.tsx" />
{/* Use a light status bar on iOS to account for the black space above the modal */}
<StatusBar style={Platform.OS === 'ios' ? 'light' : 'auto'} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
fontSize: 20,
fontWeight: 'bold',
},
separator: {
marginVertical: 30,
height: 1,
width: '80%',
},
});

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -0,0 +1,10 @@
module.exports = function (api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [
// Required for expo-router
'expo-router/babel',
],
};
};

View File

@@ -0,0 +1,82 @@
import React from 'react';
import { StyleSheet } from 'react-native';
import { ExternalLink } from './ExternalLink';
import { MonoText } from './StyledText';
import { Text, View } from './Themed';
import Colors from '../constants/Colors';
export default function EditScreenInfo({ path }: { path: string }) {
return (
<View>
<View style={styles.getStartedContainer}>
<Text
style={styles.getStartedText}
lightColor="rgba(0,0,0,0.8)"
darkColor="rgba(255,255,255,0.8)"
>
Open up the code for this screen:
</Text>
<View
style={[styles.codeHighlightContainer, styles.homeScreenFilename]}
darkColor="rgba(255,255,255,0.05)"
lightColor="rgba(0,0,0,0.05)"
>
<MonoText>{path}</MonoText>
</View>
<Text
style={styles.getStartedText}
lightColor="rgba(0,0,0,0.8)"
darkColor="rgba(255,255,255,0.8)"
>
Change any of the text, save the file, and your app will automatically
update.
</Text>
</View>
<View style={styles.helpContainer}>
<ExternalLink
style={styles.helpLink}
href="https://docs.expo.io/get-started/create-a-new-app/#opening-the-app-on-your-phonetablet"
>
<Text style={styles.helpLinkText} lightColor={Colors.light.tint}>
Tap here if your app doesn&apos;t automatically update after making
changes
</Text>
</ExternalLink>
</View>
</View>
);
}
const styles = StyleSheet.create({
getStartedContainer: {
alignItems: 'center',
marginHorizontal: 50,
},
homeScreenFilename: {
marginVertical: 7,
},
codeHighlightContainer: {
borderRadius: 3,
paddingHorizontal: 4,
},
getStartedText: {
fontSize: 17,
lineHeight: 24,
textAlign: 'center',
},
helpContainer: {
marginTop: 15,
marginHorizontal: 20,
alignItems: 'center',
},
helpLink: {
paddingVertical: 15,
},
helpLinkText: {
textAlign: 'center',
},
});

View File

@@ -0,0 +1,28 @@
import { Link } from 'expo-router';
import * as WebBrowser from 'expo-web-browser';
import React from 'react';
import { Platform } from 'react-native';
export function ExternalLink(
props: Omit<React.ComponentProps<typeof Link>, 'href'> & { href: string },
) {
return (
<Link
hrefAttrs={{
// On web, launch the link in a new tab.
target: '_blank',
}}
{...props}
// @ts-expect-error: External URLs are not typed.
href={props.href}
onPress={(e) => {
if (Platform.OS !== 'web') {
// Prevent the default behavior of linking to the default browser on native.
e.preventDefault();
// Open the link in an in-app browser.
WebBrowser.openBrowserAsync(props.href as string);
}
}}
/>
);
}

View File

@@ -0,0 +1,5 @@
import { Text, TextProps } from './Themed';
export function MonoText(props: TextProps) {
return <Text {...props} style={[props.style, { fontFamily: 'SpaceMono' }]} />;
}

View File

@@ -0,0 +1,50 @@
/**
* Learn more about Light and Dark modes:
* https://docs.expo.io/guides/color-schemes/
*/
import {
Text as DefaultText,
View as DefaultView,
useColorScheme,
} from 'react-native';
import Colors from '../constants/Colors';
type ThemeProps = {
lightColor?: string;
darkColor?: string;
};
export type TextProps = ThemeProps & DefaultText['props'];
export type ViewProps = ThemeProps & DefaultView['props'];
export function useThemeColor(
props: { light?: string; dark?: string },
colorName: keyof typeof Colors.light & keyof typeof Colors.dark,
) {
const theme = useColorScheme() ?? 'light';
const colorFromProps = props[theme];
if (colorFromProps) {
return colorFromProps;
}
return Colors[theme][colorName];
}
export function Text(props: TextProps) {
const { style, lightColor, darkColor, ...otherProps } = props;
const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
return <DefaultText style={[{ color }, style]} {...otherProps} />;
}
export function View(props: ViewProps) {
const { style, lightColor, darkColor, ...otherProps } = props;
const backgroundColor = useThemeColor(
{ light: lightColor, dark: darkColor },
'background',
);
return <DefaultView style={[{ backgroundColor }, style]} {...otherProps} />;
}

View File

@@ -0,0 +1,19 @@
const tintColorLight = '#2f95dc';
const tintColorDark = '#fff';
export default {
light: {
text: '#000',
background: '#fff',
tint: tintColorLight,
tabIconDefault: '#ccc',
tabIconSelected: tintColorLight,
},
dark: {
text: '#fff',
background: '#000',
tint: tintColorDark,
tabIconDefault: '#ccc',
tabIconSelected: tintColorDark,
},
};

28
apps/mobile/eas.json Normal file
View File

@@ -0,0 +1,28 @@
{
"build": {
"production": {
"android": {
"buildType": "app-bundle"
}
},
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal",
"ios": {
"simulator": true
},
"android": {
"buildType": "apk"
}
}
},
"submit": {
"production": {}
},
"cli": {
"version": ">= 5.2.0"
}
}

View File

@@ -0,0 +1,13 @@
module.exports = {
displayName: 'mobile',
resolver: '@nx/jest/plugins/resolver',
preset: 'jest-expo',
transformIgnorePatterns: [
'node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg)',
],
moduleFileExtensions: ['ts', 'js', 'html', 'tsx', 'jsx'],
setupFilesAfterEnv: ['<rootDir>/test-setup.ts'],
moduleNameMapper: {
'\\.svg$': '@nx/expo/plugins/jest/svg-mock',
},
};

View File

@@ -0,0 +1,36 @@
const { withNxMetro } = require('@nx/expo');
const { getDefaultConfig } = require('@expo/metro-config');
const { mergeConfig } = require('metro-config');
const exclusionList = require('metro-config/src/defaults/exclusionList');
const defaultConfig = getDefaultConfig(__dirname);
const { assetExts, sourceExts } = defaultConfig.resolver;
/**
* Metro configuration
* https://facebook.github.io/metro/docs/configuration
*
* @type {import('metro-config').MetroConfig}
*/
const customConfig = {
transformer: {
babelTransformerPath: require.resolve('react-native-svg-transformer'),
},
resolver: {
assetExts: assetExts.filter((ext) => ext !== 'svg'),
sourceExts: [...sourceExts, 'svg'],
blockList: exclusionList([/^(?!.*node_modules).*\/dist\/.*/]),
// unstable_enableSymlinks: true,
// unstable_enablePackageExports: true,
},
};
module.exports = withNxMetro(mergeConfig(defaultConfig, customConfig), {
// Change this to true to see debugging info.
// Useful if you have issues resolving modules
debug: false,
// all the file extensions used for imports other than 'ts', 'tsx', 'js', 'jsx', 'json'
extensions: [],
// Specify folders to watch, in addition to Nx defaults (workspace libraries and node_modules)
watchFolders: [],
});

65
apps/mobile/package.json Normal file
View File

@@ -0,0 +1,65 @@
{
"name": "mobile",
"main": "expo-router/entry",
"version": "1.0.0",
"jest": {
"preset": "jest-expo"
},
"private": true,
"dependencies": {
"@babel/core": "*",
"@expo/metro-config": "*",
"@expo/vector-icons": "^13.0.0",
"@nx/expo": "*",
"@react-navigation/native": "^6.1.9",
"@testing-library/jest-native": "*",
"@testing-library/react-native": "*",
"expo": "*",
"expo-font": "^11.4.0",
"expo-linking": "^6.0.0",
"expo-router": "^2.0.14",
"expo-splash-screen": "~0.20.5",
"expo-status-bar": "*",
"expo-system-ui": "^2.6.0",
"expo-web-browser": "^12.5.0",
"metro-config": "*",
"pod-install": "*",
"react": "*",
"react-dom": "18.2.0",
"react-native": "*",
"react-native-gesture-handler": "^2.14.1",
"react-native-safe-area-context": "^4.8.2",
"react-native-screens": "^3.29.0",
"react-native-svg": "*",
"react-native-svg-transformer": "*",
"react-native-web": "^0.19.10"
},
"scripts": {
"eas-build-pre-install": "cd ../../ && node tools/scripts/eas-build-pre-install.mjs . apps/mobile && cp pnpm-lock.yaml apps/mobile",
"eas-build-post-install": "cd ../../ && node tools/scripts/eas-build-post-install.mjs . apps/mobile",
"android": "expo run:android",
"ios": "expo run:ios",
"test": "jest --watchAll",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"format": "prettier --write ."
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@rnx-kit/metro-config": "^1.3.14",
"@rnx-kit/metro-resolver-symlinks": "^0.1.34",
"@types/react": "18.0.28",
"eslint-plugin-react": "7.32.2",
"eslint-plugin-react-hooks": "4.6.0",
"jest": "^29.4.1",
"jest-expo": "~49.0.0",
"pod-install": "^0.1.39",
"react-test-renderer": "18.2.0",
"typescript": "~5.2.2"
},
"overrides": {
"react-refresh": "~0.14.0"
},
"resolutions": {
"react-refresh": "~0.14.0"
}
}

94
apps/mobile/project.json Normal file
View File

@@ -0,0 +1,94 @@
{
"name": "mobile",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/mobile/src",
"projectType": "application",
"targets": {
"start": {
"executor": "@nx/expo:start",
"dependsOn": ["ensure-symlink", "sync-deps"],
"options": {
"port": 8081
}
},
"serve": {
"executor": "nx:run-commands",
"options": {
"command": "nx start mobile"
}
},
"run-ios": {
"executor": "@nx/expo:run",
"dependsOn": ["ensure-symlink", "sync-deps"],
"options": {
"platform": "ios"
}
},
"run-android": {
"executor": "@nx/expo:run",
"dependsOn": ["ensure-symlink", "sync-deps"],
"options": {
"platform": "android"
}
},
"build": {
"executor": "@nx/expo:build",
"options": {}
},
"submit": {
"executor": "@nx/expo:submit",
"options": {}
},
"build-list": {
"executor": "@nx/expo:build-list",
"options": {}
},
"sync-deps": {
"executor": "@nx/expo:sync-deps",
"options": {}
},
"ensure-symlink": {
"executor": "@nx/expo:ensure-symlink",
"options": {}
},
"prebuild": {
"executor": "@nx/expo:prebuild",
"dependsOn": ["ensure-symlink", "sync-deps"],
"options": {}
},
"install": {
"executor": "@nx/expo:install",
"options": {}
},
"update": {
"executor": "@nx/expo:update",
"options": {}
},
"export": {
"executor": "@nx/expo:export",
"dependsOn": ["ensure-symlink", "sync-deps"],
"options": {
"platform": "all",
"outputDir": "../../dist/apps/mobile"
}
},
"export-web": {
"executor": "@nx/expo:export",
"options": {
"bundler": "metro"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"]
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "apps/mobile/jest.config.ts"
}
}
},
"tags": []
}

View File

@@ -0,0 +1 @@
import '@testing-library/jest-native/extend-expect';

View File

@@ -0,0 +1,15 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": ["node"]
},
"files": ["../../node_modules/@nx/expo/typings/svg.d.ts"],
"exclude": [
"jest.config.ts",
"**/*.spec.ts",
"**/*.spec.tsx",
"test-setup.ts"
],
"include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"]
}

29
apps/mobile/tsconfig.json Normal file
View File

@@ -0,0 +1,29 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"jsx": "react-native",
"lib": [
"dom",
"esnext"
],
"moduleResolution": "node",
"skipLibCheck": true,
"resolveJsonModule": true,
"strict": true,
"declaration": true
},
"files": [],
"include": [
".expo/types/**/*.ts",
"expo-env.d.ts"
],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}

View File

@@ -0,0 +1,20 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": [
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/**/*.d.ts"
]
}

3
babel.config.json Normal file
View File

@@ -0,0 +1,3 @@
{
"babelrcRoots": ["*"]
}

5
jest.config.ts Normal file
View File

@@ -0,0 +1,5 @@
import { getJestProjects } from '@nx/jest';
export default {
projects: getJestProjects(),
};

3
jest.preset.js Normal file
View File

@@ -0,0 +1,3 @@
const nxPreset = require('@nx/jest/preset').default;
module.exports = { ...nxPreset };

41
nx.json Normal file
View File

@@ -0,0 +1,41 @@
{
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"affected": {
"defaultBase": "master"
},
"targetDefaults": {
"build": {
"cache": true,
"dependsOn": ["^build"],
"inputs": ["production", "^production"]
},
"lint": {
"cache": true
},
"@nx/jest:jest": {
"cache": true,
"inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"],
"options": {
"passWithNoTests": true
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
}
}
},
"namedInputs": {
"default": ["{projectRoot}/**/*", "sharedGlobals"],
"production": [
"default",
"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
"!{projectRoot}/tsconfig.spec.json",
"!{projectRoot}/jest.config.[jt]s",
"!{projectRoot}/src/test-setup.[jt]s",
"!{projectRoot}/test-setup.[jt]s"
],
"sharedGlobals": []
}
}

64
package.json Normal file
View File

@@ -0,0 +1,64 @@
{
"name": "@movie-web/native-app",
"version": "0.0.0",
"license": "MIT",
"scripts": {},
"private": true,
"devDependencies": {
"@config-plugins/detox": "~6.0.0",
"@expo/cli": "~0.10.13",
"@nx/detox": "17.2.8",
"@nx/expo": "17.2.8",
"@nx/jest": "17.2.8",
"@nx/js": "17.2.8",
"@nx/workspace": "17.2.8",
"@swc-node/register": "~1.6.8",
"@swc/core": "~1.3.102",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/jest-native": "~5.4.3",
"@testing-library/react-native": "~12.3.0",
"@types/jest": "^29.4.0",
"@types/node": "18.16.9",
"@types/react": "18.0.28",
"@typescript-eslint/eslint-plugin": "^6.18.1",
"@typescript-eslint/parser": "^6.18.1",
"babel-jest": "^29.4.1",
"babel-preset-expo": "~9.5.2",
"detox": "^20.11.1",
"eas-cli": "~5.2.0",
"eslint": "^8.56.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "6.7.1",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "7.32.2",
"eslint-plugin-react-hooks": "4.6.0",
"jest": "^29.4.1",
"jest-circus": "^29.4.1",
"jest-environment-jsdom": "^29.4.1",
"jest-expo": "~49.0.0",
"metro": "0.76.8",
"metro-resolver": "0.76.8",
"nx": "17.2.8",
"prettier": "^3.0.3",
"react-test-renderer": "18.2.0",
"ts-jest": "^29.1.0",
"ts-node": "10.9.1",
"typescript": "~5.2.2"
},
"dependencies": {
"@expo/metro-config": "~0.10.7",
"expo": "49.0.16",
"expo-splash-screen": "~0.20.5",
"expo-status-bar": "~1.6.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.72.6",
"react-native-svg": "13.9.0",
"react-native-svg-transformer": "1.3.0",
"react-native-web": "~0.19.9",
"tslib": "^2.3.0"
}
}

View File

@@ -1 +0,0 @@
This will be the folder that holds the common library

14515
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

3
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,3 @@
packages:
- packages/*
- apps/*

View File

@@ -0,0 +1,28 @@
/**
* This script is used to patch the '@nx/expo' package to work with EAS Build.
* It is run as a eas-build-post-install script in the 'package.json' of expo app.
* It is executed as 'node tools/scripts/eas-build-post-install.mjs <workspace root> <project root>'
* It will create a symlink from the project's node_modules to the workspace's node_modules.
*/
import { symlink, existsSync } from 'fs';
import { join } from 'path';
const [workspaceRoot, projectRoot] = process.argv.slice(2);
if (existsSync(join(workspaceRoot, 'node_modules'))) {
console.log('Symlink already exists');
process.exit(0);
}
symlink(
join(projectRoot, 'node_modules'),
join(workspaceRoot, 'node_modules'),
'dir',
(err) => {
if (err) console.log(err);
else {
console.log('Symlink created');
}
},
);

View File

@@ -0,0 +1,33 @@
/*
* This script is used to patch the '@nx/expo' package to work with EAS Build.
* It is run as the eas-build-pre-install script in the 'package.json' of expo app.
* It is executed as 'node tools/scripts/eas-build-pre-install.mjs <workspace root> <project root>'
* It will copy the dependencies and devDependencies from the workspace package.json to project's package.json.
* This is needed because EAS Build does the install in project's directory and not workspace's directory.
*/
import { readFileSync, writeFileSync } from 'fs';
import { join } from 'path';
const [workspaceRoot, projectRoot] = process.argv.slice(2);
if (!workspaceRoot) {
throw new Error('Missing workspace root');
}
if (!projectRoot) {
throw new Error('Missing project root');
}
try {
const workspacePackage = JSON.parse(
readFileSync(join(workspaceRoot, 'package.json')).toString(),
);
const projectPackage = JSON.parse(
readFileSync(join(projectRoot, 'package.json')).toString(),
);
projectPackage.dependencies = workspacePackage.dependencies;
projectPackage.devDependencies = workspacePackage.devDependencies;
writeFileSync(
join(projectRoot, 'package.json'),
JSON.stringify(projectPackage, null, 2),
);
} catch (e) {
console.error('Error reading package.json file', e);
}

19
tsconfig.base.json Normal file
View File

@@ -0,0 +1,19 @@
{
"compilerOptions": {
"rootDir": ".",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "es2015",
"module": "esnext",
"lib": ["es2020", "dom"],
"skipLibCheck": true,
"skipDefaultLibCheck": true,
"baseUrl": ".",
"paths": {}
},
"exclude": ["node_modules", "tmp"]
}