@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.
/// <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:
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
:
- useFetcher
- useApiFetcher
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>
);
}
import type { loader } from "./api.cart";
import { useApiFetcher } from "@front-commerce/remix/react";
export default function MyRoute() {
const { data, loading } = useApiFetcher<typeof loader>("/api/cart");
if (loading) {
return <div>Loading...</div>;
}
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:
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
:
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
"scripts": {
"worker": "front-commerce worker"
}