Repository: remix-run/remix
Pull request #3918 (2022-08-03 21:17:22)

feat(remix-react): unblock hydration via async module scripts
<!--

👋 Hey, thanks for your interest in contributing to Remix!

If this is a simple docs change, go ahead and delete all this.

**Please ask first before starting work on any significant new features.**

It's never a fun experience to have your pull request declined after investing a
lot of time and effort into a new feature. To avoid this from happening, we
request that contributors create a
[Feature Request discussion](https://github.com/remix-run/remix/discussions/new?category=ideas)
to first discuss any significant new features.

https://github.com/remix-run/remix/blob/main/CONTRIBUTING.md

Please fill in or delete each item below:

-->

Closes: #

- [ ] Docs
- [ ] Tests

Testing Strategy:

<!--
Please explain how you tested this. For example:

> This test covers this code: <link to test>

Or

> I opened up my windows machine and ran this script:
>
> ```
> npx create-remix@0.0.0-experimental-7e420ee3 --template remix my-test
> cd my-test
> npm run dev
> ```
-->



Patch:
diff --git a/.changeset/afraid-peaches-accept.md b/.changeset/afraid-peaches-accept.md
deleted file mode 100644
index 8774b45b8..000000000
--- a/.changeset/afraid-peaches-accept.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"@remix-run/dev": patch
----
-
-Add support for .mjs and .cjs remix.config files.
diff --git a/.changeset/curvy-drinks-flash.md b/.changeset/curvy-drinks-flash.md
deleted file mode 100644
index 24b78d03b..000000000
--- a/.changeset/curvy-drinks-flash.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"@remix-run/react": patch
----
-
-Previously, if an `action` was omitted from `<Form>` or `useFormAction`, the action value would default to `"."`. This is incorrect, as `"."` should resolve based on the current _path_, but an empty action resolves relative to the current _URL_ (including the search and hash values). We've fixed this to differentiate between the two.
diff --git a/.changeset/four-ladybugs-wait.md b/.changeset/four-ladybugs-wait.md
deleted file mode 100644
index 1e20b75c8..000000000
--- a/.changeset/four-ladybugs-wait.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"@remix-run/dev": patch
----
-
-Allow importing `.sql` files as text
diff --git a/.changeset/great-pumas-act.md b/.changeset/great-pumas-act.md
deleted file mode 100644
index dbc214cca..000000000
--- a/.changeset/great-pumas-act.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-"@remix-run/netlify": minor
-"@remix-run/server-runtime": minor
----
-
-Type safety for load context.
-
-Change `AppLoadContext` to be an interface mapping `string` to `unknown`, allowing users to extend it via:
-
-```ts
-declare module "@remix-run/server-runtime" {
-  interface AppLoadContext {
-    // add custom properties here!
-  }
-}
-```
diff --git a/.changeset/nasty-cars-care.md b/.changeset/nasty-cars-care.md
deleted file mode 100644
index d89994d6c..000000000
--- a/.changeset/nasty-cars-care.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"@remix-run/react": patch
----
-
-React 18 gets more strict with types, this adds a runtime cast to a string for the `<title>` tag value.
diff --git a/.changeset/purple-ligers-drive.md b/.changeset/purple-ligers-drive.md
deleted file mode 100644
index 51ac8ce48..000000000
--- a/.changeset/purple-ligers-drive.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"@remix-run/dev": patch
----
-
-Make MDX builds deterministic
diff --git a/.changeset/slow-apples-pretend.md b/.changeset/slow-apples-pretend.md
deleted file mode 100644
index 7547330d3..000000000
--- a/.changeset/slow-apples-pretend.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"@remix-run/react": patch
----
-
-Add subscribe method to transition manager to allow subscribing and un-subscribing for React 18 strict mode compliance.
diff --git a/.changeset/stale-worms-laugh.md b/.changeset/stale-worms-laugh.md
deleted file mode 100644
index a6886f6b1..000000000
--- a/.changeset/stale-worms-laugh.md
+++ /dev/null
@@ -1,8 +0,0 @@
----
-"remix": patch
-"@remix-run/dev": patch
----
-
-`import()` expects url-encoded strings, so the path must be properly escaped and (especially on Windows) absolute paths must pe prefixed with the `file://` protocol
-
-dynamic import does not currently work inside of vm which jest relies on so we fall back to require for this case
diff --git a/.changeset/wild-meals-beg.md b/.changeset/wild-meals-beg.md
new file mode 100644
index 000000000..241e4aad9
--- /dev/null
+++ b/.changeset/wild-meals-beg.md
@@ -0,0 +1,5 @@
+---
+"@remix-run/react": patch
+---
+
+Unblock hydration via use of async module scripts.
diff --git a/.github/workflows/postrelease.yml b/.github/workflows/postrelease.yml
index d0b00b442..d95399b8a 100644
--- a/.github/workflows/postrelease.yml
+++ b/.github/workflows/postrelease.yml
@@ -1,4 +1,4 @@
-name: 🕊 Release
+name: 🕊 Post-release
 
 on:
   push:
diff --git a/.github/workflows/release-experimental.yml b/.github/workflows/release-experimental.yml
index 63d048f41..354909afa 100644
--- a/.github/workflows/release-experimental.yml
+++ b/.github/workflows/release-experimental.yml
@@ -22,7 +22,7 @@
 # - Create a new release for the tag on GitHub to trigger the CI workflow that
 #   will publish the release to npm
 
-name: 🧪 Release (experimental)
+name: 🚀 Release (experimental)
 on:
   push:
     tags:
diff --git a/contributors.yml b/contributors.yml
index 4c75b792f..08d205c14 100644
--- a/contributors.yml
+++ b/contributors.yml
@@ -33,6 +33,7 @@
 - archwebio
 - arganaphangquestian
 - AriGunawan
+- arnaudambro
 - arvigeus
 - arvindell
 - ascorbic
@@ -188,6 +189,7 @@
 - jo-ninja
 - joaosamouco
 - jodygeraldo
+- joelazar
 - johannesbraeunig
 - johnpolacek
 - johnson444
@@ -267,6 +269,7 @@
 - matthova
 - mattmazzola
 - mattstobbs
+- maxprilutskiy
 - mbarto
 - mcansh
 - medayz
@@ -315,6 +318,7 @@
 - pcattori
 - penspinner
 - penx
+- philandstuff
 - phishy
 - plastic041
 - plondon
@@ -400,6 +404,7 @@
 - vmosyaykin
 - vorcigernix
 - weavdale
+- willin
 - wKovacs64
 - wladiston
 - XiNiHa
diff --git a/docs/api/remix.md b/docs/api/remix.md
index 85460607c..b8039756f 100644
--- a/docs/api/remix.md
+++ b/docs/api/remix.md
@@ -752,7 +752,7 @@ It is common for Remix newcomers to see this hook and think it is the primary wa
 - [`useActionData`][useactiondata]
 - [`useTransition`][usetransition]
 
-If you're building a highly interactive, "app like" user interface, you will `useFetcher` often.
+If you're building a highly interactive, "app like" user interface, you will use `useFetcher` often.
 
 ```tsx
 import { useFetcher } from "@remix-run/react";
diff --git a/docs/pages/contributing.md b/docs/pages/contributing.md
index a25614839..66c1fdbc8 100644
--- a/docs/pages/contributing.md
+++ b/docs/pages/contributing.md
@@ -143,6 +143,14 @@ This repo maintains separate branches for different purposes. They will look som
 
 There may be other branches for various features and experimentation, but all of the magic happens from these branches.
 
+## How the heck do nightly releases work?
+
+Nightly releases will run the action files from the `main` branch as scheduled workflows will always use the latest commit to the default branch, signified by [this comment on the nightly action file][nightly-action-comment] and the explicit branch appended to the reuasable workflows in the [postrelease action][postrelease-action], however they checkout the `dev` branch during their set up as that's where we want our nightly releases to be cut from. From there, we check if the git sha is the same and only cut a new nightly if something has changed.
+
+## End to end testing
+
+For every release of Remix (stable, experimental, nightly, and pre-releases), we will do a complete end-to-end test of Remix apps on each of our official adapters from `create-remix`, all the way to deploying them to production. We do this by by utilizing the default [templates][templates] and the CLIs for Fly, Vercel, Netlify, and Arc. We'll then run some simple Cypress assertions to make sure everything is running properly for both development and the deployed app.
+
 [cla]: https://github.com/remix-run/remix/blob/main/CLA.md
 [this-page]: https://github.com/remix-run/remix
 [yarn-version-1]: https://classic.yarnpkg.com/lang/en/docs/install
@@ -150,3 +158,6 @@ There may be other branches for various features and experimentation, but all of
 [pull-request]: https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request
 [yarn-workspaces]: https://classic.yarnpkg.com/en/docs/workspaces
 [vscode-playwright]: https://playwright.dev/docs/intro#using-the-vs-code-extension
+[nightly-action-comment]: https://github.com/remix-run/remix/blob/main/.github/workflows/nightly.yml#L8-L12
+[postrelease-action]: https://github.com/remix-run/remix/blob/main/.github/workflows/postrelease.yml
+[templates]: /templates
diff --git a/docs/tutorials/blog.md b/docs/tutorials/blog.md
index 9de7d64b2..02d72ce4a 100644
--- a/docs/tutorials/blog.md
+++ b/docs/tutorials/blog.md
@@ -897,7 +897,7 @@ export const action = async ({ request }) => {
 
 That's it. Remix (and the browser) will take care of the rest. Click the submit button and watch the sidebar that lists our posts update automatically.
 
-In HTML an input's `name` attribute is sent over the network and available by the same name on the request's `formData`. Oh, and don't forget, the `request` and `formData` objects are both straight out of the web specification. So if you want to learn more about either of them, head over to MDN! [mdn.io/request][mdn-io-request] [mdn.io/request.formData][mdn-io-request-form-data].
+In HTML an input's `name` attribute is sent over the network and available by the same name on the request's `formData`. Oh, and don't forget, the `request` and `formData` objects are both straight out of the web specification. So if you want to learn more about either of them, head over to MDN! [mdn.io/Request][mdn-io-request] [mdn.io/Request.formData][mdn-io-request-form-data].
 
 TypeScript is mad again, let's add some types.
 
@@ -1175,8 +1175,8 @@ We hope you love Remix! 💿 👋
 [the-styling-guide]: /guides/styling
 [prisma]: https://prisma.io
 [http-localhost-3000-posts-admin]: http://localhost:3000/posts/admin
-[mdn-io-request]: https://mdn.io/request
-[mdn-io-request-form-data]: https://mdn.io/request.formData
+[mdn-io-request]: https://mdn.io/Request
+[mdn-io-request-form-data]: https://mdn.io/Request.formData
 [disable-java-script]: https://developer.chrome.com/docs/devtools/javascript/disable
 [the-optimistic-ui-guide]: /guides/optimistic-ui
 [somewhere]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
diff --git a/examples/client-side-validation/README.md b/examples/client-side-validation/README.md
index 1b2d37611..ccc7bd697 100644
--- a/examples/client-side-validation/README.md
+++ b/examples/client-side-validation/README.md
@@ -14,7 +14,7 @@ Open this example on [CodeSandbox](https://codesandbox.com):
 
 This example shows how to use the built-in HTML5 validation features.
 
-Check [app/routes/example.tsx](app/root.tsx) to see the client-side validation in action.
+Check [app/root.tsx](app/root.tsx) to see the client-side validation in action.
 
 ## Related Links
 
diff --git a/packages/create-remix/CHANGELOG.md b/packages/create-remix/CHANGELOG.md
index 5d5edbe20..1929c9977 100644
--- a/packages/create-remix/CHANGELOG.md
+++ b/packages/create-remix/CHANGELOG.md
@@ -1,5 +1,12 @@
 # `create-remix`
 
+## 1.6.8
+
+### Patch Changes
+
+- Updated dependencies:
+  - `@remix-run/dev@1.6.8`
+
 ## 1.6.7
 
 ### Patch Changes
diff --git a/packages/create-remix/package.json b/packages/create-remix/package.json
index d77694e0e..459af74de 100644
--- a/packages/create-remix/package.json
+++ b/packages/create-remix/package.json
@@ -1,6 +1,6 @@
 {
   "name": "create-remix",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "Create a new Remix app",
   "homepage": "https://remix.run",
   "bugs": {
@@ -17,7 +17,7 @@
     "create-remix": "dist/cli.js"
   },
   "dependencies": {
-    "@remix-run/dev": "1.6.7"
+    "@remix-run/dev": "1.6.8"
   },
   "engines": {
     "node": ">=14"
diff --git a/packages/remix-architect/CHANGELOG.md b/packages/remix-architect/CHANGELOG.md
index 7fd8bc615..89ad0b8da 100644
--- a/packages/remix-architect/CHANGELOG.md
+++ b/packages/remix-architect/CHANGELOG.md
@@ -1,5 +1,12 @@
 # `@remix-run/architect`
 
+## 1.6.8
+
+### Patch Changes
+
+- Updated dependencies:
+  - `@remix-run/node@1.6.8`
+
 ## 1.6.7
 
 ### Patch Changes
diff --git a/packages/remix-architect/package.json b/packages/remix-architect/package.json
index 5c6d6f1f5..aa4108e77 100644
--- a/packages/remix-architect/package.json
+++ b/packages/remix-architect/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@remix-run/architect",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "Architect server request handler for Remix",
   "bugs": {
     "url": "https://github.com/remix-run/remix/issues"
@@ -15,7 +15,7 @@
   "typings": "dist/index.d.ts",
   "dependencies": {
     "@architect/functions": "^5.0.2",
-    "@remix-run/node": "1.6.7",
+    "@remix-run/node": "1.6.8",
     "@types/aws-lambda": "^8.10.82"
   },
   "devDependencies": {
diff --git a/packages/remix-cloudflare-pages/CHANGELOG.md b/packages/remix-cloudflare-pages/CHANGELOG.md
index f4bb9d9ed..f0014676e 100644
--- a/packages/remix-cloudflare-pages/CHANGELOG.md
+++ b/packages/remix-cloudflare-pages/CHANGELOG.md
@@ -1,5 +1,12 @@
 # `@remix-run/cloudflare-pages`
 
+## 1.6.8
+
+### Patch Changes
+
+- Updated dependencies:
+  - `@remix-run/cloudflare@1.6.8`
+
 ## 1.6.7
 
 ### Patch Changes
diff --git a/packages/remix-cloudflare-pages/package.json b/packages/remix-cloudflare-pages/package.json
index f2e0651cf..bcc84961c 100644
--- a/packages/remix-cloudflare-pages/package.json
+++ b/packages/remix-cloudflare-pages/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@remix-run/cloudflare-pages",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "Cloudflare Pages request handler for Remix",
   "bugs": {
     "url": "https://github.com/remix-run/remix/issues"
@@ -15,7 +15,7 @@
   "typings": "dist/index.d.ts",
   "module": "dist/esm/index.js",
   "dependencies": {
-    "@remix-run/cloudflare": "1.6.7"
+    "@remix-run/cloudflare": "1.6.8"
   },
   "devDependencies": {
     "@cloudflare/workers-types": "^3.4.0",
diff --git a/packages/remix-cloudflare-workers/CHANGELOG.md b/packages/remix-cloudflare-workers/CHANGELOG.md
index 8e949bbd7..9ee9fc72b 100644
--- a/packages/remix-cloudflare-workers/CHANGELOG.md
+++ b/packages/remix-cloudflare-workers/CHANGELOG.md
@@ -1,5 +1,12 @@
 # `@remix-run/cloudflare-workers`
 
+## 1.6.8
+
+### Patch Changes
+
+- Updated dependencies:
+  - `@remix-run/cloudflare@1.6.8`
+
 ## 1.6.7
 
 ### Patch Changes
diff --git a/packages/remix-cloudflare-workers/package.json b/packages/remix-cloudflare-workers/package.json
index dca6ef713..8bc113a5e 100644
--- a/packages/remix-cloudflare-workers/package.json
+++ b/packages/remix-cloudflare-workers/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@remix-run/cloudflare-workers",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "Cloudflare worker request handler for Remix",
   "bugs": {
     "url": "https://github.com/remix-run/remix/issues"
@@ -16,7 +16,7 @@
   "module": "dist/esm/index.js",
   "dependencies": {
     "@cloudflare/kv-asset-handler": "^0.1.3",
-    "@remix-run/cloudflare": "1.6.7"
+    "@remix-run/cloudflare": "1.6.8"
   },
   "devDependencies": {
     "@cloudflare/workers-types": "^3.4.0"
diff --git a/packages/remix-cloudflare/CHANGELOG.md b/packages/remix-cloudflare/CHANGELOG.md
index e7e260142..1bbcf89fc 100644
--- a/packages/remix-cloudflare/CHANGELOG.md
+++ b/packages/remix-cloudflare/CHANGELOG.md
@@ -1,5 +1,12 @@
 # `@remix-run/cloudflare`
 
+## 1.6.8
+
+### Patch Changes
+
+- Updated dependencies:
+  - `@remix-run/server-runtime@1.6.8`
+
 ## 1.6.7
 
 ### Patch Changes
diff --git a/packages/remix-cloudflare/package.json b/packages/remix-cloudflare/package.json
index 5985fb717..16e4508e8 100644
--- a/packages/remix-cloudflare/package.json
+++ b/packages/remix-cloudflare/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@remix-run/cloudflare",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "Cloudflare platform abstractions for Remix",
   "bugs": {
     "url": "https://github.com/remix-run/remix/issues"
@@ -15,7 +15,7 @@
   "typings": "dist/index.d.ts",
   "dependencies": {
     "@cloudflare/kv-asset-handler": "^0.1.3",
-    "@remix-run/server-runtime": "1.6.7"
+    "@remix-run/server-runtime": "1.6.8"
   },
   "devDependencies": {
     "@cloudflare/workers-types": "^3.4.0"
diff --git a/packages/remix-deno/CHANGELOG.md b/packages/remix-deno/CHANGELOG.md
index 35e019c95..0402d119a 100644
--- a/packages/remix-deno/CHANGELOG.md
+++ b/packages/remix-deno/CHANGELOG.md
@@ -1,5 +1,12 @@
 # `@remix-run/deno`
 
+## 1.6.8
+
+### Patch Changes
+
+- Updated dependencies:
+  - `@remix-run/server-runtime@1.6.8`
+
 ## 1.6.7
 
 ### Patch Changes
diff --git a/packages/remix-deno/package.json b/packages/remix-deno/package.json
index 1f8d04766..4982aebe3 100644
--- a/packages/remix-deno/package.json
+++ b/packages/remix-deno/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@remix-run/deno",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "Deno platform abstractions for Remix",
   "homepage": "https://remix.run",
   "main": "./index.ts",
@@ -15,7 +15,7 @@
   "license": "MIT",
   "sideEffects": false,
   "dependencies": {
-    "@remix-run/server-runtime": "1.6.7",
+    "@remix-run/server-runtime": "1.6.8",
     "mime": "^3.0.0"
   },
   "engines": {
diff --git a/packages/remix-dev/CHANGELOG.md b/packages/remix-dev/CHANGELOG.md
index 65e9adec4..1fff77535 100644
--- a/packages/remix-dev/CHANGELOG.md
+++ b/packages/remix-dev/CHANGELOG.md
@@ -1,5 +1,16 @@
 # `@remix-run/dev`
 
+## 1.6.8
+
+### Patch Changes
+
+- Added support for `.mjs` and `.cjs` file extensions for `remix.config` ([#3675](https://github.com/remix-run/remix/pull/3675))
+- Added support for importing `.sql` files as text content ([#3190](https://github.com/remix-run/remix/pull/3190))
+- Updated the compiler to make MDX builds deterministic (and a little faster!) ([#3966](https://github.com/remix-run/remix/pull/3966))
+- Updated dependencies:
+  - `@remix-run/server-runtime@1.6.8`
+  - `@remix-run/serve@1.6.8`
+
 ## 1.6.7
 
 ### Patch Changes
diff --git a/packages/remix-dev/cli/run.ts b/packages/remix-dev/cli/run.ts
index 868d4071a..130956de7 100644
--- a/packages/remix-dev/cli/run.ts
+++ b/packages/remix-dev/cli/run.ts
@@ -24,6 +24,7 @@ ${colors.logoBlue("R")} ${colors.logoGreen("E")} ${colors.logoYellow(
     $ remix build [${colors.arg("projectDir")}]
     $ remix dev [${colors.arg("projectDir")}]
     $ remix routes [${colors.arg("projectDir")}]
+    $ remix watch [${colors.arg("projectDir")}]
     $ remix setup [${colors.arg("remixPlatform")}]
     $ remix migrate [-m ${colors.arg("migration")}] [${colors.arg(
   "projectDir"
@@ -103,6 +104,14 @@ ${colors.logoBlue("R")} ${colors.logoGreen("E")} ${colors.logoYellow(
     $ remix dev my-app
     $ remix dev --debug
 
+  ${colors.heading("Start your server separately and watch for changes")}:
+
+    # custom server start command, for example:
+    $ remix watch
+
+    # in a separate tab:
+    $ node --inspect --require ./node_modules/dotenv/config --require ./mocks ./build/server.js
+
   ${colors.heading("Show all routes in your app")}:
 
     $ remix routes
diff --git a/packages/remix-dev/package.json b/packages/remix-dev/package.json
index 34e194a1b..77cdb2b71 100644
--- a/packages/remix-dev/package.json
+++ b/packages/remix-dev/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@remix-run/dev",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "Dev tools and CLI for Remix",
   "homepage": "https://remix.run",
   "bugs": {
@@ -24,7 +24,7 @@
     "@babel/preset-typescript": "^7.18.6",
     "@esbuild-plugins/node-modules-polyfill": "^0.1.4",
     "@npmcli/package-json": "^2.0.0",
-    "@remix-run/server-runtime": "1.6.7",
+    "@remix-run/server-runtime": "1.6.8",
     "@yarnpkg/esbuild-plugin-pnp": "3.0.0-rc.11",
     "arg": "^5.0.1",
     "cacache": "^15.0.5",
@@ -59,7 +59,7 @@
     "xdm": "^2.0.0"
   },
   "devDependencies": {
-    "@remix-run/serve": "1.6.7",
+    "@remix-run/serve": "1.6.8",
     "@types/cacache": "^15.0.0",
     "@types/gunzip-maybe": "^1.4.0",
     "@types/inquirer": "^8.2.0",
@@ -77,7 +77,7 @@
     "type-fest": "^2.16.0"
   },
   "peerDependencies": {
-    "@remix-run/serve": "1.6.7"
+    "@remix-run/serve": "1.6.8"
   },
   "peerDependenciesMeta": {
     "@remix-run/serve": {
diff --git a/packages/remix-eslint-config/CHANGELOG.md b/packages/remix-eslint-config/CHANGELOG.md
index 227778422..fc64b7d50 100644
--- a/packages/remix-eslint-config/CHANGELOG.md
+++ b/packages/remix-eslint-config/CHANGELOG.md
@@ -1,5 +1,7 @@
 # `@remix-run/eslint-config`
 
+## 1.6.8
+
 ## 1.6.7
 
 No significant changes to this package were made in this release. [See the releases page on GitHub](https://github.com/remix-run/remix/releases/tag/remix%401.6.7) for an overview of all changes in v1.6.7.
diff --git a/packages/remix-eslint-config/package.json b/packages/remix-eslint-config/package.json
index f05ce1f88..46f8db3d8 100644
--- a/packages/remix-eslint-config/package.json
+++ b/packages/remix-eslint-config/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@remix-run/eslint-config",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "ESLint configuration for Remix projects",
   "bugs": {
     "url": "https://github.com/remix-run/remix/issues"
diff --git a/packages/remix-express/CHANGELOG.md b/packages/remix-express/CHANGELOG.md
index 159679170..a4a03a936 100644
--- a/packages/remix-express/CHANGELOG.md
+++ b/packages/remix-express/CHANGELOG.md
@@ -1,5 +1,12 @@
 # `@remix-run/express`
 
+## 1.6.8
+
+### Patch Changes
+
+- Updated dependencies:
+  - `@remix-run/node@1.6.8`
+
 ## 1.6.7
 
 ### Patch Changes
diff --git a/packages/remix-express/package.json b/packages/remix-express/package.json
index 26949460d..8f1d2cf0e 100644
--- a/packages/remix-express/package.json
+++ b/packages/remix-express/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@remix-run/express",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "Express server request handler for Remix",
   "bugs": {
     "url": "https://github.com/remix-run/remix/issues"
@@ -14,7 +14,7 @@
   "main": "dist/index.js",
   "typings": "dist/index.d.ts",
   "dependencies": {
-    "@remix-run/node": "1.6.7"
+    "@remix-run/node": "1.6.8"
   },
   "devDependencies": {
     "@types/express": "^4.17.9",
diff --git a/packages/remix-netlify/CHANGELOG.md b/packages/remix-netlify/CHANGELOG.md
index e829042a1..62a92b686 100644
--- a/packages/remix-netlify/CHANGELOG.md
+++ b/packages/remix-netlify/CHANGELOG.md
@@ -1,5 +1,22 @@
 # `@remix-run/netlify`
 
+## 1.6.8
+
+### Patch Changes
+
+- We've added type safety for load context. `AppLoadContext` is now an an interface mapping `string` to `unknown`, allowing users to extend it via module augmentation: ([#1876](https://github.com/remix-run/remix/pull/1876))
+
+  ```ts
+  declare module "@remix-run/server-runtime" {
+    interface AppLoadContext {
+      // add custom properties here!
+    }
+  }
+  ```
+
+- Updated dependencies:
+  - `@remix-run/node@1.6.8`
+
 ## 1.6.7
 
 ### Patch Changes
diff --git a/packages/remix-netlify/package.json b/packages/remix-netlify/package.json
index 12735096d..0f13318e7 100644
--- a/packages/remix-netlify/package.json
+++ b/packages/remix-netlify/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@remix-run/netlify",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "Netlify server request handler for Remix",
   "bugs": {
     "url": "https://github.com/remix-run/remix/issues"
@@ -14,7 +14,7 @@
   "main": "dist/index.js",
   "typings": "dist/index.d.ts",
   "dependencies": {
-    "@remix-run/node": "1.6.7"
+    "@remix-run/node": "1.6.8"
   },
   "devDependencies": {
     "@netlify/functions": "^1.0.0"
diff --git a/packages/remix-node/CHANGELOG.md b/packages/remix-node/CHANGELOG.md
index ac7e6b7e7..418eede4b 100644
--- a/packages/remix-node/CHANGELOG.md
+++ b/packages/remix-node/CHANGELOG.md
@@ -1,5 +1,12 @@
 # `@remix-run/node`
 
+## 1.6.8
+
+### Patch Changes
+
+- Updated dependencies:
+  - `@remix-run/server-runtime@1.6.8`
+
 ## 1.6.7
 
 ### Patch Changes
diff --git a/packages/remix-node/package.json b/packages/remix-node/package.json
index 8e5d55f12..37c365e65 100644
--- a/packages/remix-node/package.json
+++ b/packages/remix-node/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@remix-run/node",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "Node.js platform abstractions for Remix",
   "bugs": {
     "url": "https://github.com/remix-run/remix/issues"
@@ -15,7 +15,7 @@
   "typings": "dist/index.d.ts",
   "sideEffects": false,
   "dependencies": {
-    "@remix-run/server-runtime": "1.6.7",
+    "@remix-run/server-runtime": "1.6.8",
     "@remix-run/web-fetch": "^4.1.3",
     "@remix-run/web-file": "^3.0.2",
     "@remix-run/web-stream": "^1.0.3",
diff --git a/packages/remix-react/CHANGELOG.md b/packages/remix-react/CHANGELOG.md
index 24586c7f9..064302c83 100644
--- a/packages/remix-react/CHANGELOG.md
+++ b/packages/remix-react/CHANGELOG.md
@@ -1,5 +1,13 @@
 # `@remix-run/react`
 
+## 1.6.8
+
+### Patch Changes
+
+- Previously, if an `action` was omitted from `<Form>` or `useFormAction`, the action value would default to `"."`. This is incorrect, as `"."` should resolve based on the current _path_, but an empty action resolves relative to the current _URL_ (including the search and hash values). We've fixed this to differentiate between the two, meaning that the resolved action will preserve the full URL. ([#3697](https://github.com/remix-run/remix/pull/3697))
+- Enhanced some types to work more seamlessly with React 18 ([#3917](https://github.com/remix-run/remix/pull/3917))
+- Added a subscribe method to the transition manager, which allows subscribing and unsubscribing for React 18 strict mode compliance ([#3964](https://github.com/remix-run/remix/pull/3964))
+
 ## 1.6.7
 
 ### Patch Changes
diff --git a/packages/remix-react/components.tsx b/packages/remix-react/components.tsx
index 7b89d3d23..4ff6963c0 100644
--- a/packages/remix-react/components.tsx
+++ b/packages/remix-react/components.tsx
@@ -740,15 +740,15 @@ export function Meta() {
           if (isOpenGraphTag) {
             return (
               <meta
+                property={name}
                 content={content as string}
                 key={name + content}
-                property={name}
               />
             );
           }
 
           if (typeof content === "string") {
-            return <meta content={content} name={name} key={name + content} />;
+            return <meta name={name} content={content} key={name + content} />;
           }
 
           return <meta key={name + JSON.stringify(content)} {...content} />;
@@ -807,14 +807,17 @@ export function Scripts(props: ScriptProps) {
     let routeModulesScript = `${matches
       .map(
         (match, index) =>
-          `import * as route${index} from ${JSON.stringify(
+          `import ${JSON.stringify(manifest.url)};
+import * as route${index} from ${JSON.stringify(
             manifest.routes[match.route.id].module
           )};`
       )
       .join("\n")}
 window.__remixRouteModules = {${matches
       .map((match, index) => `${JSON.stringify(match.route.id)}:route${index}`)
-      .join(",")}};`;
+      .join(",")}};
+      
+import(${JSON.stringify(manifest.entry.module)});`;
 
     return (
       <>
@@ -822,14 +825,14 @@ window.__remixRouteModules = {${matches
           {...props}
           suppressHydrationWarning
           dangerouslySetInnerHTML={createHtml(contextScript)}
+          type={undefined}
         />
-        <script {...props} src={manifest.url} />
         <script
           {...props}
           dangerouslySetInnerHTML={createHtml(routeModulesScript)}
           type="module"
+          async
         />
-        <script {...props} src={manifest.entry.module} type="module" />
       </>
     );
     // disabled deps array because we are purposefully only rendering this once
@@ -862,6 +865,11 @@ window.__remixRouteModules = {${matches
 
   return (
     <>
+      <link
+        rel="modulepreload"
+        href={manifest.entry.module}
+        crossOrigin={props.crossOrigin}
+      />
       {dedupe(preloads).map((path) => (
         <link
           key={path}
diff --git a/packages/remix-react/package.json b/packages/remix-react/package.json
index 7a7c23d85..7d8d08d01 100644
--- a/packages/remix-react/package.json
+++ b/packages/remix-react/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@remix-run/react",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "React DOM bindings for Remix",
   "bugs": {
     "url": "https://github.com/remix-run/remix/issues"
diff --git a/packages/remix-serve/CHANGELOG.md b/packages/remix-serve/CHANGELOG.md
index 4b5f4f55f..974e24f55 100644
--- a/packages/remix-serve/CHANGELOG.md
+++ b/packages/remix-serve/CHANGELOG.md
@@ -1,5 +1,12 @@
 # `@remix-run/serve`
 
+## 1.6.8
+
+### Patch Changes
+
+- Updated dependencies:
+  - `@remix-run/express@1.6.8`
+
 ## 1.6.7
 
 ### Patch Changes
diff --git a/packages/remix-serve/package.json b/packages/remix-serve/package.json
index 60d4ffff4..c22763312 100644
--- a/packages/remix-serve/package.json
+++ b/packages/remix-serve/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@remix-run/serve",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "Production application server for Remix",
   "bugs": {
     "url": "https://github.com/remix-run/remix/issues"
@@ -17,7 +17,7 @@
     "remix-serve": "dist/cli.js"
   },
   "dependencies": {
-    "@remix-run/express": "1.6.7",
+    "@remix-run/express": "1.6.8",
     "compression": "^1.7.4",
     "express": "^4.17.1",
     "morgan": "^1.10.0"
diff --git a/packages/remix-server-runtime/CHANGELOG.md b/packages/remix-server-runtime/CHANGELOG.md
index 77178c138..a38b9875b 100644
--- a/packages/remix-server-runtime/CHANGELOG.md
+++ b/packages/remix-server-runtime/CHANGELOG.md
@@ -1,5 +1,19 @@
 # `@remix-run/server-runtime`
 
+## 1.6.8
+
+### Patch Changes
+
+- We've added type safety for load context. `AppLoadContext` is now an an interface mapping `string` to `unknown`, allowing users to extend it via module augmentation: ([#1876](https://github.com/remix-run/remix/pull/1876))
+
+  ```ts
+  declare module "@remix-run/server-runtime" {
+    interface AppLoadContext {
+      // add custom properties here!
+    }
+  }
+  ```
+
 ## 1.6.7
 
 No significant changes to this package were made in this release. [See the releases page on GitHub](https://github.com/remix-run/remix/releases/tag/remix%401.6.7) for an overview of all changes in v1.6.7.
diff --git a/packages/remix-server-runtime/package.json b/packages/remix-server-runtime/package.json
index 98814f245..16218f518 100644
--- a/packages/remix-server-runtime/package.json
+++ b/packages/remix-server-runtime/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@remix-run/server-runtime",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "Server runtime for Remix",
   "bugs": {
     "url": "https://github.com/remix-run/remix/issues"
diff --git a/packages/remix-vercel/CHANGELOG.md b/packages/remix-vercel/CHANGELOG.md
index 8ab1d6db7..3d16c6488 100644
--- a/packages/remix-vercel/CHANGELOG.md
+++ b/packages/remix-vercel/CHANGELOG.md
@@ -1,5 +1,12 @@
 # `@remix-run/vercel`
 
+## 1.6.8
+
+### Patch Changes
+
+- Updated dependencies:
+  - `@remix-run/node@1.6.8`
+
 ## 1.6.7
 
 ### Patch Changes
diff --git a/packages/remix-vercel/package.json b/packages/remix-vercel/package.json
index c041fed96..a358f9122 100644
--- a/packages/remix-vercel/package.json
+++ b/packages/remix-vercel/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@remix-run/vercel",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "Vercel server request handler for Remix",
   "bugs": {
     "url": "https://github.com/remix-run/remix/issues"
@@ -14,7 +14,7 @@
   "main": "dist/index.js",
   "typings": "dist/index.d.ts",
   "dependencies": {
-    "@remix-run/node": "1.6.7"
+    "@remix-run/node": "1.6.8"
   },
   "devDependencies": {
     "@types/supertest": "^2.0.10",
diff --git a/packages/remix/package.json b/packages/remix/package.json
index be07ca22a..c85bd9a64 100644
--- a/packages/remix/package.json
+++ b/packages/remix/package.json
@@ -1,6 +1,6 @@
 {
   "name": "remix",
-  "version": "1.6.7",
+  "version": "1.6.8",
   "description": "A framework for building better websites",
   "homepage": "https://remix.run",
   "bugs": {
diff --git a/templates/deno/.vscode/settings.json b/templates/deno/.vscode/settings.json
index 2fe1308e4..e1533c2bb 100644
--- a/templates/deno/.vscode/settings.json
+++ b/templates/deno/.vscode/settings.json
@@ -1,5 +1,4 @@
 {
   "deno.enable": true,
-  "deno.importMap": "./.vscode/resolve_npm_imports.json",
   "deno.lint": true
 }
diff --git a/templates/deno/deno.json b/templates/deno/deno.json
new file mode 100644
index 000000000..67973e8d5
--- /dev/null
+++ b/templates/deno/deno.json
@@ -0,0 +1,6 @@
+{
+  "importMap": ".vscode/resolve_npm_imports.json",
+  "compilerOptions": {
+    "lib": ["dom", "dom.iterable", "dom.asynciterable", "deno.ns"]
+  }
+}


Test patch:
diff --git a/.github/workflows/release-test.yml b/.github/workflows/release-test.yml
index 2d2f7dc4d..e15c4b4e3 100644
--- a/.github/workflows/release-test.yml
+++ b/.github/workflows/release-test.yml
@@ -1,11 +1,11 @@
-name: 🧪 Test
+name: 🧪 Test (release)
 
 on:
   push:
     branches:
       - release-*
-    tags-ignore:
-      - v*
+    tags:
+      - "v0.0.0-nightly-*"
     paths-ignore:
       - "docs/**"
       - "scripts/**"
diff --git a/.github/workflows/reusable-test.yml b/.github/workflows/reusable-test.yml
index 90b554738..1bf11c63d 100644
--- a/.github/workflows/reusable-test.yml
+++ b/.github/workflows/reusable-test.yml
@@ -1,4 +1,4 @@
-name: 🧪 Test
+name: 🧪 Test (shared)
 
 on:
   workflow_call:
diff --git a/packages/remix-dev/__tests__/cli-test.ts b/packages/remix-dev/__tests__/cli-test.ts
index ba727183b..90ed4f9b7 100644
--- a/packages/remix-dev/__tests__/cli-test.ts
+++ b/packages/remix-dev/__tests__/cli-test.ts
@@ -96,6 +96,7 @@ describe("remix CLI", () => {
             $ remix build [projectDir]
             $ remix dev [projectDir]
             $ remix routes [projectDir]
+            $ remix watch [projectDir]
             $ remix setup [remixPlatform]
             $ remix migrate [-m migration] [projectDir]
 
@@ -171,6 +172,14 @@ describe("remix CLI", () => {
             $ remix dev my-app
             $ remix dev --debug
 
+          Start your server separately and watch for changes:
+
+            # custom server start command, for example:
+            $ remix watch
+
+            # in a separate tab:
+            $ node --inspect --require ./node_modules/dotenv/config --require ./mocks ./build/server.js
+
           Show all routes in your app:
 
             $ remix routes