diff --git a/.bazelrc b/.bazelrc index 489c91631..6494342dc 100644 --- a/.bazelrc +++ b/.bazelrc @@ -27,6 +27,8 @@ common --experimental_google_legacy_api build --noincremental_dexing --fat_apk_cpu=armeabi-v7a,arm64-v8a,x86,x86_64 mobile-install --start=warm +# Cache Config for Build: the cache occassionally becomes corrupted. Comment out this block to disable caching. +# Then build (wait for success), uncomment the block, and build again. This should fix the issue. build --bes_results_url=https://app.buildbuddy.io/invocation/ build --bes_backend=grpcs://remote.buildbuddy.io build --remote_cache=grpcs://remote.buildbuddy.io diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 61a7b8f14..171813418 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,105 +1,18 @@ -# How to Contribute +# Contributing to Player -If you find something interesting you want contribute to the repo, feel free to raise a PR, or open an issue for features you'd like to see added. +Thank you for your interest in contributing to Player! -[For first time contributors](./newCONTRIBUTORS.md) +## πŸ“– Documentation -## Proposing a Change +**Complete contributing documentation lives on our documentation site: πŸ‘‰ [Contributing Guide](https://github.intuit.com/pages/player/docs/latest/contributing/)** -For small bug-fixes, documentation updates, or other trivial changes, feel free to jump straight to submitting a pull request. +## Quick Links -If the changes are larger (API design, architecture, etc), [opening an issue](https://github.com/player-ui/player/issues/new/choose) can be helpful to reduce implementation churn as we hash out the design. - -## Requirements - -- [bazelisk](https://github.com/bazelbuild/bazelisk) -- [pnpm >= 9.0.0](https://pnpm.io/installation) - -- [Swift >= 5.5](https://www.swift.org/download/) -- [Xcode 15.3](https://developer.apple.com/download/all/) - -- [Android NDK 27.1.12297006](https://github.com/android/ndk/releases/tag/r27b). You'll need to add `ANDROID_NDK_HOME` to your environment manually. It will look like `export ANDROID_NDK_HOME=/Users/{USERNAME}/Library/Android/sdk/ndk/27.1.12297006` -- Python < 3 (recommended 2.7.18) - you can use [pyenv](https://realpython.com/intro-to-pyenv/) to manage different python versions with ease. - -- [Signed Commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification). For convenience it is recommended to set git to sign all commits by default as mentioned [here](https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key) - -## Building and Testing Locally (All platforms) - -> This project also contains [just](https://github.com/casey/just) recipes for many common commands. They can be listed using `just -l` - -### Player - -For speed and consistency, this repo leverages `bazel` as its main build tool. Check out the [bazel](https://bazel.build/) docs for more info. - -After forking the repo, run builds using bazel to test, build and run: - -## Docs Sites - -These require the [Android NDK](https://developer.android.com/ndk). -The docs site can be run locally using: - -```bash -bazel run //docs/site:dev -``` - -which will run an instance on `http://localhost:4321`. - -When a PR is merged, any `docs/site` changes will be deployed to the `next` folder in [https://github.com/player-ui/player-ui.github.io](https://github.com/player-ui/player-ui.github.io), which stores the built files for the site. - -The OSS site is deployed with the following route logic: - -- The `next` route correlates to the doc site generated by the latest build of Player. - Every PR merged into the main branch (unless opted out) will generate a next build so that functionality can be immediately consumed. -- The `latest` route correlates to the doc site generated from the last non-next release of Player. - These are releases that are we intentionally choose to cut and have a non-tagged semvar version. -- The `0` route contains the docs for the last `0.x.x` release. - For every major release, we preserve the doc site for the last version released for it to allow folks who can't upgrade immediately to still have access to docs that are relevant for them. - -## For Android Only Builds - -If you are interested in only contributing for android, follow our [android guide](https://github.com/player-ui/player/blob/main/android/demo/README.md) - -## For iOS Only Builds - -### Xcode Project Generation - -Generate the `.xcodeproj` to open and work in Xcode. Builds and tests will be executed through bazel, to ensure behavioral parity. - -```bash -bazel run //ios:xcodeproj -open -a Xcode ios/PlayerUI.xcodeproj/ -``` - -### Demo Application - -#### Xcode - -The first time the Xcode project is generated, the default selected target is `PlayerUI`, for a runnable target select `PlayerUIDemo` to run the demo application in the simulator. - -#### Bazel - -The demo app can also be built and launched in a simulator from the command line with bazel: - -```bash -bazel run //ios/demo:PlayerUIDemo -``` - -## Submitting a Pull Request - -Prior to submitting a pull request, ensure that your fork and branch are up to date with the lastest changes on `main`. - -Any new features should have corresponding tests that exercise all code paths, and public symbols should have docstrings at a minimum. For more complex features, adding new documentation pages to the site to help guide users to consume the feature would be preferred. - -When you're ready, submit a new pull request to the `main` branch and the team will be notified of the new requested changes. We'll do our best to respond as soon as we can. - -## Releases - -When a PR is merged, it will generate a `next` release, so something like `0.12.0-next.0` which can then be used in your project. This is done so that you can consume the latest changes without having to wait for a release to be cut. - -### Canary Releases - -To trigger a canary release, collaborators can add a `/canary` comment to any PR. Note: Canary builds can only be requested by collaborators. +- πŸ› [Report a Bug](https://github.com/player-ui/player/issues/new?assignees=&labels=bug&template=bug_report.md&title=) +- πŸ’‘ [Request a Feature](https://github.com/player-ui/player/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=) +- πŸ”§ [Troubleshooting Guide](https://github.intuit.com/pages/player/docs/latest/contributing/troubleshooting/) +- πŸ’¬ [Join Discussions](https://github.com/player-ui/player/discussions) --- -Inspired by react's [How to Contribute](https://reactjs.org/docs/how-to-contribute.html) +*For the most up-to-date and comprehensive contributing information, please visit our [documentation site](https://github.intuit.com/pages/player/docs/latest/contributing/).* \ No newline at end of file diff --git a/DEV_GUIDE.md b/DEV_GUIDE.md deleted file mode 100644 index 5f08efb0f..000000000 --- a/DEV_GUIDE.md +++ /dev/null @@ -1,158 +0,0 @@ -# PlayerUI Typescript Development Guide - -### Sections: -1. [Setup](#Setup) -2. [Adding a new plugin](#adding-a-new-plugin) -3. [Dependencies](#Dependencies) - -## Setup -### Demo Application -The demo app can be built and launched from the command line with bazel: -```bash -bazel build //docs/site:site -bazel run //docs/site:site -``` - -## Adding a new plugin -Adding a new plugin is simple using predefined macros for `BUILD.bazel` files. - -### Core vs React Plugins -Core plugins provide shared functionality, usable on all platforms i.e. as Player Core runs on every platform, any core Player plugin will also run on every platform which allows for shared functionality to be authored once and shared across every platform. - -React plugins add react specific functionality. - -### Scaffold -All plugins follow a common structure: - -The basic structure is as follows: -```bash -plugins/example -β”œβ”€β”€ react -β”‚Β Β  β”œβ”€β”€ BUILD.bazel -β”‚Β Β  β”œβ”€β”€ src -β”‚Β Β  β”‚Β Β  β”œβ”€β”€ index.tsx -β”‚ β”‚ └── __tests__ -β”‚ β”‚ └── index.test.tsx -β”‚Β Β  └── package.json -└── core - β”œβ”€β”€ BUILD.bazel - β”œβ”€β”€ src - β”‚Β Β  β”œβ”€β”€ index.ts - β”‚ └── __tests__ - β”‚ └── index.test.ts - └── package.json -``` - -To scaffold your plugin, create a new `core` or `react` folder in the appropriate plugin directory, with the appropriate folders, a package.json and a blank `BUILD.bazel`: - -For core plugins: -```bash -mkdir -p plugins/example-plugin/core/src -cd plugins/example-plugin/core -pnpm init -touch BUILD.bazel -``` - -For react plugins: -```bash -mkdir -p plugins/example-plugin/react/src -cd plugins/example-plugin/react -pnpm init -touch BUILD.bazel -``` - -Set the name, version, and entry point of the package in the `package.json`: - -For core plugins: -```javascript -{ - "name": "@player-ui/example-plugin-core", - "version": "0.0.0-PLACEHOLDER", - "main": "src/index.ts", -} -``` - -For react plugins: -```javascript -{ - "name": "@player-ui/example-plugin-react", - "version": "0.0.0-PLACEHOLDER", - "main": "src/index.tsx", -} -``` - -> [!NOTE] -> The package follows a naming convemtion of `@player-ui/{description}-plugin-{platform}`. - -### BUILD -The `js_pipeline` macro will handle the full build: - -```python -load("@rules_player//javascript:defs.bzl", "js_pipeline") - -js_pipeline(package_name = "@player-ui/example-plugin-core") -``` - -In order to use the `tsup` bundler, add `tsup_config` to the `BUILD.bazel` file. This is done by loading the `tsup_config` helper from the `tools` package and calling it within `BUILD.bazel`: - -```python -load("//tools:defs.bzl", "tsup_config") - -tsup_config(name = "tsup_config") -``` - -All plugins leverage `vitest` for testing. To use `vitest`, add `vitest_config` to the `BUILD.bazel` file. This is done by loading the `vitest_config` helper from the `tools` package and calling it within `BUILD.bazel`: - -```python -load("//tools:defs.bzl", "...", "vitest_config") - -vitest_config(name = "vitest_config") -``` - -## Dependencies -Since each package can have different external dependencies, they each need to have their own node_modules. `pnpm` supports a single lock file for multiple packages by setting up a `pnpm-workspace.yaml`. The resulting lock file can be used by `rules_js` to set up a Bazel workspace with multiple packages that each get their own `node_modules` folder in the bin tree. The `npm_link_all_packages` rule will automatically set up the correct node_modules folder based on the Bazel package name and the `pnpm-lock.yaml`. Add the following to your `BUILD.bazel` file. - -```python -load("@npm//:defs.bzl", "npm_link_all_packages") - -npm_link_all_packages(name = "node_modules") -``` - -`js_pipeline` takes `deps`, `test_deps`, and `peer_deps` to allow specifying dependencies: - -```python -js_pipeline( - package_name = "@player-ui/example-plugin-core", - peer_deps = [ - "//:node_modules/react", - ], - deps = [ - ":node_modules/@player-ui/react-subscribe", - ], - test_deps = [ - ":node_modules/@player-ui/common-types-plugin", - ], -) -``` - -> [!NOTE] -> External dependencies are specified as such `//:node_modules/...` with the leading `//`, while internal dependencies are specified as such `:node_modules/...` without the leading `//`. - -Internal dependencies also need to be added to the `package.json` either as a dependency, dev dependency, or peer dependency: - -```javascript -{ - ... - "dependencies": { - "@player-ui/react-subscribe": "workspace:*", - }, - "devDependencies": { - "@player-ui/common-types-plugin": "workspace:*", - } - ... -} -``` - -Add the new package's `node_modules` directory to `.bazelignore`: - -`plugins/example-plugin/core/node_modules` diff --git a/android/demo/README.md b/android/demo/README.md deleted file mode 100644 index b0a190ae4..000000000 --- a/android/demo/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# Android Demo App - -# Local Development with Android Studio - -This will be a getting started guide on contributing to Player on Android. - -It's been tested on Andriod Studio Chipmunk(2021.2.1) and Android Studio Giraffe(2022.3.1). Although other versions may work as well. - -Assuming you have read the [requirements on the root contributing guide](https://github.com/player-ui/player/blob/main/CONTRIBUTING.md). - -1. Once you have Android Studio installed, you will need to go to tools->SDK Manager->SDK Platforms. - 1. Make sure you have **only** the following SDK installed: Android API 33. -2. The next step will be to make sure you have the right (and _only_ the right) SDK Build tools and NDK. Click on the SDK Tools tab and make sure you have only the following clicked: - 1. 30.0.3 - 2. 27.1.12297006 -3. You will now need to create an android device for emulation. Click on Device Manager and do create new device. - 1. You will need to download an Sv2. - 2. You should now be able to click the play button to start up your device. -4. You should now be able to run `bazel build //android/demo` -5. The following are different ways to run the apk on your device. If the following methods do not work, we can manually drop the APK that gets generated from the build command to the emulated android device. - -``` -bazel run //android:demo -``` - -``` -bazel run //android/demo:install -``` - -If those command do not run, you can find the apk in `bazelbin/android/demo/install.runfiles/player/android/demo/demo.apk` and drag this apk onto the emulated device. This will install it. ( you may need to swipe on the device to see the application) - - - -## Troubleshooting Guide - - - -### 1. If you are seeing issues around Toolchain and sdk -Check your SDK and NDK versions in SDK Manager in Android Studio. As well as your `ANDROID_HOME` and `ANDROID_NDK_HOME` in your bash or zsh profiles to make sure they are properly set. - - -### 2. If you are seeing Errors around babel: -``` -could not find dependency @babel/helper-string-parser of @babel.plugin-transform-react-jsx/noode_modules/@babel/types -Error: Analysis of target '//android/demo:demo' failed; build aborted. -``` -Make sure you have done a `bundle install` - - - -### 3. Error Message : -``` - ResourceProcessorBusyBox failed: error executing command bazel-out/darwin-opt-exec-2B5CBBC6/bin/external/bazel_tools/src/tools/android/java/com/google/devtools/build/android/ResourceProcessorBusyBox --tool LINK_STATIC_LIBRARY -- --aapt2 ... (remaining 17 arguments skipped) -``` -**Possible Solution:** Check your SDK and NDK versions in SDK Manager in Android Studio. As well as your `ANDROID_HOME` and `ANDROID_NDK_HOME` in your bash or zsh profiles to make sure they are properly set. - -You can also do `ls $ANDROID_HOME/platforms` and make sure that there are no versions higher than 30. - -### 3. Error Message : -``` -ModuleNotFoundError: No module named 'six.moves' -... -from six.moves import range # pylint: disable=redefined-builtin -^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``` -**Possible Solution:** Check your `python --version` is less than 3 (recommended 2.7.18). If it is and you are still getting the error try running you bazel commands with the flag `--incompatible_use_python_toolchains=false` - diff --git a/docs/site/astro.config.mjs b/docs/site/astro.config.mjs index 260ee2181..250e22313 100644 --- a/docs/site/astro.config.mjs +++ b/docs/site/astro.config.mjs @@ -116,6 +116,15 @@ export default defineConfig({ }, ], }, + { + label: "Contributing", + items: [ + { + label: "Contributing", + autogenerate: { directory: "contributing" }, + }, + ], + }, { label: "Plugins", items: [ diff --git a/docs/site/src/components/Sidebar.astro b/docs/site/src/components/Sidebar.astro index 1cbf92ada..33f9b9665 100644 --- a/docs/site/src/components/Sidebar.astro +++ b/docs/site/src/components/Sidebar.astro @@ -11,7 +11,7 @@ type SidebarEntry = (typeof sidebar)[number]; /** Get the icon for a group. Update the icon names in the array to change the icons associated with a group. */ const getIcon = (index: number) => - (["seti:video", "puzzle", "setting"] as const)[index]; + (["seti:video", "pencil", "puzzle", "setting"] as const)[index]; function getFirstEntry(entry: SidebarEntry) { if (entry.type === "group") { diff --git a/docs/site/src/content/docs/contributing/android.mdx b/docs/site/src/content/docs/contributing/android.mdx new file mode 100644 index 000000000..bc230c73e --- /dev/null +++ b/docs/site/src/content/docs/contributing/android.mdx @@ -0,0 +1,66 @@ +--- +title: Android Development Guide +description: Complete guide for Android development with Player +--- + +This guide covers everything you need to know for contributing to Player on Android, from initial setup to troubleshooting common issues. + +## Local Development with Android Studio + +This setup has been tested on Android Studio Chipmunk (2021.2.1) and Android Studio Giraffe (2022.3.1), though other versions may work as well. + +### Prerequisites + +Make sure you have read the [main contributing requirements](/contributing/#requirements) first. + +### Setup Steps + +1. **Install Required SDKs** + - Once you have Android Studio installed, go to **Tools β†’ SDK Manager β†’ SDK Platforms** + - Make sure you have **only** the following SDK installed: **Android API 33** + +2. **Configure SDK Build Tools and NDK** + - Click on the **SDK Tools** tab + - Make sure you have only the following versions installed: + - **30.0.3** (SDK Build Tools) + - **27.1.12297006** (NDK) + +3. **Create Android Emulator** + - Click on **Device Manager** and create a new device + - You will need to download an **Sv2** system image + - You should now be able to click the play button to start your emulator + +4. **Build the Project** + ```bash + bazel build //android/demo + ``` + +5. **Run the Demo App** + + You have several options to install and run the APK on your device: + + **Option 1: Direct run (recommended)** + ```bash + bazel run //android:demo + ``` + + **Option 2: Install command** + ```bash + bazel run //android/demo:install + ``` + + **Option 3: Manual installation** + If the above commands don't work, you can manually install the APK: + 1. Find the APK at: `bazel-bin/android/demo/install.runfiles/player/android/demo/demo.apk` + 2. Drag this APK file onto your emulated Android device + 3. This will install the app (you may need to swipe on the device to see the application) + +## Troubleshooting + +If you encounter issues during setup or development, check the [Troubleshooting Guide](/contributing/troubleshooting) for solutions to common Android development problems. + +## Development Tips + +- The Android emulator needs to be running before executing bazel run commands + +For general contributing guidelines, see the [main contributing guide](/contributing/). diff --git a/docs/site/src/content/docs/contributing/core-web.mdx b/docs/site/src/content/docs/contributing/core-web.mdx new file mode 100644 index 000000000..c76f15817 --- /dev/null +++ b/docs/site/src/content/docs/contributing/core-web.mdx @@ -0,0 +1,203 @@ +--- +title: Core & Web Development Guide +description: Complete guide for Core and Web development with Player +--- + +import { Aside, Steps, Card, CardGrid, FileTree, Tabs, TabItem } from '@astrojs/starlight/components'; + +This guide covers everything you need to know for developing Player plugins and core functionality using TypeScript and JavaScript. + +## Quick Start + +### Demo Application + +The demo app can be built and launched from the command line with Bazel: + +```bash +bazel build //docs/site:site +bazel run //docs/site:site +``` + +## Plugin Development + +Adding a new plugin is straightforward using predefined macros for `BUILD.bazel` files. + +### Core vs React Plugins + +- **Core plugins** provide shared functionality usable on all platforms. Since Player Core runs on every platform, any core Player plugin will also run on every platform, allowing shared functionality to be authored once and used everywhere. + +- **React plugins** add React-specific functionality and components. + +### Plugin Structure + +All plugins follow a common structure: + + +- plugins/example + - react/ + - BUILD.bazel + - src/ + - index.tsx + - __tests__/ + - index.test.tsx + - package.json + - core/ + - BUILD.bazel + - src/ + - index.ts + - __tests__/ + - index.test.ts + - package.json + + +### Scaffolding a New Plugin + +To scaffold your plugin, create a new `core` or `react` folder in the appropriate plugin directory, with the appropriate folders, a `package.json`, and a blank `BUILD.bazel`: + + + + ```bash + mkdir -p plugins/example-plugin/core/src + cd plugins/example-plugin/core + pnpm init + touch BUILD.bazel + ``` + + + ```bash + mkdir -p plugins/example-plugin/react/src + cd plugins/example-plugin/react + pnpm init + touch BUILD.bazel + ``` + + + +### Package Configuration + +Set the name, version, and entry point of the package in the `package.json`: + + + + ```json + { + "name": "@player-ui/example-plugin-core", + "version": "0.0.0-PLACEHOLDER", + "main": "src/index.ts" + } + ``` + + + ```json + { + "name": "@player-ui/example-plugin-react", + "version": "0.0.0-PLACEHOLDER", + "main": "src/index.tsx" + } + ``` + + + + + +### BUILD Configuration + +The `js_pipeline` macro handles the full build process: + +```python +load("@rules_player//javascript:defs.bzl", "js_pipeline") + +js_pipeline(package_name = "@player-ui/example-plugin-core") +``` + +#### Adding Bundling Support + +To use the `tsup` bundler, add `tsup_config` to the `BUILD.bazel` file: + +```python +load("//tools:defs.bzl", "tsup_config") + +tsup_config(name = "tsup_config") +``` + +#### Adding Testing Support + +All plugins leverage `vitest` for testing. To use `vitest`, add `vitest_config` to the `BUILD.bazel` file: + +```python +load("//tools:defs.bzl", "vitest_config") + +vitest_config(name = "vitest_config") +``` + +## Dependency Management + +Since each package can have different external dependencies, they each need their own `node_modules`. `pnpm` supports a single lock file for multiple packages by setting up a `pnpm-workspace.yaml`. The resulting lock file can be used by `rules_js` to set up a Bazel workspace with multiple packages that each get their own `node_modules` folder in the bin tree. + +### Setting Up Node Modules + +The `npm_link_all_packages` rule automatically sets up the correct `node_modules` folder based on the Bazel package name and the `pnpm-lock.yaml`. Add the following to your `BUILD.bazel` file: + +```python +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages(name = "node_modules") +``` + +### Specifying Dependencies + +`js_pipeline` takes `deps`, `test_deps`, and `peer_deps` to allow specifying dependencies: + +```python +js_pipeline( + package_name = "@player-ui/example-plugin-core", + peer_deps = [ + "//:node_modules/react", + ], + deps = [ + ":node_modules/@player-ui/react-subscribe", + ], + test_deps = [ + ":node_modules/@player-ui/common-types-plugin", + ], +) +``` + + + +### Package.json Dependencies + +Internal dependencies also need to be added to the `package.json` as a dependency, dev dependency, or peer dependency: + +```json +{ + ... + "dependencies": { + "@player-ui/react-subscribe": "workspace:*", + }, + "devDependencies": { + "@player-ui/common-types-plugin": "workspace:*", + } + ... +} +``` + +### Bazel Ignore Configuration + +Add the new package's `node_modules` directory to `.bazelignore`: + +``` +plugins/example-plugin/core/node_modules +plugins/example-plugin/react/node_modules +``` diff --git a/docs/site/src/content/docs/contributing/index.mdx b/docs/site/src/content/docs/contributing/index.mdx new file mode 100644 index 000000000..f47c2297e --- /dev/null +++ b/docs/site/src/content/docs/contributing/index.mdx @@ -0,0 +1,108 @@ +--- +title: Contributing to Player +description: Complete guide for contributing to the Player project +--- + +import { Aside, Card, CardGrid, LinkCard } from '@astrojs/starlight/components'; + +If you find something interesting you want contribute to the repo, feel free to raise a PR, or open an issue for features you'd like to see added. + + + +## Proposing a Change + +For small bug-fixes, documentation updates, or other trivial changes, feel free to jump straight to submitting a pull request. + +If the changes are larger (API design, architecture, etc), [opening an issue](https://github.com/player-ui/player/issues/new/choose) can be helpful to reduce implementation churn as we hash out the design. + +## Requirements + +- [bazelisk](https://github.com/bazelbuild/bazelisk) +- [pnpm >= 9.0.0](https://pnpm.io/installation) + +- [Swift >= 5.5](https://www.swift.org/download/) +- [Xcode 15.3](https://developer.apple.com/download/all/) + +- [Android NDK 27.1.12297006](https://github.com/android/ndk/releases/tag/r27b). You'll need to add `ANDROID_NDK_HOME` to your environment manually. It will look like `export ANDROID_NDK_HOME=/Users/{USERNAME}/Library/Android/sdk/ndk/27.1.12297006` +- Python < 3 (recommended 2.7.18) - you can use [pyenv](https://realpython.com/intro-to-pyenv/) to manage different python versions with ease. + +- [Signed Commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification). For convenience it is recommended to set git to sign all commits by default as mentioned [here](https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key) + +## Building and Testing Locally (All platforms) + + + +### Player + +For speed and consistency, this repo leverages `bazel` as its main build tool. Check out the [bazel](https://bazel.build/) docs for more info. + +After forking the repo, run builds using bazel to test, build and run: + +## Docs Sites + +These require the [Android NDK](https://developer.android.com/ndk). +The docs site can be run locally using: + +```bash +bazel run //docs/site:dev +``` + +which will run an instance on `http://localhost:4321`. + +When a PR is merged, any `docs/site` changes will be deployed to the `next` folder in [https://github.com/player-ui/player-ui.github.io](https://github.com/player-ui/player-ui.github.io), which stores the built files for the site. + +The OSS site is deployed with the following route logic: + +- The `next` route correlates to the doc site generated by the latest build of Player. + Every PR merged into the main branch (unless opted out) will generate a next build so that functionality can be immediately consumed. +- The `latest` route correlates to the doc site generated from the last non-next release of Player. + These are releases that are we intentionally choose to cut and have a non-tagged semvar version. +- The `0` route contains the docs for the last `0.x.x` release. + For every major release, we preserve the doc site for the last version released for it to allow folks who can't upgrade immediately to still have access to docs that are relevant for them. + +## Platform-Specific Development + + + + Plugin development and core functionality using TypeScript and JavaScript. + + + + Complete Android development setup with troubleshooting guides. + + + + iOS development, Xcode setup, and plugin creation. + + + + Solutions to common problems across all platforms. + + + + +## Submitting a Pull Request + +Prior to submitting a pull request, ensure that your fork and branch are up to date with the lastest changes on `main`. + +Any new features should have corresponding tests that exercise all code paths, and public symbols should have docstrings at a minimum. For more complex features, adding new documentation pages to the site to help guide users to consume the feature would be preferred. + +When you're ready, submit a new pull request to the `main` branch and the team will be notified of the new requested changes. We'll do our best to respond as soon as we can. + +## Releases + +When a PR is merged, it will generate a `next` release, so something like `0.12.0-next.0` which can then be used in your project. This is done so that you can consume the latest changes without having to wait for a release to be cut. + +### Canary Releases + +To trigger a canary release, collaborators can add a `/canary` comment to any PR. Note: Canary builds can only be requested by collaborators. + +--- + +Inspired by react's [How to Contribute](https://reactjs.org/docs/how-to-contribute.html) diff --git a/docs/site/src/content/docs/contributing/ios.mdx b/docs/site/src/content/docs/contributing/ios.mdx new file mode 100644 index 000000000..c4a31fa39 --- /dev/null +++ b/docs/site/src/content/docs/contributing/ios.mdx @@ -0,0 +1,353 @@ +--- +title: iOS Development Guide +description: Complete guide for iOS development with Player +--- + +import { Aside, FileTree } from '@astrojs/starlight/components'; + +This comprehensive guide covers everything you need to know for iOS development with Player, from basic setup to advanced plugin development. + +## Quick Start + +### Xcode Project Generation + +Generate the `.xcodeproj` to open and work in Xcode. Builds and tests will be executed through bazel to ensure behavioral parity. + +```bash +bazel run //ios:xcodeproj +open -a Xcode ios/PlayerUI.xcodeproj/ +``` + +### Demo Application + +#### Running in Xcode +The first time the Xcode project is generated, the default selected target is `PlayerUI`. For a runnable target, select `PlayerUIDemo` to run the demo application in the simulator. + +#### Running with Bazel +The demo app can also be built and launched in a simulator from the command line: + +```bash +bazel run //ios/demo:PlayerUIDemo +``` + +## Important Build Notes + + + +**Best Practice:** Build individual targets through those that depend on the underlying targets using `swift_library`. In practice, this primarily means building through test targets or the example application. + +**Example:** You can't build `PlayerUIInternalTestUtilities` directly, but you can build `//ios/core:PlayerUITests` which builds `PlayerUIInternalTestUtilities` through it being a test dependency. + +**Note:** It's perfectly fine to use `/...` when [querying targets](#examining-targets) because querying just lists targets without building anything. + +## Plugin Development + +Adding new plugins is straightforward using predefined macros for `BUILD.bazel` files. Additional steps are required to include new code in final artifacts and the Xcode project. + +### iOS vs SwiftUI Plugins + +- **iOS plugins** provide generic functionality to any Player implementation on iOS. Generally these plugins load core JavaScript plugin functionality into Swift and provide Swift APIs. + +- **SwiftUI plugins** are targeted at the specific `SwiftUIPlayer` implementation and typically link Player functionality into the SwiftUI environment. + +### Plugin Structure + +All iOS plugins follow a common structure: + + +- plugins/example + - ios/ + - BUILD.bazel + - Sources/ + - ExamplePlugin.swift + - Tests/ + - ExamplePluginTests.swift + - swiftui/ + - BUILD.bazel + - Sources/ + - ExamplePlugin.swift + - ViewInspector/ + - ExamplePluginViewInspectorTests.swift + + +### Scaffolding a New Plugin + +**For iOS plugins:** +```bash +mkdir -p plugins/example/ios/Sources +mkdir -p plugins/example/ios/Tests +touch plugins/example/ios/BUILD.bazel +``` + +**For SwiftUI plugins:** +```bash +mkdir -p plugins/example/swiftui/Sources +mkdir -p plugins/example/swiftui/ViewInspector +touch plugins/example/swiftui/BUILD.bazel +``` + +### BUILD Configuration + +#### iOS Plugin BUILD.bazel +```python +load("//tools/ios:util.bzl", "ios_plugin") + +ios_plugin(name = "ExamplePlugin") +``` + +#### SwiftUI Plugin BUILD.bazel +```python +load("//tools/ios:util.bzl", "swiftui_plugin") + +swiftui_plugin( + name = "ExamplePlugin", + resources = [], + deps = [ + "//ios/swiftui:PlayerUISwiftUI" + ] +) +``` + +#### Adding Dependencies + +Both `ios_plugin` and `swiftui_plugin` accept `deps` and `test_deps`: + +```python +swiftui_plugin( + name = "ExamplePlugin", + resources = [], + deps = [ + "//ios/swiftui:PlayerUISwiftUI" + ], + test_deps = [ + "//plugins/reference-assets/swiftui:PlayerUIReferenceAssets", + ] +) +``` + +#### JavaScript Resources + +Many iOS plugins are built on top of core JavaScript plugin functionality. Include JS resources easily: + +```python +ios_plugin( + name = "ExamplePlugin", + resources = ["//plugins/example/core:core_native_bundle"] +) + +swiftui_plugin( + name = "ExamplePlugin", + resources = ["//plugins/example/core:core_native_bundle"] +) +``` + +This creates a resource bundle with the provided name and necessary runtime files for accessing `Bundle.module` from bazel. These resource bundles and extensions are only ever created at runtime by bazel - they can be viewed in Xcode, but the project needs to be built first to generate the files. + + + +#### Examining Targets + +List all targets exposed from any `BUILD.bazel` file: + +```bash +bazel query //plugins/example/ios/... +``` + +The `name` passed into `ios_plugin` or `swiftui_plugin` is prefixed with `PlayerUI` by default: + +```python +ios_plugin(name = "ExamplePlugin") # Creates "PlayerUIExamplePlugin" +``` + +### Xcode Integration + +Add new plugins to be visible and testable in Xcode by adding the test target to `ios/BUILD.bazel`: + +```python +xcodeproj( + name = "xcodeproj", + project_name = "PlayerUI", + tags = ["manual"], + top_level_targets = [ + ..., + "//plugins/example/ios:PlayerUIExamplePluginTests", + # or for swiftui + "//plugins/example/swiftui:PlayerUIExamplePluginViewInspectorTests", + ], +) +``` + +After adding the target, regenerate the Xcode project: +```bash +bazel run //ios:xcodeproj +``` + +### Package Manager Integration + +#### Package.swift + +Add new plugins to the appropriate array in `Package.swift`: + +```swift +let ios_plugins: [SwiftPlugin] = [ + ..., + (name: "ExamplePlugin", path: "example", resources: true) +] +``` + +**For utility packages** that don't fit the plugin pattern: +```swift +products: [ + ..., + .playerPackage("PlayerUIUtilityPackage") +] +``` + +#### PlayerUI.podspec + +In `PlayerUI.podspec`, subspecs are listed in a single location, and there are `ios_plugin` and `swiftui_plugin` functions to generate the subspec entries: + +```ruby +# Plugin Name, Path, Resources +ios_plugin.call("ExamplePlugin", "example", FALSE) +# Plugin Name, Path, Dependencies, Resources +swiftui_plugin.call("ExamplePlugin", "example", ["OtherPlugin"], FALSE) +``` + +##### Adding Utility Packages + +For packages that do not fit the plugin pattern, subspecs must be manually specified to set the appropriate file paths for Sources and Resources. + +### Final Artifacts + +Add new plugins to the root `BUILD.bazel` for code artifacts: + +```python +assemble_pod( + name = "PlayerUI_Pod", + srcs = glob([ + "LICENSE", + "Package.swift", + ]), + data = { + ..., + "//plugins/example/ios:PlayerUIExamplePlugin_Sources": "plugins/example/ios/", + "//plugins/example/core:core_native_bundle": "plugins/example/ios/Resources/" + }, + podspec = ":PlayerUI.podspec", +) +``` + +## Advanced Usage + +### External Dependencies + + + +#### Bazel Configuration + +Bazel resolution of external Swift dependencies is done with [rules_swift_package_manager](https://github.com/cgrindel/rules_swift_package_manager). + +1. **Add dependencies to Package.swift files:** + - Add to both the main `Package.swift` (for final consumer users) and to `xcode/Package.swift` (for workspace use) + + + +2. **Regenerate the dependency index:** + ```bash + bazel run //:swift_update_pkgs + ``` + +3. **Update `MODULE.bazel` to expose the package:** + ```python + use_repo( + swift_deps, + "swiftpkg_swift_hooks", + ..., + "swiftpkg_" + ) + ``` + + + +4. **Use the dependency in bazel targets:** + ``` + @swiftpkg_//:Sources_ + ``` + +### Custom Bazel Macros + +For complex use cases, use `ios_pipeline` directly instead of `ios_plugin` or `swiftui_plugin`: + +```python +load("@rules_player//ios:defs.bzl", "ios_pipeline") + +ios_pipeline( + name = "PlayerUITestUtilitiesCore", + resources = ["//core/make-flow:make-flow_native_bundle"], + deps = [ + "//ios/core:PlayerUI", + "//ios/swiftui:PlayerUISwiftUI", + "//ios/logger:PlayerUILogger" + ], + test_deps = [ + "//plugins/reference-assets/swiftui:PlayerUIReferenceAssets", + "//ios/internal-test-utils:PlayerUIInternalTestUtilities" + ], + hasUnitTests = True, + hasViewInspectorTests = True +) +``` + +### Custom Bazel Macros - Advanced Details + +Both `ios_plugin` and `swiftui_plugin` call the same `ios_pipeline` macro and hardcode some of the parameters to that pipeline. For more complex use cases, `ios_pipeline` can be used directly to generate tests for packages that have both regular unit tests as well as SwiftUI ViewInspector based tests. + + + +## FAQ + +### How do I debug issues with resource bundles? + +Resource bundles are generated at runtime by Bazel. If you're having issues: + +1. **Build first**: Always build your target with Bazel before trying to access resources in Xcode +2. **Check bundle paths**: Verify that the resource paths in your BUILD files match the actual file locations +3. **Regenerate Xcode project**: After changing resource configurations, regenerate the Xcode project + +### Why can't I build certain targets directly with Bazel? + +Some targets using `swift_library` (like `PlayerUIInternalTestUtilities`) are not buildable directly due to platform requirements. Instead: + +- Build through test targets that depend on them +- Build through the demo application +- Use `bazel query` to explore targets without building them + +## Development Tips + +- Always regenerate the Xcode project after making changes to BUILD files +- Resource bundles are generated at runtime by bazel - build first to see them in Xcode + +## Related Resources + +- [Main Contributing Guide](/contributing/) - General contributing guidelines +- [Troubleshooting Guide](/contributing/troubleshooting/) - Solutions to common iOS development issues diff --git a/docs/site/src/content/docs/contributing/new-contributors.mdx b/docs/site/src/content/docs/contributing/new-contributors.mdx new file mode 100644 index 000000000..e25b769e2 --- /dev/null +++ b/docs/site/src/content/docs/contributing/new-contributors.mdx @@ -0,0 +1,196 @@ +--- +title: New Contributors Guide +description: Welcome guide for first-time contributors to Player +--- + +import { Aside, Card, CardGrid, Badge, FileTree, Steps } from '@astrojs/starlight/components'; + +# Welcome, New Contributors! + +Thank you for your interest in contributing to Player! This guide will help you get started with your first contribution. + +## Getting Started + + + +1. **Fork the Repository** + + The git workflow for forking is slightly different than the normal branch workflow. Rather than cloning the main repo and pushing a new branch, each person works off of their own fork and pushes their own branches there. This helps limit the need (especially for non-team members) to give out access rights to the repo to push up a branch, and also helps keep the main repo clean from stale branches. + + The easiest way to maintain your own fork is via the GitHub CLI, which you can easily install through Homebrew. After you've gone through the initial setup, the CLI gives us a few powerful commands that do most of the legwork for us when working with a fork. + +2. **Clone and Set Up Fork** + + Start by cloning the repo you'd like to contribute to: + + ```bash + git clone https://github.com/player-ui/player.git + cd player + ``` + + From there, leverage the GitHub CLI to create and set up your fork: + + ```bash + gh repo fork + ``` + + This command creates the fork for us from the repo we've cloned, sets up a new remote to publish to, and renames the previous remote so we can easily reference it: + + ```bash + $ git remote -v + origin https://github.com/YOUR_USERNAME/player.git (fetch) + origin https://github.com/YOUR_USERNAME/player.git (push) + upstream https://github.com/player-ui/player.git (fetch) + upstream https://github.com/player-ui/player.git (push) + ``` + +3. **Set Up Development Environment** + + Follow the [requirements setup](/contributing/#requirements) and install the necessary tools and dependencies. + +4. **Choose Your Platform** + + + + TypeScript/JavaScript plugin development + + + Native Android development + + + Native iOS development + + + +5. **Need Help?** + + Check the [Troubleshooting Guide](/contributing/troubleshooting) for common issues and solutions. + + + +## Keeping Your Fork Updated + +To keep your fork in sync with the main repository, you can leverage the upstream remote that was created when you set up your fork: + +```bash +# Make sure we're on main branch first +git checkout main +git pull upstream main +git push origin main +``` + +This allows you to quickly take everything that the main repo has on main and push it back up to your fork. You should do this anytime you want to contribute to ensure you don't have a stale branch with outdated files. + +> **Alternative Method**: You can also create forks and PRs through [GitHub's web interface](https://github.com/player-ui/player) if you prefer not to use the CLI. + + +## Making Your First Contribution + +### Good First Issues + +Look for issues labeled with: +- - Perfect for newcomers +- - Community contributions welcome +- - Great for getting familiar with the codebase + +### Example Development Workflow + + + +1. **Create a Branch** + + ```bash + git checkout -b feature/your-feature-name + ``` + +2. **Make Your Changes** + + - Write your code + - Add or update tests + - Update documentation if needed + +3. **Test Your Changes** + + ```bash + # Run relevant tests + bazel test //path/to/your:tests + + # For broader testing + bazel test //... + ``` + +4. **Commit Your Changes** + + ```bash + git add . + git commit -S -m "feat: add your feature description" + ``` + + + +5. **Push and Create Pull Request** + + ```bash + git push origin feature/your-feature-name + ``` + + When you're ready to submit a Pull Request, there's a great CLI command for that too: + + ```bash + gh pr create + ``` + + This will guide you through writing your PR and creating it for the repo. You can also quickly monitor the status of the CI checks with: + + ```bash + gh pr checks + ``` + + This will show all checks that have run on your PR and if they have passed or failed, and additionally add any links to quickly jump to the checks to debug. + + + +## Getting Help + +### Community Resources + +- **[GitHub Issues](https://github.com/player-ui/player/issues)**: Ask questions or report problems +- **[GitHub Discussions](https://github.com/player-ui/player/discussions)**: General questions and community chat +- **Pull Request Reviews**: Get feedback on your code + +### Code Review Process + +1. Automated checks will run on your PR (tests, linting, builds) +2. A maintainer will review your code +3. Address any feedback from reviewers +4. Once approved, your PR will be merged! + +## Understanding the Codebase + +### Project Structure + + +- player/ + - android/ # Android-specific code + - ios/ # iOS-specific code + - core/ # Core Player functionality + - plugins/ # Plugin implementations + - docs/ # Documentation site + - tools/ # Build tools and utilities + + +### Key Technologies + +- **Bazel**: Build system used across all platforms +- **TypeScript/JavaScript**: Core Player logic +- **Swift**: iOS implementation +- **Kotlin**: Android implementation +- **React**: Web implementation + +Welcome to the Player community! We're excited to see what you'll build. πŸŽ‰ + +For more detailed information, check out the [main contributing guide](/contributing/). diff --git a/docs/site/src/content/docs/contributing/troubleshooting.mdx b/docs/site/src/content/docs/contributing/troubleshooting.mdx new file mode 100644 index 000000000..28285145a --- /dev/null +++ b/docs/site/src/content/docs/contributing/troubleshooting.mdx @@ -0,0 +1,77 @@ +--- +title: Troubleshooting Guide +description: Common issues and solutions for Player development +--- + +import { Card, CardGrid, Aside } from '@astrojs/starlight/components'; + +This guide covers documented issues that developers have encountered when contributing to Player and their solutions. + + + +## Web & Core Development Issues + + + +## Android Development Issues + + +## iOS Development Issues + +### 1. iOS Builds Fail + +#### **Symptoms** +The iOS build fails due to a `tsup` error even though the core files definitely exist. You may see an error like this: +``` +/Users/---/dev/GitHub/player/core/types/BUILD:11:16: tsup core/types/dist/index.mjs failed: (Exit 1): types_tsup_build_tsup_bin failed: error executing tsup command (from target //core/types:types_tsup_build) +``` + +#### **Solution / Workaround** +The most likely cause is a rare cache corruption. +1. Go to `.bazelrc` and comment out the β€œCache Config for Build” block. +1. Run the command you were trying again. Wait for it to succeed. +1. Uncomment the cache block. +1. Run the command again. It should work properly now. + + +### 2. ViewInspector Test Crashes + +**Symptoms:** +- New ViewInspector tests crash when running +- Test failures with threading-related errors + +**Solution:** +ViewInspector requires the tests to be running on the main thread in a few different cases. To fix this, add `@MainActor` to the test class: + +```swift +@MainActor +class MyPluginViewInspectorTests: XCTestCase { + // Your ViewInspector tests here +} +``` + +### 3. Swift Compiler Metadata Errors + +**Symptoms:** +``` +Unable to parse compiler-emitted metadata at `file:///path/to/Wrappers.swiftconstvalues`: The file "Wrappers.swiftconstvalues" couldn't be opened because there is no such file. +``` + +**Solution:** +This occurs when Xcode tries to compile Swift files directly instead of using Bazel's pre-built outputs. + +1. **Regenerate the Xcode project:** + ```bash + bazel clean + bazel run //ios:xcodeproj + ``` + +2. **Use the correct scheme:** Ensure you're using the "PlayerUIDemo" scheme in Xcode (not individual library schemes) + +3. **Clean Xcode build folder:** In Xcode, go to Product β†’ Clean Build Folder \ No newline at end of file diff --git a/ios/README.md b/ios/README.md deleted file mode 100644 index 33c589493..000000000 --- a/ios/README.md +++ /dev/null @@ -1,313 +0,0 @@ -# PlayerUI iOS Development Guide - -### Sections: -1. [Setup](#Setup) -2. [Adding a new plugin](#adding-a-new-plugin) -3. [Advance Usage](#advanced-Usage) - * [External dependencies](#external-dependencies) - * [Bazel Macros](#bazel-macros) - -## Setup -### Xcode Project generation -Generate the `.xcodeproj` to open and work in Xcode. Builds and tests will be executed through bazel, to ensure behavioral parity. - -```bash -bazel run //ios:xcodeproj -open -a Xcode ios/PlayerUI.xcodeproj/ -``` -### Demo Application -#### Xcode -The first time the Xcode project is generated, the default selected target is `PlayerUI`, for a runnable target select `PlayerUIDemo` to run the demo application in the simulator. - -#### Bazel -The demo app can also be built and launched in a simulator from the command line with bazel: -```bash -bazel run //ios/demo:PlayerUIDemo -``` - - -> [!NOTE] -> When building/testing targets with Bazel it is not recommended to build all targets under a package using `/...` as some targets such as those using `swift_library` for example `PlayerUIInternalTestUtilities` and `PlayerUIReferenceAssets` are not buildable due to running on MacOS, or requiring iOS SDKs. - -It is recommended to build the individual targets through those that depend on the underlying targets using `swift_library`. In practice, this primarily means build through test targets, or building the example application. - -For example, you can't build `PlayerUIInternalTestUtilities` but you can build `//ios/core:PlayerUITests` which builds `PlayerUIInternalTestUtilities` through it being a test dependency. - -It is not an issue to use `/...` when [querying](#Examining-Targets) all targets under a package because querying just lists targets and nothing is being built. - -## Adding a new plugin -Adding a new plugin is simple using predefined macros for `BUILD.bazel` files. Additional steps are required to include new code in the final artifacts, and in the Xcode project. - -### iOS vs SwiftUI Plugins -iOS plugins provide generic functionality to any Player implementation on iOS. Generally these plugins are used to load core JavaScript plugin functionality into Swift, and to provide swift APIs for those plugins. - -SwiftUI plugins are more targetted at the specific `SwiftUIPlayer` implementation, and typically are needed to link up Player functionality into the SwiftUI environment. - -### Scaffold -All iOS plugins follow a common structure, with SwiftUI plugins defining a different test folder. - -The basic structure is as follows: -```bash -plugins/example -β”œβ”€β”€ ios -β”‚Β Β  β”œβ”€β”€ BUILD.bazel -β”‚Β Β  β”œβ”€β”€ Sources -β”‚Β Β  β”‚Β Β  └── ExamplePlugin.swift -β”‚Β Β  └── Tests -β”‚Β Β  └── ExamplePluginTests.swift -└── swiftui - β”œβ”€β”€ BUILD.bazel - β”œβ”€β”€ Sources - β”‚Β Β  └── ExamplePlugin.swift - └── ViewInspector - └── ExamplePluginViewInspectorTests.swift -``` - -To scaffold your plugin, create a new `ios` or `swiftui` folder in the appropriate plugin directory, with the appropriate folders, and a blank `BUILD.bazel` - -```bash -mkdir -p plugins/example/ios/Sources -mkdir -p plugins/example/ios/Tests -touch plugins/example/ios/BUILD.bazel -``` - -or for SwiftUI plugins: -```bash -mkdir -p plugins/example/swiftui/Sources -mkdir -p plugins/example/swiftui/ViewInspector -touch plugins/example/swiftui/BUILD.bazel -``` - -### BUILD -#### iOS Plugin -For plugins that are not specifically for SwiftUI, the `ios_plugin` macro will handle the full build: -```python -load("//tools/ios:util.bzl", "ios_plugin") - -ios_plugin(name = "ExamplePlugin") -``` - -#### SwiftUI Plugin -For plugins that are SwiftUI specific, the `swiftui_plugin` macro will handle the full build: -```python -load("//tools/ios:util.bzl", "swiftui_plugin") - -swiftui_plugin( - name = "ExamplePlugin", - resources = [], - deps = [ - "//ios/swiftui:PlayerUISwiftUI" - ] -) -``` - -#### Dependencies -Both `ios_plugin` and `swiftui_plugin` take `deps` and `test_deps`, to allow specifying dependencies on other swift targets. - -```python -swiftui_plugin( - name = "ExamplePlugin", - resources = [], - deps = [ - "//ios/swiftui:PlayerUISwiftUI" - ], - test_deps = [ - "//plugins/reference-assets/swiftui:PlayerUIReferenceAssets", - ] -) -``` - -For external dependencies, see [External Dependencies](#external-dependencies). - -#### JavaScript Resources -As PlayerUI is a cross platform project, that aims for code reuse, many plugins for iOS are built on top of core plugin functionality. These JS resources can be easily included in either the `ios_plugin` or `swiftui_plugin` macros: - -```python -ios_plugin( - name = "ExamplePlugin", - resources = ["//plugins/example/core:core_native_bundle"] -) - -swiftui_plugin( - name = "ExamplePlugin", - resources = ["//plugins/example/core:core_native_bundle"] - deps = [ - "//ios/swiftui:PlayerUISwiftUI" - ] -) -``` - -This will create a resource bundle with the provided name, as well as any necessary runtime files for accessing `Bundle.module` from bazel. These resource bundles and extensions are only ever created at runtime by bazel, they can be viewed in Xcode, but the project needs to be built first to generate the files. - -#### Examining Targets -Macros can produce multiple bazel targets, the targets exposed from any give `BUILD.bazel` file can be listed: -```bash -$ bazel query //plugins/example/ios/... -``` - -The `name` passed into `ios_plugin` or `swiftui_plugin` is prefixed with `PlayerUI` by default: - -```python -ios_plugin(name = "ExamplePlugin") -``` - -For iOS plugins the `js_pipeline` for the core plugin should have `native_bundle` set to `ExamplePlugin` to match the `name` in the ios_plugin - -```python -js_pipeline( - native_bundle = "ExamplePlugin" - ... -) -``` - - -Will produce a `swift_library` target called `PlayerUIExamplePlugin`. - -### Xcode -To add new plugins to be visible + testable in Xcode, the test target needs to be added to `ios/BUILD.bazel` as a top level target: - -```python - -xcodeproj( - name = "xcodeproj", - project_name = "PlayerUI", - tags = ["manual"], - top_level_targets = [ - ..., - "//plugins/example/ios:PlayerUIExamplePluginTests", - # or for swiftui - "//plugins/example/swiftui:PlayerUIExamplePluginViewInspectorTests", - ], -) - -``` - -After adding the new target to `xcodeproj`, rerun `bazel run //ios:xcodeproj` to regenerate the `PlayerUI.xcodeproj`. - -### Package Manifests -When adding a new plugin, the steps to add it to bazel and Xcode allow us to do local development and testing, but do not expose the plugin in the SPM module, or the CocoaPod. We will need to update `Package.swift` and `PlayerUI.podspec` to expose the new plugins to those package managers. - -#### Package.swift - -In `Package.swift` there are two arrays of plugin entries, one for `ios_plugin` equivalents, and one for `swiftui_plugin` equivalents. Add the new plugin to the appropriate array, the `name` and all dependencies listed will be prefixed with `PlayerUI` to simplify this file. - -```swift -let ios_plugins: [SwiftPlugin] = [ - ..., - (name: "ExamplePlugin", path: "example", resources: true) -] -``` - -##### Adding utility packages - -For packages that do not fit the plugin pattern, targets must be manually specified, and products can use the `.playerPackage` extension to expose the product from the Package. - -```swift -products: [ - ..., - .playerPackage("PlayerUIUtilityPackage") -``` - -#### PlayerUI.podspec - -In `PlayerUI.podspec` subspecs are listed in a single location, and there are `ios_plugin` and `swiftui_plugin` functions to generate the subspec entries. - -```ruby -# Plugin Name, Path, Resources -ios_plugin.call("ExamplePlugin", "example", FALSE) -# Plugin Name, Path, Dependencies, Resources -swiftui_plugin.call("ExamplePlugin", "example", ["OtherPlugin"] FALSE) -``` - -##### Adding Utility Packages -For packages that do not fit the plugin pattern, subspecs must be manually specified to set the appropriate file paths for Sources and Resources. - -### Artifacts - -To add new plugins to final code artifacts, the sources and resources must be added to the root `BUILD.bazel`. For both CocoaPods and SPM, files are expected to match the locations in the respective `PlayerUI.podspec` or `Package.swift`, and as such we need to map resources to the intended locations in the final archive. - -```python -assemble_pod( - name = "PlayerUI_Pod", - srcs = glob([ - "LICENSE", - "Package.swift", - ]), - data = { - ..., - "//plugins/example/ios:PlayerUIExamplePlugin_Sources": "plugins/example/ios/", - "//plugins/example/core:core_native_bundle": "plugins/example/ios/Resources/" - }, - podspec = ":PlayerUI.podspec", -) -``` - -## Advanced Usage - -### External Dependencies - -Adding external dependencies for packages is simple, but requires some manual changes to bazel files. - -> [!NOTE] -> As `PlayerUI` is published as a Swift Package and a CocoaPod, external dependencies must be available on both package managers. - -#### Bazel -Bazel resolution of external swift dependencies is done with [rules_swift_package_manager](https://github.com/cgrindel/rules_swift_package_manager). - -Add new dependencies for plugins to both the main `Package.swift` for final consumer user, and to `xcode/Package.swift` for workspace use. - -> [!TIP] -> With `Package.swift` manifest files, dependencies for consuming users are resolved regardless of whether or not the consuming user relies the product with that dependency. Due to this, test packages, and developer tooling can conflict with consuming users. To avoid this potential conflict, project level dependencies are redeclared in `xcode/Package.swift`. This allows the main `Package.swift` to contain dependencies only for the library targets, and no testing or tooling dependencies. - -After adding the dependency, a bazel command is used to regenerate the dependency index: -```bash -bazel run //:swift_update_pkgs -``` - -After updating the index, `MODULE.bazel` needs to be updated to expose that package in the `use_repo` call: -```python -use_repo( - swift_deps, - "swiftpkg_swift_hooks", - ..., - "swiftpkg_" -) -``` - -Package names are converted to snake case, if you are unsure what name to use, open `swift_deps.bzl` and search for the git repository for that dependency to find its entry and name. - -Once the `MODULE.bazel` entry is updated, the dependency is available to bazel targets: -``` -@swiftpkg_//:Sources_ -``` - -#### SPM / CocoaPods - -Adding external dependencies to package manifests follows the normal convention for those package managers. If you are deviating from the plugin pattern to add an external dependency, you will need to specify the targets manually. - -### Bazel Macros -Both `ios_plugin` and `swiftui_plugin` call the same `ios_pipeline` macro, and hardcode some of the parameters to that pipeline. For more complex usecases, `ios_pipeline` can be used directly, to generate tests for packages that have both regular unit tests, as well as SwiftUI ViewInspector based tests. - -Note: the `ios_pipeline` macro is a common macro loaded from rules_player repo, it requires a few peer dependencies that must be added in this main repo in order to work with the `ios_pipeline` including SwiftLint and ViewInspector (SPM dependencies) and build_bazel_rules_apple and build_bazel_rules_ios (Rule dependencies) - -Example: - -```python -load("@rules_player//ios:defs.bzl", "ios_pipeline") - -ios_pipeline( - name = "PlayerUITestUtilitiesCore", - resources = ["//core/make-flow:make-flow_native_bundle"], - deps = [ - "//ios/core:PlayerUI", - "//ios/swiftui:PlayerUISwiftUI", - "//ios/logger:PlayerUILogger" - ], - test_deps = [ - "//plugins/reference-assets/swiftui:PlayerUIReferenceAssets", - "//ios/internal-test-utils:PlayerUIInternalTestUtilities" - ], - hasUnitTests = True, - hasViewInspectorTests = True -) -```