v0.16.0 Release Notes

This release gives a taste of what it will be like after our 1.0 release: no breaking changes just improvements and bug fixes 😎

New Features

*.server.js and *.client.js are back!

The new esbuild-based compiler now supports the *.server.js and *.client.js extensions to exclude modules from the opposite build. *.server.js files will only be included in the server bundle and *.client.js files will only be included in the browser bundles.

This allows you to have module side-effects like reading window in client only files:

// ./stripe.client.js
let stripe = createStripe(window.ENV.STRIPE_PUBLIC_KEY);
export { stripe };

Before that would have thrown an error while server rendering, but now it will be excluded from the server build.

Or if you've got node_modules that are doing dynamic requires or have module side-effects that are messing up your browser bundles, you can just eliminate them from the browser bundles by putting those imports into a *.server.js file.

// ./problematic-thing.server.js
import { stuff } from "problematic-thing";
export { stuff };

Now that file will be excluded from client bundles and your problems go away.

npm init remix

Goodbye starters, hello generator!

Instead of cloning starter repos and fiddling around with an .npmrc, we have a new project generator. Give it shot! open up a terminal and type:

npm init remix

It will ask you where you want to deploy, will auto-detect your Remix token in a home ~/.npmrc or REMIX_TOKEN environment variable, ask if you want TypeScript or JavaScript, and then generate the project for you.

remix-serve

If you already tried out npm init remix you may have noticed the first server option was "Remix App Server".

We've been saying the whole time that "Remix isn't your server, it's just a function on your server". Now Remix can also be your server.

npm i @remix-run/serve
remix-serve <server-build-dir>

This is a small, but production-ready, express server for your Remix app. Not only is it great for production, but it makes starting a new project when inspiration strikes frictionless. Check it out:

  1. You get an idea!
  2. npm init remix
  3. npm run dev

And then you can deploy that app easily to places that run node apps like Heroku, Fly, Render, Google App Engine, AWS, etc.

remix dev and remix run3

Yep ... run3. 🤣 We'll explain in a second, but first here's what it does.

Now that we have a Remix App Server, we can have a command that runs both the app server and the dev asset server in the same process (no messing around with multiple tabs or concurrently/pm2-dev).

And that's exactly what run3 does for apps using the Remix App Server!

Okay, let us explain the name:

When we released the new esbuild-based compiler, we added run2 and build2. In the release after this we will be removing the old compiler. Then we can clean up this cli's hilarious command names.

In the next release there will only be three commands:

  • remix build - builds your app for production (today's build2)
  • remix dev - starts the asset dev server and rebuilds on file changes (today's run2)
  • remix run - runs app and dev asset server in the same process in develoment mode (today's run3)

You can use remix dev today instead of run2.

useLiveReload

Running remix dev now supports live reload! When you change files the browser will automatically reload the page. This is a big productivity enhancement.

You have complete control over using this feature or not:

import { useLiveReload } from "remix";

export function Root() {
  useLiveReload();
  return <html>{/* ... */}</html>;
}

It will only connect to the dev server in development mode, so you don't have to worry about removing the hook's call site in production.

People are curious about HMR after this. It will likely happen but not anytime soon. HMR in React is heavily dependent on babel which our new compiler doesn't use. We've explored it and know the amount of effort it will take, so we'll be waiting until our business can afford the investment in a marginal improvement over live reload.

Fixes

useSubmit now works as expected when not passing in a form or button element.