Skip to content

v1.12.0

Compare
Choose a tag to compare
@chaance chaance released this 31 Jan 00:10
· 2508 commits to main since this release
f215e47

We've got a few nice bug fixes and improvements in this release. You can catch those in the individual package changelogs below, but what we really want to talk about today is a huge step forward in a much nicer developer experience for you. Let's get to it!

An early peek at a new dev server 👀

Since the early days of Remix, the remix dev command has been limited by its association with the built-in Remix app server while remix watch simply watched your files and spit out builds, but doesn't handle requests like some other tools. But one of the major benefits of this is that Remix lets you own your server. While this is a very powerful core feature of our architecture, it presented a few challenges for local development. If you own your server, how can we build a dev server that is flexible enough to work for your specific setup?

Our first answer was … we don't. Don't try to be clever, don't over-abstract anything. Simply run the remix watch, spit out files, and have <LiveReload> tell the browser to reload. But we didn't know if your app server was done rebooting the server code! And in the case of remix dev with remix-serve, we didn't reboot the server, we simply wiped out the node require cache as a budget server side HMR.

There were a few downsides for local development with this:

  1. Clearing the require cache wipes in-memory references, such as database connections or in-memory caches. This means you have to use workaround like sticking flags on global to persist anything stored in memory across rebuilds.
  2. Getting the web socket port to remix watch and over to your app server in a different process (whether it was express, netlify def, vercel dev, etc.) and using it in LiveReload was a lot of unnecessary friction.
  3. It makes implementing popular new dev features like hot-module replacement (HMR) much more difficult to implement in a way that works consistently across all app servers.
  4. Each rebuild writes new files to build/ and public/build/. As these files are not removed (unless the dev server crashes or is gracefully terminated), thousands of files could accumulate as the dev server ran. This causes performance issues and could be confusing when debugging.

To start addressing these issues, we decided to take a new approach. This release gives you early access to our new dev server and start making incremental improvements to your local development flow.

Please note that this is an unstable feature and a work-in-progress. But we think there are good reasons to opt in right away!

At this stage, the idea is to spin up the dev server alongside your normal Remix app server:

# spin up the new dev server
remix dev

# Spin up your app server in parallel.
# This can be done in a separate terminal or with a tool like `concurrently`.
nodemon --watch build/ ./server.js

Our dev server will build your app in development mode and then rebuild whenever any app files changes. It will also wait for your app server to signal that it's "ready" before triggering a reload in your browser.

No more wiping in-memory caches. No more weird hacks to keep your database alive. A fresh, clean slate for each rebuild.

While this may seem like a relatively small change, but it's removes a huge barrier for future DX improvements for local development. We think you're going to love what we're working on next 🔥🔁

Limitations

The new dev server does not currently work with Remix App Server (i.e. remix-serve command) because Remix App Server hardcodes NODE_ENV=production.

Rest assured, when the new dev server stabilizes it will support Remix App Server as well.

Configuring the unstable_dev server

To enable the new dev server with all defaults, set the unstable_dev future flag to true:

// remix.config.js
module.exports = {
  future: {
    unstable_dev: true,
  },
};

You can also set specific options. As this is an unstable feature, these options may change before the next major release.

// remix.config.js
module.exports = {
  future: {
    unstable_dev: {
      // Port to use for the dev server (i.e. the <LiveReload> websocket)
      // This can be overridden by a CLI flag: `remix dev --port 3011`
      // By default, we will find an empty port and use that
      port: 3010,

      // Port for running your Remix app server
      // This can be overridden by a CLI flag: `remix dev --app-server-port 3021`
      // default: `3000`
      appServerPort: 3020,

      // Path to the Remix request handler in your app server
      // Most app servers will route all requests to the Remix request
      // handler and will not need this option. If your app server _does_
      // route only certain request paths to the Remix request handler, then
      // you'll need to set this.
      // default: `""`
      remixRequestHandlerPath: "/products",

      // The number of milliseconds between "readiness" pings to your app server
      // When a Remix rebuild finishes, the dev server will ping a special
      // endpoint (`__REMIX_ASSETS_MANIFEST`) to check if your app server is
      // serving up-to-date routes and assets. You can set this option to tune
      // how frequently the dev server polls your app server.
      // default: `50`
      rebuildPollIntervalMs: 25,
    },
  },
};

Other Stuff

  • Updated to latest react-router versions. See the release notes for more details.
    • react-router-dom@6.8.0
    • @remix-run/router@1.3.1
  • You can now configure the client-side socket timeout via the new timeoutMs prop on <LiveReload /> (#4036)
  • <Link to> can now accept absolute URLs. When the to value is an absolute URL, the underlying anchor element will behave as normal, and its URL will not be prefetched. (#5092)
  • Added support for unstable_useBlocker and unstable_usePrompt from React Router (#5151)
  • Removed react & react-dom from peerDependencies (#4801)

Changes by Package 🔗