Skip to main content
Version: next

@front-commerce/remix

This package contains Front-Commerce implementations related to Remix.

Installation

First ensure you have installed the package:

$ pnpm install @front-commerce/remix@latest

Type Safety

You can get type safety over the network for your loaders with LoaderFunctionArgs and for your actions with ActionFunctionArgs.

To ensure that the typed frontCommerce context is in the arguments, you can add the @front-commerce/remix reference to your remix.env.d.ts file.

remix.env.d.ts
/// <reference types="@remix-run/dev" />
/// <reference types="@remix-run/node" />
/// <reference types="@front-commerce/remix" />

Front-Commerce Context

To ensure the Front-Commerce Context is available in your loaders and actions, you need to add the createFrontCommerceContext to your server via the getLoadContext, to do this, update your server.ts

import { createFrontCommerceContext } from "@front-commerce/remix";
import { createRemixRequest } from "@remix-run/express/dist/server";

app.all(
"*",
createRequestHandler({
build: require(BUILD_DIR),
mode: process.env.NODE_ENV,
getLoadContext(request, response) {
const remixRequest = createRemixRequest(request, response);
return {
frontCommerce: createFrontCommerceContext(remixRequest),
};
},
})
);

@front-commerce/remix/node

@front-commerce/remix/react

We exposed new methods in the @front-commerce/remix to replace the methods from @remix-run which allows for better type safety:

These methods are used the same as the ones from @remix-run with the exception of useApiFetcher, for example:

/app/routes/my-route.tsx
import { useLoaderData } from "@remix-run/react";
import { useLoaderData } from "@front-commerce/remix/react";
import { json } from "@remix-run/node";
import { json } from "@front-commerce/remix/node";

const loader = () => {
return json({
foo: "bar" as const
date: new Date()
});
};

export default function MyRoute() {
const data = useLoaderData<typeof loader>();

return (
<div>
{data.foo} // data will be typed as { foo: "bar", date: string } instead of SerializeObject<UndefinedToOptional<{ foo: "bar", date: string }>>
</div>
);
}

In the above example the data will be typed as

{ foo: "bar", date: string }

Instead of the standard remix SerializeObject type:

SerializeObject<UndefinedToOptional<{ foo: "bar"; date: string }>>;

useApiFetcher

The useApiFetcher is an optimised fetcher which allows to deduplicate client-side calls to the same /api endpoint. It is designed to replace the load method from useFetcher for API calls.

Here is an example of how to change from useFetcher to useApiFetcher:

/app/routes/my-route.tsx
import type { loader } from "./api.cart";
import { useFetcher } from "@front-commerce/remix/react";

export default function MyRoute() {
const fetcher = useFetcher<typeof loader>();

useEffect(() => {
if (!fetcher.data && fetcher.state !== "loading") {
fetcher.load("/api/cart");
}
}, [fetcher]);

if (fetcher.state === "loading") {
return <div>Loading...</div>;
}

const data = fetcher.data;

return (
<div>
Cart Id: {data.cart.id}
Cart Qty: {data.cart.items_qty}
</div>
);
}

Here is an example of 5 concurrent calls to the same /api/cart endpoint:

http://localhost:4000

As you can see with the useFetcher it will call the API for each component, with the useApiFetcher it will only called the API once and share the data between the components. This also works when using the useRevalidator hook.

useApiFetcherPromise

Just like useApiFetcher, useApiFetcherPromise allows you to retrieve optimised data from /api endpoints. The only difference is that it returns a promise instead of the actual data. Use it when you need to process the data in a more "synchronous" way, without depending on fetcher states.

Here is an example of how to use useApiFetcherPromise:

/app/routes/my-route.tsx
import type { loader } from "./api.cart";
import { useApiFetcherPromise } from "@front-commerce/remix/react";

export default function MyRoute() {
const doSomething = useApiFetcherPromise<typeof loader>("/api/do-something");

return (
<div>
<button
onClick={() =>
doSomething().then((result) =>
console.log("Something has been done!", result)
)
}
>
Do something !
</button>
</div>
);
}

CLI

translate

Extract translations from your application sources

Usage

$ front-commerce translate <path> --locale <locale>

Options

--help, -h Displays this message --locale Output locale for the translations

codegen

Run the graphql-codegen command

Usage

$ front-commerce codegen

Options

--help, -h Displays this message --watch, -w Watch for changes and regenerate --verbose, -v Verbose logging for debugging purposes

find-unused-style-variables

Checks the application for unused style variables.

Usage

$ front-commerce find-unused-style-variables <path/to/your/project> [second/path/to/your/project] ...

Options

--help, -h Displays this message

migrate

Migrate your project to a new version of Front-Commerce

Usage

$ front-commerce migrate <target>

Options

--help, -h Displays this message --dry, -d Run the migration without changing any file --verbose Show more information about the migration

worker

Runs the Server Side Events worker instance.

This should be added as a script in the package.json

package.json
"scripts": {
"worker": "front-commerce worker"
}