Shopify / shopify-app-template-remix

374 stars 151 forks source link

[Question] Reading `SHOPIFY_API_KEY` via Vite `define` instead of `loader()` #798

Open kinngh opened 3 months ago

kinngh commented 3 months ago

app/routes/app.tsx pulls the SHOPIFY_API_KEY from protected env via a loader, which is the Remix recommended way of reading envs client side in Remix.

export const loader = async ({ request }: LoaderFunctionArgs) => {
  await authenticate.admin(request);

  return json({ apiKey: process.env.SHOPIFY_API_KEY || "" });
};

export default function App() {
  const { apiKey } = useLoaderData<typeof loader>();

  return (
    <AppProvider isEmbeddedApp apiKey={apiKey}>
      <NavMenu>
        <Link to="/app" rel="home">
          Home
        </Link>
        <Link to="/app/additional">Additional page</Link>
      </NavMenu>
      <Outlet />
    </AppProvider>
  );

Since this requires making a fetch request on each page load OR building ways to persist across navigations, why not use Vite's define instead to read it, since the API key is completely find with being exposed to the client side?

bun install dotenv -D

vite.config.ts:

import "dotenv/config"

export default defineConfig({
 define: {
    SHOPIFY_API_KEY: JSON.stringify(process.env.SHOPIFY_API_KEY ),
  },
  ...
  }

app.tsx:

export default function App() {
  return (
    <AppProvider isEmbeddedApp apiKey={SHOPIFY_API_KEY}>
        ...
    </AppProvider>
  );
}

From my understanding, using Vite's define feature saves us at least one fetch() to get the API key and allows shedding the (potential) persistence code since Vite now handles providing the right value(s) across the board?

matteodepalo commented 3 months ago

Hi @kinngh thank you for the proposal! This makes sense to me, however I'll double check with the team to see if there are any gotchas here.

kinngh commented 3 months ago

Sure thing! If you want to see it in action, I've been working on a Remix boilerplate (it's broken in all sort of ways for now), but this specific part works.

Vite Config: vite.config.js Reading the API Key: root.jsx

matteodepalo commented 3 months ago

Great! One question is, do we need the dotenv package?

kinngh commented 3 months ago

I have seen that without the dotenv package and import in vite config the value is thrown as undefined sometimes, which is why I've added in as a dev dependency just to be sure that when developers use with older versions of node, it still works.

I also have a problem with aggressive caching in my setup so I cannot definitively state if we really do need the dotenv package

muchisx commented 2 months ago

Hi @matteodepalo !

Putting my two cents here,

We've done this in our app for a few months already, our approach is a bit different though:

// app.tsx
import { PUBLIC_ENV } from '~/constants/app';

<AppProvider isEmbeddedApp apiKey={PUBLIC_ENV.VITE_SHOPIFY_API_KEY}>
// constants file, or you can just use directly in the app.tsx

const {  VITE_SHOPIFY_API_KEY, ...otherstuff } = import.meta.env;
export const PUBLIC_ENV = {
  VITE_SHOPIFY_API_KEY,
} as const;
// shopify.server.ts
const shopify = shopifyApp({
  apiKey: process.env.VITE_SHOPIFY_API_KEY, // or from PUBLIC.ENV.VITE_SHOPIFY_API_KEY, its the same
..etc

With our approach there was no need to mess with vite.config.ts, only thing was swapping the name of the ENV (adding VITE_)

https://vitejs.dev/guide/env-and-mode

matteodepalo commented 2 months ago

Thank you for the alternative approach @muchisx ! We've put this issue in our backlog.