This release includes some significant improvements to the way Remix apps are deployed to production. It includes two major improvements to a production Remix app:
These are some pretty major changes to the underlying architecture of Remix that fixes support for several cloud providers and opens the door to deploying to many more.
Specifially, this release fixes deployments on both Architect (broken in 0.10) and Vercel (who recently changed the way they do deploys).
To upgrade from Remix 0.13:
@remix-run/cli
from your dependencies
in package.json
and replace it with @remix-run/dev
in your devDependencies
createRequestHandler({ build: require("./build") })
in server.js
postinstall
step to run remix build
build/assets.json
to know when to restart the serverAs always, remember to use the starters as your guide. We currently have starter repos for:
Before Remix 0.14, we had both development and production dependencies in the same package: @remix-run/core
. Having everything in one package helped us bootstrap the project quickly, but also became a burden over time. For example, as we added features to the Remix compiler, which is only needed in development, the overall size of the dependencies Remix needed in a production deployment grew. So, we knew we needed to split out all of Remix's development dependencies into a separate package. In addition, some of our dev dependencies require binaries that we are not able to deploy to AWS. Separating them out into a dev-only package fixes production deploys on AWS.
Another issue with deploying Remix to production before this release is that it required you to deploy your remix.config.js
file (and your app
directory!) alongside your build
directory. Remix would read the config and reconstruct the route hierarchy at runtime so that it knew about any dynamic routes you created using config.routes
. It would also dynamically require
all modules needed to run your app, which was a non-starter on hosts like Netlify (and, suddenly as of this week, Vercel 🤷♂️). We knew we needed to get rid of all dynamic require
s in production. You shouldn't have to deploy your source code, just the build artifacts.
So ... this release splits up our core dependency and completely alters the way we load modules and deploy to production.
No sweat, right? 😅
The big winner is that your production deploys are going to be more streamlined (no dev dependencies) and we are laying the groundwork for being able to deploy Remix to more providers by eliminating dynamic requires.
Despite the significant changes on our side, upgrading your app from Remix 0.13 should be fairly straightforward.
First, remove @remix-run/cli
from your dependencies
in package.json
and replace it with @remix-run/dev
in your devDependencies
.
$ npm remove @remix-run/cli
$ npm add -D @remix-run/dev
Going forward, @remix-run/dev
will contain everything you need to develop a Remix app. It should only ever be in devDependencies
so it doesn't end up in your production environment. We even named it dev
to help you remember :D
Next, we need to let the Remix server know about our app. In Remix 0.14, your entire app is compiled down to a single module in build/index.js
with static require
calls to load the rest of the app. This means you can load the entire app using require("./build")
(or whatever your config.serverBuildDirectory
is).
To upgrade, open up server.js
(or your serverless function module) and add the build
key to your server's createRequestHandler
:
createRequestHandler({
// Add this line!
build: require("./build"),
getLoadContext() {
// ...
}
});
Note: You can see how we did it in the Express starter.
This line requires the entire app and passes it to your server. Of course, this means you'll need to actually build the app before you can start the server, so you may want to add a postinstall
hook to your package.json
so that your app is ready to go after a fresh npm install
:
{
"scripts": {
"postinstall": "remix build"
}
}
If you're using Vercel, Architect, or Firebase, this postintall hook isn't necessary, just make sure your build finishes before you open the app in the browser.
In Express apps, you'll probably also want to update your file watcher in development. We currently recommend watching build/assets.json
to know when to restart your server.
In the Express starter we use PM2. The relevant portion of the config looks like this:
module.exports = {
apps: [
{
script: "server.js",
watch: ["build/assets.json"]
}
]
};
Note: There are actually 2 builds going on (server and client), but the client build always takes longer since it has to bundle dependencies as well as your app code. So that's why we recommend watching build/assets.json
. We are, however, working on improving our build times, so this recommendation may change soon.
If you're using Vercel or Architect, you don't need to set up any watchers, these providers dev servers already handle the file watching.
The build config and remix config in Vercel deploys were a bit involved because of our dynamic requires, you can now greatly simplify it, and even use Vercel's auto-deploys from GitHub now.
Your remix.config.js
no longer needs to branch on any environment variables, it can be simple again:
module.exports = {
appDirectory: "app",
browserBuildDirectory: "public/build",
publicPath: "/build/",
serverBuildDirectory: "build",
devServerPort: 8002
};
Your vercel.json
can likewise be simplified by removing the includeFiles
option in your builds config:
{
"builds": [
{
"src": "index.js",
"use": "@vercel/node"
}
],
// etc.
}
Because your app modules are all in the require graph now, we don't need to provide any hints to Vercel about what to deploy, it knows just by looking at your index file.
A few other miscellaneous changes in this release that you may be interested in:
.cache
directory in the root (sibling to remix.config.js
). If you want to put it somewhere else, use config.cacheDirectory
in your remix.config.js
process.env.NODE_ENV
strings in your server code anymore, so you should get that value from the actual process that is running your serverEnjoy your slimmed down production builds!