diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 303d00b2c..edd97bed2 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -26,21 +26,21 @@ jobs: - '.github/workflows/validate.yml' js: - '.node-version' - - '.eslintrc.js' + - '.eslint.config.mjs' - '.prettierrc.js' - 'package.json' - 'tsconfig.json' - 'yarn.lock' - 'src/**' - - 'example/src/**' - - 'example/**.json' - - 'example/**.js' + - 'apps/example-native/src/**' + - 'apps/example-native/**.json' + - 'apps/example-native/**.js' ios: - 'ios/**' - - 'example/ios/**' + - 'apps/example-native/ios/**' android: - 'android/**' - - 'example/android/**' + - 'apps/example-native/android/**' docs: - 'docs/**' check-typescript: @@ -57,23 +57,13 @@ jobs: - name: Install Dependencies if: ${{ needs.check-changes.outputs.should-check-types }} run: |- - yarn install --frozen-lockfile - - name: Install Example Dependencies - if: ${{ needs.check-changes.outputs.should-check-types }} - run: |- - yarn example install --frozen-lockfile + yarn install --immutable - name: Check Lint, Format & Types if: ${{ needs.check-changes.outputs.should-check-types }} run: | - yarn lint - yarn format - yarn typecheck - - name: Example - Check Lint, Format & Types - if: ${{ needs.check-changes.outputs.should-check-types }} - run: | - yarn example lint - yarn example format - yarn example typecheck + yarn lint:check:all + yarn format:check:all + yarn types build-ios: runs-on: blaze/macos-14 needs: check-changes @@ -87,21 +77,16 @@ jobs: +: ruby-lang.org@3.1.0 classic.yarnpkg.com tuist.io/xcbeautify - - name: Install Library Dependencies + - name: Install Dependencies if: ${{ needs.check-changes.outputs.should-build-ios }} - run: yarn install --frozen-lockfile + run: yarn install --immutable - name: Build Library if: ${{ needs.check-changes.outputs.should-build-ios }} run: yarn build - - name: Install Example Dependencies - if: ${{ needs.check-changes.outputs.should-build-ios }} - run: |- - cd example - yarn install --frozen-lockfile - name: Bundle Install if: ${{ needs.check-changes.outputs.should-build-ios }} run: |- - cd example/ios + cd apps/example-native/ios pkgx +ruby-lang.org@3.1.0 gem install bundler pkgx +ruby-lang.org@3.1.0 bundle config set --local path 'vendor/bundle' pkgx +ruby-lang.org@3.1.0 bundle install @@ -109,19 +94,19 @@ jobs: if: ${{ needs.check-changes.outputs.should-build-ios }} uses: buildjet/cache@v4 with: - path: example/ios/Pods - key: ${{ runner.os }}-pods-${{ hashFiles('example/ios/Podfile.lock') }} + path: apps/example-native/ios/Pods + key: ${{ runner.os }}-pods-${{ hashFiles('apps/example-native/ios/Podfile.lock') }} restore-keys: | ${{ runner.os }}-pods- - name: Install Cococapods if: ${{ needs.check-changes.outputs.should-build-ios }} run: |- - cd example/ios + cd apps/example-native/ios pkgx +ruby-lang.org@3.1.0 bundle exec pod install - name: Build App if: ${{ needs.check-changes.outputs.should-build-ios }} run: |- - cd example/ios + cd apps/example-native/ios set -o pipefail && xcodebuild build -workspace TrackPlayerExample.xcworkspace -scheme TrackPlayerExample -destination 'platform=iOS Simulator,name=iPhone 15 Pro' | xcbeautify --renderer github-actions build-android: runs-on: ubuntu-latest @@ -134,35 +119,30 @@ jobs: uses: pkgxdev/setup@v2 with: +: classic.yarnpkg.com - - name: Install Library Dependencies + - name: Install Dependencies if: ${{ needs.check-changes.outputs.should-build-android }} - run: yarn install --frozen-lockfile + run: yarn install --immutable - name: Build Library if: ${{ needs.check-changes.outputs.should-build-android }} run: yarn build - - name: Install Mobile Dependencies - if: ${{ needs.check-changes.outputs.should-build-android }} - run: |- - cd example - yarn install - name: Cache Gradle Wrapper if: ${{ needs.check-changes.outputs.should-build-android }} uses: actions/cache@v4 with: path: ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('example/android/gradle/wrapper/gradle-wrapper.properties') }} + key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('apps/example-native/android/gradle/wrapper/gradle-wrapper.properties') }} - name: Cache Gradle Dependencies if: ${{ needs.check-changes.outputs.should-build-android }} uses: actions/cache@v4 with: path: ~/.gradle/caches - key: ${{ runner.os }}-gradle-caches-${{ hashFiles('example/android/gradle/wrapper/gradle-wrapper.properties') }} + key: ${{ runner.os }}-gradle-caches-${{ hashFiles('apps/example-native/android/gradle/wrapper/gradle-wrapper.properties') }} restore-keys: | ${{ runner.os }}-gradle-caches- - name: Build App if: ${{ needs.check-changes.outputs.should-build-android }} run: |- - cd example/android + cd apps/example-native/android ./gradlew assembleDebug --no-daemon build-docs: runs-on: ubuntu-latest @@ -181,7 +161,7 @@ jobs: - name: Install Dependencies if: ${{ needs.check-changes.outputs.should-build-docs }} run: |- - yarn install --frozen-lockfile + yarn install --immutable - name: Build Docs if: ${{ needs.check-changes.outputs.should-build-docs }} run: |- diff --git a/.gitignore b/.gitignore index 67f32126d..55cbb6f9d 100644 --- a/.gitignore +++ b/.gitignore @@ -43,10 +43,10 @@ android.iml # Cocoapods # -example/ios/Pods +apps/*/ios/Pods # Ruby -example/vendor/ +apps/*/vendor/ # node.js # diff --git a/apps/common-app/package.json b/apps/common-app/package.json new file mode 100644 index 000000000..db62cfbda --- /dev/null +++ b/apps/common-app/package.json @@ -0,0 +1,39 @@ +{ + "name": "common-app", + "version": "0.0.1", + "private": true, + "scripts": { + "format": "prettier --write src", + "format:check": "prettier --check src", + "lint": "eslint src --fix", + "lint:check": "eslint src --max-warnings=0", + "start": "react-native start", + "types": "tsc --noEmit true" + }, + "peerDependencies": { + "react-native": "*" + }, + "dependencies": { + "@react-native-community/slider": "^4.5.7", + "@react-native-vector-icons/fontawesome6": "^12.0.1", + "react": "19.1.0", + "react-native-safe-area-context": "^5.5.0", + "react-native-track-player": "workspace:*" + }, + "devDependencies": { + "@babel/core": "^7.25.2", + "@babel/preset-env": "^7.25.3", + "@babel/runtime": "^7.25.0", + "@react-native-community/cli": "19.1.1", + "@react-native-community/cli-platform-android": "19.1.1", + "@react-native-community/cli-platform-ios": "19.1.1", + "@react-native/babel-preset": "0.80.2", + "@react-native/eslint-config": "0.80.2", + "@react-native/metro-config": "0.80.2", + "@react-native/typescript-config": "0.80.2", + "@types/react": "^19.1.0" + }, + "engines": { + "node": ">=24" + } +} diff --git a/example/src/App.tsx b/apps/common-app/src/App.tsx similarity index 98% rename from example/src/App.tsx rename to apps/common-app/src/App.tsx index 3c4caaa6d..5b7181293 100644 --- a/example/src/App.tsx +++ b/apps/common-app/src/App.tsx @@ -13,9 +13,7 @@ import { View, } from 'react-native'; import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context'; -import TrackPlayer, { - useActiveTrack -} from 'react-native-track-player'; +import TrackPlayer, { useActiveTrack } from 'react-native-track-player'; import { ActionSheet, Button, diff --git a/example/src/assets/data/playlist.json b/apps/common-app/src/assets/data/playlist.json similarity index 100% rename from example/src/assets/data/playlist.json rename to apps/common-app/src/assets/data/playlist.json diff --git a/example/src/assets/resources/artwork.jpg b/apps/common-app/src/assets/resources/artwork.jpg similarity index 100% rename from example/src/assets/resources/artwork.jpg rename to apps/common-app/src/assets/resources/artwork.jpg diff --git a/example/src/assets/resources/pure.m4a b/apps/common-app/src/assets/resources/pure.m4a similarity index 100% rename from example/src/assets/resources/pure.m4a rename to apps/common-app/src/assets/resources/pure.m4a diff --git a/example/src/components/ActionSheet.tsx b/apps/common-app/src/components/ActionSheet.tsx similarity index 100% rename from example/src/components/ActionSheet.tsx rename to apps/common-app/src/components/ActionSheet.tsx diff --git a/example/src/components/Button.tsx b/apps/common-app/src/components/Button.tsx similarity index 100% rename from example/src/components/Button.tsx rename to apps/common-app/src/components/Button.tsx diff --git a/example/src/components/OptionSheet.tsx b/apps/common-app/src/components/OptionSheet.tsx similarity index 97% rename from example/src/components/OptionSheet.tsx rename to apps/common-app/src/components/OptionSheet.tsx index 622a2edf0..e2aa6617a 100644 --- a/example/src/components/OptionSheet.tsx +++ b/apps/common-app/src/components/OptionSheet.tsx @@ -41,9 +41,7 @@ export function OptionSheet() { value: 'stop-playback-and-remove-notification', }, ]} - value={ - currentOptions.android.appKilledPlaybackBehavior - } + value={currentOptions.android.appKilledPlaybackBehavior} onSelect={(appKilledPlaybackBehavior: AppKilledPlaybackBehavior) => { TrackPlayer.updateOptions({ android: { diff --git a/example/src/components/PlayPauseButton.tsx b/apps/common-app/src/components/PlayPauseButton.tsx similarity index 89% rename from example/src/components/PlayPauseButton.tsx rename to apps/common-app/src/components/PlayPauseButton.tsx index 7dba8595e..185026c0d 100644 --- a/example/src/components/PlayPauseButton.tsx +++ b/apps/common-app/src/components/PlayPauseButton.tsx @@ -14,9 +14,7 @@ export function PlayPauseButton() { {buffering ? ( ) : ( - + App); diff --git a/example/ios/.xcode.env b/apps/example-native/ios/.xcode.env similarity index 100% rename from example/ios/.xcode.env rename to apps/example-native/ios/.xcode.env diff --git a/example/ios/Podfile b/apps/example-native/ios/Podfile similarity index 100% rename from example/ios/Podfile rename to apps/example-native/ios/Podfile diff --git a/example/ios/Podfile.lock b/apps/example-native/ios/Podfile.lock similarity index 94% rename from example/ios/Podfile.lock rename to apps/example-native/ios/Podfile.lock index 8139875dc..f562bee5f 100644 --- a/example/ios/Podfile.lock +++ b/apps/example-native/ios/Podfile.lock @@ -1648,7 +1648,7 @@ PODS: - React-RCTFBReactNativeSpec - ReactCommon/turbomodule/core - SocketRocket - - react-native-safe-area-context (5.5.0): + - react-native-safe-area-context (5.6.2): - boost - DoubleConversion - fast_float @@ -1667,8 +1667,8 @@ PODS: - React-hermes - React-ImageManager - React-jsi - - react-native-safe-area-context/common (= 5.5.0) - - react-native-safe-area-context/fabric (= 5.5.0) + - react-native-safe-area-context/common (= 5.6.2) + - react-native-safe-area-context/fabric (= 5.6.2) - React-NativeModulesApple - React-RCTFabric - React-renderercss @@ -1679,7 +1679,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - react-native-safe-area-context/common (5.5.0): + - react-native-safe-area-context/common (5.6.2): - boost - DoubleConversion - fast_float @@ -1708,7 +1708,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - react-native-safe-area-context/fabric (5.5.0): + - react-native-safe-area-context/fabric (5.6.2): - boost - DoubleConversion - fast_float @@ -1826,7 +1826,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - react-native-vector-icons-fontawesome6 (12.0.1) + - react-native-vector-icons-fontawesome6 (12.2.0) - React-NativeModulesApple (0.80.2): - boost - DoubleConversion @@ -2348,7 +2348,7 @@ DEPENDENCIES: - React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`) - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) - "react-native-slider (from `../node_modules/@react-native-community/slider`)" - - react-native-track-player (from `../..`) + - react-native-track-player (from `../../..`) - "react-native-vector-icons-fontawesome6 (from `../node_modules/@react-native-vector-icons/fontawesome6`)" - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) - React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`) @@ -2475,7 +2475,7 @@ EXTERNAL SOURCES: react-native-slider: :path: "../node_modules/@react-native-community/slider" react-native-track-player: - :path: "../.." + :path: "../../.." react-native-vector-icons-fontawesome6: :path: "../node_modules/@react-native-vector-icons/fontawesome6" React-NativeModulesApple: @@ -2551,76 +2551,76 @@ SPEC CHECKSUMS: fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 hermes-engine: bbc1152da7d2d40f9e59c28acc6576fcf5d28e2a - RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669 + RCT-Folly: 59ec0ac1f2f39672a0c6e6cecdd39383b764646f RCTDeprecation: 300c5eb91114d4339b0bb39505d0f4824d7299b7 RCTRequired: e0446b01093475b7082fbeee5d1ef4ad1fe20ac4 RCTTypeSafety: cb974efcdc6695deedf7bf1eb942f2a0603a063f React: e7a4655b09d0e17e54be188cc34c2f3e2087318a React-callinvoker: 62192daaa2f30c3321fc531e4f776f7b09cf892b - React-Core: b23cdaaa9d76389d958c06af3c57aa6ad611c542 - React-CoreModules: 8e0f562e5695991e455abbebe1e968af71d52553 - React-cxxreact: 6ccbe0cc2c652b29409b14b23cfb3cd74e084691 + React-Core: c400b068fdb6172177f3b3fae00c10d1077244d7 + React-CoreModules: 8e911a5a504b45824374eec240a78de7a6db8ca2 + React-cxxreact: 06a91f55ac5f842219d6ca47e0f77187a5b5f4ac React-debug: 1834225a63b420b16e9b8b01ba5870aee96d0610 - React-defaultsnativemodule: dd88d445d542d58ab61a8a29a7c1d2272dfed577 - React-domnativemodule: fc3c24f4d3bb92770727ea48b4133dab77ded7f7 - React-Fabric: 00fe76339e568da0d0497cc72daeeb01e463871a - React-FabricComponents: 7bb179ee55db68f88c007800b0ac62c930115a85 - React-FabricImage: 21e01118011dd1e4ff3cdab20dbf57839cff52ee - React-featureflags: 6e67f2e252bc8ebb1d538c2ae8c14df432fe5fc0 - React-featureflagsnativemodule: eff5216a5cde5df5d09243d15db1bc401474deef - React-graphics: 8539372da8754118a565251ed08a88fc70f69340 - React-hermes: cc8c77acee1406c258622cd8abbee9049f6b5761 - React-idlecallbacksnativemodule: 7349675d1ccbec876c29b0e206ac08c762baaa36 - React-ImageManager: 4089d8ad52c86a8ae1d7591282fff1665ff5518b - React-jserrorhandler: 89a7a5fa8d04791e729119d1db03bf0ee85a9e29 - React-jsi: ea5c640ea63c127080f158dac7f4f393d13d415c - React-jsiexecutor: cf7920f82e46fe9a484c15c9f31e67d7179aa826 - React-jsinspector: 69e974b6313dbbb635ba503f2f4f2c389b30edbf - React-jsinspectorcdp: 231ddd5b7164c37589dcde3b8b6960136c891d6d - React-jsinspectornetwork: ff74911f79cf0a407a7f0ad0eeb0be64687ed815 - React-jsinspectortracing: df2aa2d944bb3fa280d9c920b9a06664bca8a7e8 - React-jsitooling: 77849c27e374a028ed8106e434a35267f6c6600b - React-jsitracing: 0dc6978e5b38c6e5e01e6aed484e4aec3f5f581b - React-logger: 7cfc7b1ae1f8e5fe5097f9c746137cc3a8fad4ce - React-Mapbuffer: 7018c5b7da5b13ed22fe55dae51d50187a00b2d7 - React-microtasksnativemodule: 8ff9cb220a8efa625b5885996bd69e69db9edf02 - react-native-safe-area-context: 3bae4f8474c13ab141c40ed6c5c33f6177778d71 - react-native-slider: c434f7094c9500dfa1176931f48e5957872818f8 - react-native-track-player: 5a85aff2010595a73137ca9df980cf0cec78f997 - react-native-vector-icons-fontawesome6: 624a5578d701e52b18fb7f35b56556395a4249c0 - React-NativeModulesApple: 37c08c3c54db55854de816b0df0f3683832be35a + React-defaultsnativemodule: 260aa990a9617c58df46c00321f396ad6ea7cc7f + React-domnativemodule: 9b3456a614c325da986867f27ca0eb34cb86828c + React-Fabric: fc7bcbac28989e6025ca6ae0988bff61bb78e5d3 + React-FabricComponents: ae4a9c82bedf7c95bace1b215caf8685bcb32e23 + React-FabricImage: c9cd4786180c150bb2a3841d65d360fd52be9ef8 + React-featureflags: 534cd678e05848fbfc8c7288d4b14bcd8894b696 + React-featureflagsnativemodule: bf7419f4d81226a3c4dd792445a03a6d703ce9a4 + React-graphics: 18296c3559d54a42baaf7f2ae9c137a2e0fe9d51 + React-hermes: b6e33fcd21aa7523dc76e62acd7a547e68c28a5b + React-idlecallbacksnativemodule: da8696a714ab16adb56bbfc9e0dfb4de7a713340 + React-ImageManager: 052ccce122e4fd4e09c5d4f30e56381704dac439 + React-jserrorhandler: 4c037384a32f57332abfa64181aeea915f9e0f0d + React-jsi: 3fde19aaf675c0607a0824c4d6002a4943820fd9 + React-jsiexecutor: 4f898228240cf261a02568e985dfa7e1d7ad1dfb + React-jsinspector: 4ad0cdfa25a45d1362e2ddd06c78727d7964b34f + React-jsinspectorcdp: a649cc98a448e0fd8d54ac2a9e3e53177a1d8bd3 + React-jsinspectornetwork: 2d701b6b152be202342f8269223046ec664c7d47 + React-jsinspectortracing: cd898b3d7ea89f3e0ae10020fe3504bb4b327dd8 + React-jsitooling: feca163583c69ba642cebb6b8ccd2f5e6732fed8 + React-jsitracing: 1965307a468987b20d2a020f8fe782efa591ded7 + React-logger: ea80169d826e0cd112fa4d68f58b2b3b968f1ecb + React-Mapbuffer: a5d550d1add940ed2bc65b20dc1413407bf1a63f + React-microtasksnativemodule: 5d00fefc19f0bc9a6432e5533683d6fc9c3da4e1 + react-native-safe-area-context: d446989793f96dc2f44c33c42dbfb316d983f24e + react-native-slider: 83d77040942794b3994a8c3e116258463326cee5 + react-native-track-player: 4d01ef050bc01cce94ad66b34d1aae4ec797988a + react-native-vector-icons-fontawesome6: 1b667969bef2f430d1d7515163b980b856f58670 + React-NativeModulesApple: b22e6abb44d78270dfdfc7d85efe29e35e0333a7 React-oscompat: 56d6de59f9ae95cd006a1c40be2cde83bc06a4e1 - React-perflogger: 4008bd05a8b6c157b06608c0ea0b8bd5d9c5e6c9 - React-performancetimeline: 9321ba7605abcfb3a2b497fd7cbaf5cfd8c7cf67 + React-perflogger: 0633844e495d8b34798c9bf0cb32ce315f1d5c9f + React-performancetimeline: a04dae9154c32eda1891fcfa51cb2680a0421b3e React-RCTActionSheet: 49138012280ec3bbb35193d8d09adb8bc61c982e - React-RCTAnimation: ebfe7c62016d4c17b56b2cab3a221908ae46288d - React-RCTAppDelegate: 0108657ba9a19f6a1cd62dcd19c2c0485b3fc251 - React-RCTBlob: 6cc309d1623f3c2679125a04a7425685b7219e6b - React-RCTFabric: 0a9ff5c9d1e1d7fc026bda6671180cbf56861c15 - React-RCTFBReactNativeSpec: ff3e37e2456afc04211334e86d07bf20488df0ae - React-RCTImage: bb98a59aeed953a48be3f917b9b745b213b340ab - React-RCTLinking: d6e9795d4d75d154c1dd821fd0746cc3e05d6670 - React-RCTNetwork: 5c8a7a2dd26728323189362f149e788548ac72bc - React-RCTRuntime: 96808e8fdce300a26c82d8c24174e33ba5210a7c - React-RCTSettings: b6a02d545ce10dd936b39914b32674db6e865307 - React-RCTText: c7d9232da0e9b5082a99a617483d9164a9cd46e9 - React-RCTVibration: fe636c985c1bf25e4a5b5b4d9315a3b882468a72 + React-RCTAnimation: c7ed4a9d5a4e43c9b10f68bb43cd238c4a2e7e89 + React-RCTAppDelegate: ea2ab6f4aef1489f72025b7128d8ab645b40eafb + React-RCTBlob: c052799460b245e1fffe3d1dddea36fa88e998a0 + React-RCTFabric: e7acf005f8ed58d09f755b980ff83703b3af9fcf + React-RCTFBReactNativeSpec: ffb22c3ee3d359ae9245ca94af203845da9371ec + React-RCTImage: 59fc2571f4f109a77139924f5babee8f9cd639c9 + React-RCTLinking: a045cb58c08188dce6c6f4621de105114b1b16ce + React-RCTNetwork: fc7115a2f5e15ae0aa05e9a9be726817feefb482 + React-RCTRuntime: a7bca9be4f571586b2a9d4b57cf605421ffb6335 + React-RCTSettings: 30d7dd7eae66290467a1e72bf42d927fa78c3884 + React-RCTText: 755d59284e66c7d33bb4f0ccc428fe69110c3e74 + React-RCTVibration: ffe019e588815df226f6f8ccdc65979f8b2bc440 React-rendererconsistency: d20fcb77173861cc7d8356239823e3b36966fc31 - React-renderercss: 56461d1e18db6a325048fdd04a51d68bd7ddb5a8 - React-rendererdebug: fcd44d3eb8a02d74beee778bb142e724016c7375 + React-renderercss: 63c720c32aaabd4788ac4136a071d49a052d8002 + React-rendererdebug: a25ddddc73cabf50d814d8dfbc60d257b3d854c4 React-rncore: bafb76fc01b78757a9592e92dbc227f9260bf0ac - React-RuntimeApple: 01e3ad08793efaa54cf85276457fa4a1f103d5b4 - React-RuntimeCore: 5c4bec5bf402a99b134e55972f2f4e676c70b9ab + React-RuntimeApple: 45f8ef1b220a91b4fa4a79820b81990bffd95aa5 + React-RuntimeCore: a0e095493b22ee3f6c639df4258cc5185674f0b8 React-runtimeexecutor: b35de9cb7f5d19c66ea9b067235f95b947697ba5 - React-RuntimeHermes: ba549a5834a6592d243b9a605530ecd7b6f5e79c - React-runtimescheduler: 9a9914d58caec7976aaae381cd2d997408f2260f + React-RuntimeHermes: 5b8126fffd1531475861dc0294a10b5f9793271a + React-runtimescheduler: 44fa97351d105afd0ffaecc4ed11cadad562deb6 React-timing: 4f97958cc918f0af9444f93e4a7083415e6f5daf - React-utils: f491e2726eb8ced8af13893e1f77317f0fa9a954 - ReactAppDependencyProvider: 8df342c127fd0c1e30e8b9f71ff814c22414a7c0 - ReactCodegen: 439c427ccc115d71d16cc84256e5fbdc7fcef57a - ReactCommon: 592ef441605638b95e533653259254b4bd35ff4f + React-utils: 3c4b0b7788e4dc132d1bf918bc0615e2b21f36b3 + ReactAppDependencyProvider: 6c9197c1f6643633012ab646d2bfedd1b0d25989 + ReactCodegen: 9ea66ee246511816b72e9d6e380f884b7b3b99d7 + ReactCommon: 7aca047f2f453a7d7f0adeccb63810d61829235a SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 - Yoga: a742cc68e8366fcfc681808162492bc0aa7a9498 + Yoga: 1c52fbd270869e556504def7e94fffbf67f53f7b PODFILE CHECKSUM: 3b4ec20947e91756d94116d805d6728ccbf46a37 diff --git a/example/ios/TrackPlayerExample.xcodeproj/project.pbxproj b/apps/example-native/ios/TrackPlayerExample.xcodeproj/project.pbxproj similarity index 100% rename from example/ios/TrackPlayerExample.xcodeproj/project.pbxproj rename to apps/example-native/ios/TrackPlayerExample.xcodeproj/project.pbxproj diff --git a/example/ios/TrackPlayerExample.xcodeproj/xcshareddata/xcschemes/TrackPlayerExample.xcscheme b/apps/example-native/ios/TrackPlayerExample.xcodeproj/xcshareddata/xcschemes/TrackPlayerExample.xcscheme similarity index 100% rename from example/ios/TrackPlayerExample.xcodeproj/xcshareddata/xcschemes/TrackPlayerExample.xcscheme rename to apps/example-native/ios/TrackPlayerExample.xcodeproj/xcshareddata/xcschemes/TrackPlayerExample.xcscheme diff --git a/example/ios/TrackPlayerExample.xcworkspace/contents.xcworkspacedata b/apps/example-native/ios/TrackPlayerExample.xcworkspace/contents.xcworkspacedata similarity index 100% rename from example/ios/TrackPlayerExample.xcworkspace/contents.xcworkspacedata rename to apps/example-native/ios/TrackPlayerExample.xcworkspace/contents.xcworkspacedata diff --git a/example/ios/TrackPlayerExample/AppDelegate.swift b/apps/example-native/ios/TrackPlayerExample/AppDelegate.swift similarity index 100% rename from example/ios/TrackPlayerExample/AppDelegate.swift rename to apps/example-native/ios/TrackPlayerExample/AppDelegate.swift diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/Contents.json b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/Contents.json rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/Contents.json diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/Icon.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/Icon.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/Icon.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/Icon.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt@2x 1.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt@2x 1.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt@2x 1.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt@2x 1.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt@2x.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt@2x.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt@2x.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt@2x.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt@3x.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt@3x.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt@3x.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_20pt@3x.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt@2x 1.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt@2x 1.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt@2x 1.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt@2x 1.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt@2x.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt@2x.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt@2x.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt@2x.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt@3x.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt@3x.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt@3x.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_29pt@3x.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt@2x 1.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt@2x 1.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt@2x 1.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt@2x 1.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt@2x.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt@2x.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt@2x.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt@2x.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt@3x.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt@3x.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt@3x.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_40pt@3x.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_60pt@2x.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_60pt@2x.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_60pt@2x.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_60pt@2x.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_60pt@3x.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_60pt@3x.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_60pt@3x.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_60pt@3x.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_76pt.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_76pt.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_76pt.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_76pt.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_76pt@2x.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_76pt@2x.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_76pt@2x.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_76pt@2x.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_83.5@2x.png b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_83.5@2x.png similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_83.5@2x.png rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/AppIcon.appiconset/icon_83.5@2x.png diff --git a/example/ios/TrackPlayerExample/Images.xcassets/Contents.json b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/Contents.json similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/Contents.json rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/Contents.json diff --git a/example/ios/TrackPlayerExample/Images.xcassets/Logo.imageset/Contents.json b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/Logo.imageset/Contents.json similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/Logo.imageset/Contents.json rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/Logo.imageset/Contents.json diff --git a/example/ios/TrackPlayerExample/Images.xcassets/Logo.imageset/Logo.pdf b/apps/example-native/ios/TrackPlayerExample/Images.xcassets/Logo.imageset/Logo.pdf similarity index 100% rename from example/ios/TrackPlayerExample/Images.xcassets/Logo.imageset/Logo.pdf rename to apps/example-native/ios/TrackPlayerExample/Images.xcassets/Logo.imageset/Logo.pdf diff --git a/example/ios/TrackPlayerExample/Info.plist b/apps/example-native/ios/TrackPlayerExample/Info.plist similarity index 100% rename from example/ios/TrackPlayerExample/Info.plist rename to apps/example-native/ios/TrackPlayerExample/Info.plist diff --git a/example/ios/TrackPlayerExample/LaunchScreen.storyboard b/apps/example-native/ios/TrackPlayerExample/LaunchScreen.storyboard similarity index 100% rename from example/ios/TrackPlayerExample/LaunchScreen.storyboard rename to apps/example-native/ios/TrackPlayerExample/LaunchScreen.storyboard diff --git a/example/ios/TrackPlayerExample/PrivacyInfo.xcprivacy b/apps/example-native/ios/TrackPlayerExample/PrivacyInfo.xcprivacy similarity index 100% rename from example/ios/TrackPlayerExample/PrivacyInfo.xcprivacy rename to apps/example-native/ios/TrackPlayerExample/PrivacyInfo.xcprivacy diff --git a/example/jest.config.js b/apps/example-native/jest.config.js similarity index 100% rename from example/jest.config.js rename to apps/example-native/jest.config.js diff --git a/apps/example-native/metro.config.js b/apps/example-native/metro.config.js new file mode 100644 index 000000000..b380248a5 --- /dev/null +++ b/apps/example-native/metro.config.js @@ -0,0 +1,31 @@ +const path = require('path'); +const { getDefaultConfig } = require('@react-native/metro-config'); +const { withMetroConfig } = require('react-native-monorepo-config'); + +const root = path.resolve(__dirname, '..', '..'); +const commonAppPath = path.resolve(__dirname, '..', 'common-app'); + +/** + * Metro configuration + * https://facebook.github.io/metro/docs/configuration + * + * @type {import('metro-config').MetroConfig} + */ +const config = withMetroConfig(getDefaultConfig(__dirname), { + root, + dirname: __dirname, +}); + +// Add watchFolders to watch common-app +config.watchFolders = [root, commonAppPath]; + +// Ensure node_modules are resolved correctly +config.resolver = { + ...config.resolver, + nodeModulesPaths: [ + path.resolve(__dirname, 'node_modules'), + path.resolve(root, 'node_modules'), + ], +}; + +module.exports = config; diff --git a/example/package.json b/apps/example-native/package.json similarity index 80% rename from example/package.json rename to apps/example-native/package.json index 49ac61e4d..a4c092f33 100644 --- a/example/package.json +++ b/apps/example-native/package.json @@ -1,11 +1,12 @@ { - "name": "react-native-track-player-example", + "name": "example-native", "version": "0.0.1", "private": true, "scripts": { + "clean": "del-cli android/build android/app/build ios/build", "android:adb-reverse": "adb reverse tcp:8081 tcp:8081 && adb forward tcp:5277 tcp:5277", "android:adb-stop": "adb shell am force-stop trackplayer.example", - "android:dhu": "pkill -f 'desktop-head-unit' || true && $HOME/Library/Android/sdk/extras/google/auto/desktop-head-unit", + "android:dhu": "pkill -f 'desktop-head-unit' || true && $ANDROID_SDK_ROOT/extras/google/auto/desktop-head-unit --usb", "android:build": "react-native build-android --extra-params \"--no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a\"", "android:clean": "rm -rf android/.gradle && rm -rf android/build && rm -rf android/app/build && rm -rf android/app/.cxx", "android:ide": "open -a /Applications/Android\\ Studio.app ./android", @@ -14,20 +15,22 @@ "android:release": "cd android && ./gradlew clean && ./gradlew bundleRelease && cd app/build/outputs/bundle/release && pwd && ls", "android:uninstall": "adb uninstall trackplayer.example", "android": "react-native run-android", - "format:fix": "prettier --write src", - "format": "prettier --check src", "ios:build": "react-native build-ios --mode Debug", "ios:ide": "open ios/*.xcworkspace", "ios:sim": "react-native run-ios --simulator=\"iPhone\"", + "ios:rebuild": "cd ios && pod install && cd ../.. && yarn ios", "ios": "react-native run-ios", - "lint:fix": "eslint src --fix", - "lint": "eslint src --max-warnings=0", + "format": "prettier --write index.js", + "format:check": "prettier --check index.js", + "lint": "eslint . --fix", + "lint:check": "eslint . --max-warnings=0", "start": "react-native start", "types": "tsc --noEmit true" }, "dependencies": { "@react-native-community/slider": "^4.5.7", "@react-native-vector-icons/fontawesome6": "^12.0.1", + "common-app": "workspace:*", "react": "19.1.0", "react-native": "0.80.2", "react-native-safe-area-context": "^5.5.0" @@ -44,6 +47,7 @@ "@react-native/metro-config": "0.80.2", "@react-native/typescript-config": "0.80.2", "@types/react": "^19.1.0", + "babel-plugin-module-resolver": "^5.0.2", "react-native-builder-bob": "^0.40.12", "react-native-monorepo-config": "^0.1.9", "typescript": "^5.9.3" diff --git a/example/react-native.config.js b/apps/example-native/react-native.config.js similarity index 80% rename from example/react-native.config.js rename to apps/example-native/react-native.config.js index 59d969820..2701c08cf 100644 --- a/example/react-native.config.js +++ b/apps/example-native/react-native.config.js @@ -1,5 +1,5 @@ const path = require('path'); -const pkg = require('../package.json'); +const pkg = require('../../package.json'); module.exports = { project: { @@ -9,7 +9,7 @@ module.exports = { }, dependencies: { [pkg.name]: { - root: path.join(__dirname, '..'), + root: path.join(__dirname, '..', '..'), platforms: { // Codegen script incorrectly fails without this // So we explicitly specify the platforms with empty object diff --git a/apps/example-native/tsconfig.json b/apps/example-native/tsconfig.json new file mode 100644 index 000000000..3f5061a50 --- /dev/null +++ b/apps/example-native/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["../common-app/src/*"] + } + }, + "exclude": [ + "**/node_modules", + "**/Pods", + "metro.config.js", + "android", + "ios", + ".bundle" + ] +} diff --git a/apps/example-nextjs/.gitignore b/apps/example-nextjs/.gitignore new file mode 100644 index 000000000..a680367ef --- /dev/null +++ b/apps/example-nextjs/.gitignore @@ -0,0 +1 @@ +.next diff --git a/apps/example-nextjs/README.md b/apps/example-nextjs/README.md new file mode 100644 index 000000000..e839ba5c6 --- /dev/null +++ b/apps/example-nextjs/README.md @@ -0,0 +1,174 @@ +# TrackPlayer Next.js Example + +This example demonstrates how to use `react-native-track-player` in a Next.js web application using React Native Web. + +## Features + +- ✅ Full audio playback control (play, pause, skip) +- ✅ Progress tracking with visual progress bar +- ✅ Track metadata display with artwork +- ✅ Responsive UI using React Native components +- ✅ Server-side rendering compatible (uses dynamic imports) +- ✅ Web-specific player implementation using HTML5 Audio/Shaka Player + +## Quick Start + +### From the Monorepo Root + +```bash +# Install dependencies +yarn install + +# Build the library +yarn prepare + +# Start the Next.js dev server +cd apps/example-nextjs +yarn dev +``` + +Open [http://localhost:3000](http://localhost:3000) to see the audio player. + +## Running the App + +You can: + +- **Start in development mode:** + +```bash +yarn dev +``` + +- **Create and run a production build:** + +```bash +yarn build +yarn start +``` + +- **Analyze the bundle** (opens report in browser): + +```bash +yarn build:analyze +``` + +- **Build without minification** (useful for debugging): + +```bash +yarn build:disable-minification +``` + +## Project Structure + +``` +apps/example-nextjs/ +├── components/ +│ ├── AudioPlayer.js # Main player UI component +│ └── TrackPlayerProvider.js # Player setup and initialization +├── pages/ +│ ├── _app.js # Next.js app wrapper +│ ├── _document.js # HTML document structure +│ └── index.js # Home page with player +├── next.config.js # Next.js configuration +└── package.json # Dependencies +``` + +## How It Works + +### Server-Side Rendering + +The app uses Next.js dynamic imports to avoid SSR issues: + +```javascript +const AudioPlayer = dynamic(() => import('../components/AudioPlayer'), { + ssr: false, +}); +``` + +This ensures TrackPlayer only loads client-side where browser APIs are available. + +### Web Implementation + +- **Native (iOS/Android)**: Platform-specific audio APIs +- **Web**: HTML5 Audio API or Shaka Player for HLS/DASH + +The web implementation is automatically selected in browser environments. + +## Adding Custom Tracks + +Edit `components/TrackPlayerProvider.js`: + +```javascript +const tracks = [ + { + url: 'https://example.com/audio.mp3', + title: 'My Track', + artist: 'Artist Name', + artwork: 'https://example.com/artwork.jpg', + duration: 120, + }, +]; +``` + +## Components + +### TrackPlayerProvider + +Initializes TrackPlayer and loads the queue: + +```javascript + + + +``` + +### AudioPlayer + +Main UI with: + +- Track info and artwork +- Progress bar +- Playback controls (play/pause/skip) + +Uses TrackPlayer hooks: + +- `useActiveTrack()` - Current track info +- `useProgress()` - Playback progress +- `usePlaybackState()` - Player state + +## Troubleshooting + +### Audio Not Playing + +1. Check browser console for errors +2. Verify audio URLs are accessible (check CORS) +3. Some browsers require user interaction before playing + +### Module Resolution Issues + +```bash +# From root +yarn install +yarn prepare + +# Clear Next.js cache +cd apps/example-nextjs +rm -rf .next +yarn dev +``` + +## Web vs Native Differences + +| Feature | Web | Native | +| -------------------- | ----------------- | ------------------ | +| Background playback | Limited | Full | +| Lock screen controls | No | Yes | +| Notifications | No | Yes | +| Car integration | No | Yes | +| Audio formats | Browser-dependent | Platform-dependent | + +## Resources + +- [TrackPlayer Docs](https://react-native-track-player.js.org/) +- [Next.js Documentation](https://nextjs.org/docs) +- [React Native Web](https://necolas.github.io/react-native-web/) diff --git a/apps/example-nextjs/babel.config.js b/apps/example-nextjs/babel.config.js new file mode 100644 index 000000000..da4606b61 --- /dev/null +++ b/apps/example-nextjs/babel.config.js @@ -0,0 +1,4 @@ +/** @type {import('@babel/core').TransformOptions} */ +module.exports = { + presets: ['next/babel'], +}; diff --git a/apps/example-nextjs/components/TrackPlayerApp.js b/apps/example-nextjs/components/TrackPlayerApp.js new file mode 100644 index 000000000..0fccb290b --- /dev/null +++ b/apps/example-nextjs/components/TrackPlayerApp.js @@ -0,0 +1,33 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { ActivityIndicator, StyleSheet, View } from 'react-native'; +import App from '../../common-app/src/App'; + +const styles = StyleSheet.create({ + container: { + alignItems: 'center', + flexGrow: 1, + justifyContent: 'center', + backgroundColor: '#1a1a1a', + padding: 20, + }, +}); + +export default function TrackPlayerProvider() { + const [isMounted, setIsMounted] = useState(false); + + useEffect(() => { + setIsMounted(true); + }, []); + + if (!isMounted) { + return ( + + + + ); + } + + return ; +} diff --git a/apps/example-nextjs/cypress.config.js b/apps/example-nextjs/cypress.config.js new file mode 100644 index 000000000..8ae01ad7a --- /dev/null +++ b/apps/example-nextjs/cypress.config.js @@ -0,0 +1,9 @@ +const defineConfig = require('cypress').defineConfig; + +module.exports = { + default: defineConfig({ + e2e: { + supportFile: false, + }, + }), +}; diff --git a/apps/example-nextjs/next-env.d.ts b/apps/example-nextjs/next-env.d.ts new file mode 100644 index 000000000..254b73c16 --- /dev/null +++ b/apps/example-nextjs/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. diff --git a/apps/example-nextjs/next.config.js b/apps/example-nextjs/next.config.js new file mode 100644 index 000000000..90f529fe5 --- /dev/null +++ b/apps/example-nextjs/next.config.js @@ -0,0 +1,90 @@ +const path = require('path'); + +const withBundleAnalyzer = require('@next/bundle-analyzer')({ + enabled: process.env.ANALYZE_BUNDLE === '1', +}); + +// this can be used to obtain a more readable bundle for debugging +const disableMinification = process.env.DISABLE_MINIFICATION === '1'; + +const config = { + eslint: { + ignoreDuringBuilds: true, + }, + transpilePackages: [ + 'common-app', + 'react-native-track-player', + 'react-native-web', + 'react-native', + ], + webpack(webpackConfig, { isServer }) { + if (disableMinification) { + webpackConfig.optimization.minimizer = []; + } + + // Configure aliases - must be done for both client and server + webpackConfig.resolve.alias = { + ...(webpackConfig.resolve.alias || {}), + // Ensure single React instance + 'react': path.resolve(__dirname, 'node_modules/react'), + 'react-dom': path.resolve(__dirname, 'node_modules/react-dom'), + // Alias react-native to react-native-web + 'react-native$': path.resolve(__dirname, 'react-native-shim.js'), + 'react-native': path.resolve(__dirname, 'react-native-shim.js'), + // Use web-specific implementation for TrackPlayer (compiled) + 'react-native-track-player$': path.resolve( + __dirname, + '../../lib/module/index.js', + ), + }; + + // Ensure proper extensions + webpackConfig.resolve.extensions = [ + '.web.tsx', + '.web.ts', + '.web.jsx', + '.web.js', + '.tsx', + '.ts', + '.jsx', + '.js', + '.json', + '.wasm', + ...(webpackConfig.resolve.extensions || []).filter( + (ext) => + ![ + '.web.tsx', + '.web.ts', + '.web.jsx', + '.web.js', + '.tsx', + '.ts', + '.jsx', + '.js', + ].includes(ext), + ), + ]; + + // Add font file loader for react-native-vector-icons + webpackConfig.module.rules.push({ + test: /\.(ttf|otf|eot|woff|woff2)$/, + type: 'asset/resource', + generator: { + filename: 'static/fonts/[name][ext]', + }, + }); + + // Add audio/video file loader + webpackConfig.module.rules.push({ + test: /\.(mp3|mp4|m4a|wav|ogg|webm)$/, + type: 'asset/resource', + generator: { + filename: 'static/media/[name][ext]', + }, + }); + + return webpackConfig; + }, +}; + +module.exports = withBundleAnalyzer(config); diff --git a/apps/example-nextjs/package.json b/apps/example-nextjs/package.json new file mode 100644 index 000000000..274021823 --- /dev/null +++ b/apps/example-nextjs/package.json @@ -0,0 +1,43 @@ +{ + "name": "example-nextjs", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "next", + "build": "", + "build:next": "next build", + "build:analyze": "ANALYZE_BUNDLE=1 next build", + "build:disable-minification": "DISABLE_MINIFICATION=1 next build", + "start": "next start", + "e2e": "start-server-and-test http://localhost:3000 \"cypress open --e2e\"", + "e2e:headless": "start-server-and-test http://localhost:3000 \"cypress run --e2e\"", + "lint": "eslint --fix components pages", + "lint:check": "eslint --max-warnings=0 components pages", + "format": "prettier --write components pages", + "format:check": "prettier --check components pages" + }, + "dependencies": { + "common-app": "workspace:*", + "expo": "54.0.13", + "next": "15.5.4", + "react": "19.1.1", + "react-dom": "19.1.1", + "react-native-track-player": "workspace:*", + "react-native-web": "0.21.1", + "webpack": "5.102.1" + }, + "devDependencies": { + "@babel/core": "7.28.4", + "@expo/next-adapter": "6.0.0", + "@next/bundle-analyzer": "15.5.4", + "cypress": "15.4.0", + "eslint": "9.37.0", + "next-compose-plugins": "2.2.1", + "prettier": "3.6.2", + "start-server-and-test": "2.1.2", + "typescript": "5.8.3" + }, + "installConfig": { + "selfReferences": false + } +} diff --git a/apps/example-nextjs/pages/_app.js b/apps/example-nextjs/pages/_app.js new file mode 100644 index 000000000..950f5a968 --- /dev/null +++ b/apps/example-nextjs/pages/_app.js @@ -0,0 +1,13 @@ +import Head from 'next/head'; + +export default function App({ Component, pageProps }) { + return ( + <> + + RNTP - Next.js Example + + + + + ); +} diff --git a/apps/example-nextjs/pages/_document.js b/apps/example-nextjs/pages/_document.js new file mode 100644 index 000000000..6b9f6517e --- /dev/null +++ b/apps/example-nextjs/pages/_document.js @@ -0,0 +1,62 @@ +/* eslint-disable react-native/no-inline-styles */ +import { Children } from 'react'; +import Document, { Html, Head, Main, NextScript } from 'next/document'; +import { AppRegistry } from 'react-native'; + +// Follows the setup for react-native-web: +// https://necolas.github.io/react-native-web/docs/setup/#root-element +// Plus additional React Native scroll and text parity styles for various +// browsers. +// Force Next-generated DOM elements to fill their parent's height +const style = ` +html, body, #__next { + -webkit-overflow-scrolling: touch; +} +#__next { + display: flex; + flex-direction: column; + height: 100%; +} +html { + scroll-behavior: smooth; + -webkit-text-size-adjust: 100%; +} +body { + /* Allows you to scroll below the viewport; default value is visible */ + overflow-y: auto; + overscroll-behavior-y: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -ms-overflow-style: scrollbar; +} +`; + +export default class MyDocument extends Document { + static async getInitialProps({ renderPage }) { + AppRegistry.registerComponent('main', () => Main); + // @ts-expect-error + const { getStyleElement } = AppRegistry.getApplication('main'); + const page = await renderPage(); + const styles = [ +