If you already have a Remix application that you wish to move to Compute,
the easiest way to do this is to create an empty Remix project using remix-template
.
This way, all the Compute-related dependencies will be installed for you, and the server adapter will be
created as part of the process as well.
NOTE: If you wish to modify your project directly instead, see the Modifying an existing Remix application for Fastly Compute section below.
The general steps are as follows:
- Create an empty Remix project with
remix-template
by following the steps in the README. - Install into your new project any additional dependency packages referenced by your original project.
- Move your existing project’s files into your new project.
In Remix, your application’s files are found in app/
and public/
. For most of the files in these directories, you can
usually simply copy them into your new project, keeping the following points in mind.
-
Some of the source files will reference Remix runtime packages such as
@remix-run/node
,@remix-run/cloudflare
, or@remix-run/deno
. Modify these references to @fastly/remix-server-runtime.For example, you may have the following:
import { json } from "@remix-run/node";
You’ll want to change this to:
import { json } from "@fastly/remix-server-runtime";
-
For
entry.client.tsx
,entry.server.tsx
, androot.tsx
in theapp/
directory, you’ll generally want to start with the ones found in the new project. Examine these files in your source project. Look for any changes that you had made to them in your source project, and then make the equivalent changes in the new project as necessary. -
Skip
/public/build/
. This is a directory that is generated during the build step. -
Depending on the dependencies used by your project, you may need to use module bundling and add polyfills to run in Compute. For details, see "Module bundling" in the template's README.
If you'd rather modify your application in place to adapt it for Fastly Compute, perform the following general steps in your project's directory.
- Install the following dependencies:
npm install @fastly/remix-server-runtime @fastly/remix-server-adapter
- Install the following development dependencies:
npm install --save-dev @fastly/compute-js-static-publish @fastly/js-compute npm-run-all
- Uninstall the previous runtime, such as
@remix-run/node
.
npm uninstall @remix-run/node
- Uninstall the previous adapter if any, such as
@remix-run/express
.
npm uninstall @remix-run/express
- In
remix.config.js
, remove theserverBuildTarget
field if it's set. Also, make sure the following values are set:
serverConditions: ["worker"],
serverDependenciesToBundle: "all",
serverMainFields: ["browser", "module", "main"],
serverMinify: false,
serverModuleFormat: "esm",
serverPlatform: "neutral",
-
In
remix.config.js
, set the value of thedevServerBroadcastDelay
field to10000
. -
Modify
.gitignore
and add the following lines:
# Fastly Compute
/bin
/pkg
# @fastly/compute-js-static-publish
/src/statics.js
/src/statics.d.ts
/src/statics-metadata.js
/src/statics-metadata.d.ts
/src/static-content
- Create a
src/index.js
file with the following content:
/// <reference types="@fastly/js-compute" />
import { createEventHandler } from '@fastly/remix-server-adapter';
import { moduleAssets, getServer } from './statics.js';
/** @type {import('@remix-run/server-runtime').ServerBuild} */
const build = moduleAssets.getAsset('/build/index.js').getStaticModule();
/** @type {import('@fastly/compute-js-static-publish').PublisherServer} */
const server = getServer();
addEventListener("fetch", createEventHandler({ build, server }));
- Create a
fastly.toml
file with the following content:
# This file describes a Fastly Compute package. To learn more visit:
# https://developer.fastly.com/reference/fastly-toml/
authors = []
description = ""
language = "javascript"
manifest_version = 2
name = "remix-compute-js-app"
service_id = ""
[scripts]
build = "npm run build"
- Create a
static-publish.rc.js
file with the following content:
/*
* Copyright Fastly, Inc.
* Licensed under the MIT license. See LICENSE file for details.
*/
/** @type {import('@fastly/compute-js-static-publish').StaticPublisherConfig} */
export default {
rootDir: './',
excludeDirs: [ './node_modules', ],
moduleAssetInclusionTest: function(path) {
if (path.startsWith('/build/') && !path.endsWith('.map')) { return 'static-import'; }
return false;
},
contentAssetInclusionTest: function(path) {
if (path.startsWith('/public/')) { return true; }
return false;
},
server: {
publicDirPrefix: '/public',
},
};
- Modify
remix.env.d.ts
and each source file in/app
, replacing any references to the previous runtime with@fastly/remix-server-runtime
. This includesimport
statements,/// <reference />
directives, and if your application is in TypeSCript,import type
statements.
Examples:
// Change this:
import { json } from "@remix-run/node";
// to this:
import { json } from "@fastly/remix-server-runtime";
// Change this:
/// <reference types="@remix-run/node" />
// to this:
/// <reference types="@fastly/remix-server-runtime" />
// Change this:
import type { EntryContext } from "@remix-run/node";
// to this:
import type { EntryContext } from "@fastly/remix-server-runtime";
- Add the following
scripts
topackage.json
{
"scripts": {
"build": "npm run build:remix && npm run build:fastly",
"build:remix": "remix build",
"prebuild:fastly": "compute-js-static-publish --build-static --suppress-framework-warnings",
"build:fastly": "js-compute-runtime ./src/index.js ./bin/main.wasm",
"deploy": "fastly compute publish",
"dev:remix": "remix watch",
"dev:fastly": "fastly compute serve --watch",
"dev": "run-p \"dev:*\"",
"start": "fastly compute serve"
}
}
- If your current
entry.server.js/ts
usesrenderToPipeableStream
orrenderToReadableStream
to generate their Server-Side-Rendering markup, then you'll have to modify it to userenderToString
. The following is an example:
import type { EntryContext } from "@fastly/remix-server-runtime";
import { RemixServer } from "@remix-run/react";
import { renderToString } from "react-dom/server";
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
const markup = renderToString(
<RemixServer context={remixContext} url={request.url} />
);
responseHeaders.set("Content-Type", "text/html");
return new Response("<!DOCTYPE html>" + markup, {
status: responseStatusCode,
headers: responseHeaders,
});
}
-
Depending on the dependencies used by your project, you may need to use module bundling and add polyfills to run in Compute. For details, see "Module bundling" in the template's README.
-
Depending on your application, further changes may be necessary. Refer to
remix-template
as an example.