# os-webview builds the OpenStax site into dev or dist, and its tests need the dev build first

> A TypeScript front end with a five step release runbook, three separate linters, and one environment variable that decides which CMS instance it talks to. Two details will bite you: the documented tag format no longer matches the tags being published, and the unit tests silently need the development output to exist.

**openstax/os-webview** — :books: Front-end web application for the OpenStax web site

- Repository: https://github.com/openstax/os-webview
- Stars: 29 · Forks: 5
- Language: TypeScript
- License: not declared
- Published: 2026-08-27 · Updated: 2026-08-27 · Language: en
- Canonical page: https://hysenlabs.com/projects/openstax-os-webview

## Node comes from a version manager, and install applies patches afterwards

The only stated requirement is a Node version manager, and the repository root carries a file that pins the version to use. Getting the source in is three commands: clone over SSH, change into the directory, and run the setup script from the script directory. That last command is the one worth understanding rather than memorising. The package manifest declares a post-install hook that runs a patch application tool, and the tree contains a patches directory to match, so the install step rewrites something inside the dependency tree after it is fetched. The same script pulls in the Mac specific dependencies listed in a Brewfile, which is why the documentation opens by assuming Homebrew is already present. Skipping the script and running a bare install gives you a tree that has not been patched, and the failure will not necessarily point at the missing step.

```
git clone git@github.com:openstax/os-webview.git
cd os-webview
script/setup
```

## The dev server serves from a dev directory, and the tests depend on it existing

Running the site locally takes a sourced bootstrap step followed by a dev script, which starts BrowserSync and opens the result in your default browser. What it produces is a directory named dev, and that directory is the thing served. The intended edit loop is short: you change files in the src directory, webpack watches that directory, compiles and transpiles what changed, and writes the result back into dev. The dependency worth knowing about is between building and testing. The test documentation states plainly that the unit tests require the development build to have been built in the dev directory first, so running the tests on a fresh clone without that step gives you failures that look like broken tests and are actually missing fixtures.

```
. script/bootstrap
script/dev
```

## Three linters run separately, and one of them emits nothing at all

The test entry point is two commands: one builds, one runs the suite. Underneath, the suite is jest with coverage enabled, pointed at a single test directory, and the coverage report is a static page you open from a coverage directory in your browser. The linting is where the structure gets interesting, because it is split into three named scripts rather than one. One runs the JavaScript linter over the source directory. One runs the stylesheet linter against every SCSS file in that same directory. The third is a type check that passes a skip-library-check flag and a no-emit flag, so it validates TypeScript without writing any output. A combined script chains all three in sequence, which means a stylesheet failure can look like a JavaScript failure if you only read the exit code.

```
script/build
script/test
```

## Production output lands in dist, and HTTP/2 is the only advice given

The production build is the build script with a single production argument. What you get is a dist directory, and the deployment responsibility is yours: you must configure a web server to host those files. The documentation is unusually light on requirements here, stating that no special configuration is needed, and then making one recommendation, which is to serve the site over HTTP/2. That is the entire production story, so if your hosting setup needs more than static files in a directory, the answers are not in this repository. Two related conveniences sit alongside it. A separate script profiles the webpack build and writes the result to a JSON file that is checked into the repository root, and a second script opens that file in a bundle analyzer, so bundle growth can be inspected without rebuilding.

```
./script/build production
```

## One environment variable decides which CMS instance answers

Configuration is a single variable. The API origin environment variable names which content management instance the front end talks to, and the readme points at the CMS project so you know what is on the other end of that call. Settings are not read from a local file at all: they are fetched from the named instance's webview settings API, which means the behaviour of a build changes with the value of one string and nothing else. The development script has a default, and it points at the development host rather than production. That default is what makes a fresh setup safe, and it is also the thing to override when you want to exercise a different content set. Because settings arrive over the network at runtime, a build is not fully self-contained, which matters when you copy a dist directory somewhere isolated.

## The runbook's tag format no longer matches the tags being published

The release documentation is thorough, and in one respect it has drifted. It describes a six step process on a new branch: bump the version, update dependencies, commit, tag, push, and publish a GitHub release. Every command in it uses a three-part numeric version with a leading letter, and the documented tag format is explicitly that shape. The tags actually being published do not look like that. The three most recent are dated forms with a year, a month and a sequence number, and the package manifest currently carries a different three-part number again. So the runbook is a reliable description of the steps and an unreliable description of the naming. Before cutting a release from this branch, match whatever the previous release used rather than copying the example commands verbatim.

## A release commit touches exactly two files

The versioning rule is unusually narrow and worth internalising before your first release. The manifest version field is the only file that has to change for versioning, and the convention is to increment the middle number, with the last number reserved for hotfixes. Dependencies are refreshed in the same pass with a single upgrade command, which updates the lock file to the latest versions the declared ranges allow. The commit that follows therefore adds exactly two paths: the manifest and the lock file. Nothing in the source tree is touched by the release itself, which is what makes the tag a clean snapshot of a dependency refresh rather than a code change. If your upgrade produced source edits as well, that is a fix that belongs in its own commit before the release commit, not inside it.

```
yarn upgrade
```

```
git add package.json yarn.lock
git commit -m "Release v2.148.0"
git push origin release-v2.148.0
```

## React is an alias for Preact's compatibility build

The dependency list contains one entry that looks like a mistake and is not. React itself is declared as an alias pointing at Preact's compatibility package, so imports resolve to a different implementation while keeping the React API surface. That single line is the reason you will not find a React release tag in the lock file, and it is worth knowing before you start reading bundle output or searching for component behaviour in the React repository. Two other entries shape how the app is wired. A page renderer is pulled straight from a git ref rather than a registry version, so upgrading it can move without any change on this side. Error reporting goes through a Sentry client, which is why the bundle statistics and analyzer scripts exist: the payload of a dependency-driven front end is easiest to judge by looking at it.

## Conclusion

Use this repository if you are changing the OpenStax web application, since it is the site front end and not a general purpose component. Set up your environment through the setup script rather than by hand, because the install step also applies patches that the project relies on, and build the development output before you run the test suite or you will be debugging an empty result. Before cutting a release, follow the actual published tag format rather than the one in the runbook, and keep the release as a pre-release until the deploy to production has happened, which is what the project asks for.

## FAQ

### What is WebView used for?

Not the Android system component. In this repository os-webview is the OpenStax web site front end, a TypeScript application built with webpack and served during development from a dev directory by BrowserSync, with content and settings fetched at runtime from a CMS instance named by an environment variable.

### What is Android system WebView and do I need it on my phone?

The repository says nothing about phones or the Android rendering engine. What it requires on a development machine is a Node version manager, a clone of this repository, and the setup script, which installs dependencies and applies patches afterwards.

### Can I disable Android system WebView on my phone?

Nothing in this repository addresses that setting. The closest documented behaviour is browser side: the production build produces a directory of static files that you host yourself, with HTTP/2 recommended and no other server configuration required.

## Sources

- [Official README](https://github.com/openstax/os-webview#readme)
- [Project repository](https://github.com/openstax/os-webview)
- [Release notes](https://github.com/openstax/os-webview/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/openstax-os-webview
