@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"
}