Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Environment variables declared in the Oxygen admin are not available via import.meta.env #2033

Closed
maplessmann opened this issue Aug 24, 2022 · 10 comments
Labels
bug Something isn't working

Comments

@maplessmann
Copy link

Describe the bug
I have a sanity.config.js file at the root of my project:

export const sanityConfig = {
  apiVersion: 'v2022-05-01',
  dataset: import.meta.env.PUBLIC_SANITY_DATASET,
  projectId: 'xyz',
  useCdn: true,
}

When I deploy my app to Oxygen, dataset is undefined.

Note: PUBLIC_SANITY_DATASET env variable was added to my Oxygen admin

To Reproduce

  1. Go to Oxygen admin
  2. Create a new env variable with PUBLIC_ prefix. E.g PUBLIC_SANITY_DATASET
  3. Open a .js file and add this line: console.log(import.meta.env.PUBLIC_SANITY_DATASET)
  4. Deploy to Oxygen
  5. If you check the preview URL, you'll see that the log is returning undefined

Expected behaviour
import.meta.env.PUBLIC_SANITY_DATASET should return the value defined in my Oxygen admin

  • Hydrogen version: 1.1.0
  • Node version: 16
@maplessmann maplessmann added the bug Something isn't working label Aug 24, 2022
@frandiox
Copy link
Contributor

Currently, the variables added in Oxygen admin are only available using Oxygen.env because they are runtime variables. The import.meta.env syntax requires that the variables are available locally when building the project. For now, you can try one of the following:

  • Use import.meta.env.PROD or import.meta.env.DEV to switch datasets:
    dataset: import.meta.env.PROD ? 'production' : 'development',
  • Use Oxygen.env, but you also need to wrap it in a function:
    export const sanityConfig = () => ({
      apiVersion: 'v2022-05-01',
      dataset: Oxygen.env.SANITY_DATASET,
      ...
    })
    
    // When you import it in your component:
    function MyServerComponent() {
       const sanity = sanityConfig();
       ...
    }

@maplessmann
Copy link
Author

Thank you @frandiox, your solution worked for me!

@9001-Sols
Copy link

9001-Sols commented Sep 14, 2022

I am completely unable to access Oxygen environment variables (in the client) on any environment, running locally or deployed/published to Oxygen. Environment variables are created in the Oxygen admin (Oxyven.env locally), and flagged for Preview and Production.

declare const Oxygen: any;
if (typeof Oxygen !== 'undefined') {
  console.log('FOUND OXYGEN', Oxygen);
} else {
  console.log('OXYGEN NOT FOUND');
}

const oxygenConfig = () => ({
  PUBLIC_DEBUG: 'PUBLIC_DEBUG',
});

...

const debug = oxygenConfig()["PUBLIC_DEBUG"];

Oxygen.env contents for local run

PUBLIC_DEBUG="PUBLIC_DEBUG"

Results in:
OXYGEN NOT FOUND 4react-server-dom-vite.js:97 Uncaught ReferenceError: Oxygen is not defined

@blittle
Copy link
Contributor

blittle commented Sep 14, 2022

@9001-Sols Oxygen.env can only be used within server components. It is for runtime environment variables, and the client code get's build and bundled. That bundle of code is downloaded to the browser and when it executes it inherently doesn't have access to the runtime environment variables on the server. If the client needs access to a runtime environment variable, get the variable in a server component with Oxygen.env and pass it to a client component as a prop.

Separately, environment variables can be injected into the client bundle of code at build time. Use import.meta.env to do so. Again, these are variables that might exist in your CI process that is building hydrogen.

Make sure whatever you do, that no secret variables are passed to client components.

@9001-Sols
Copy link

While not directly related, I figured I'd post some findings for other people having issues with .env's in Hydrogen.

It seems that import.meta.env.xyz gets statically replaced, so it can't be dynamically keyed into. Additionally, it is an exact replace, so it can't be safely accessed. This is actually documented in the vite docs, and not Hydrogen. https://vitejs.dev/guide/env-and-mode.html#production-replacement

console.log('|mport.meta.env.PUBLIC_DEBUG', import.meta.env.PUBLIC_DEBUG); // Works as expected
console.log('|mport.meta.env[PUBLIC_DEBUG]', import.meta.env['PUBLIC_DEBUG']); // Works as expected
// console.log('|mport.meta?.env.PUBLIC_DEBUG', import.meta?.env.PUBLIC_DEBUG); // <-- Breaks the build if uncommented
console.log('|mport.meta?.env?.PUBLIC_DEBUG', import.meta?.env?.PUBLIC_DEBUG); // undefined
console.log("|mport.meta?.env?.['PUBLIC_DEBUG']", import.meta?.env?.['PUBLIC_DEBUG']); // undefined

Notice the usage of | in the raw string part of the console logs - if I wrote out import.meta.env in the raw string portion, it gets statically replaced and can break JS syntax, thus leading to build breakage.

@blittle
Copy link
Contributor

blittle commented Sep 16, 2022

I think we are going to update the docs to mainly focus on runtime variables through Hydrogen.env (Oxygen.env being deprecated). I don't think we should push the user into using import.meta.env, as build time vs runtime variables has proven to be confusing. And it's a vite thing, so if someone comes to Hydrogen with vite experience, they might use import.meta.env, but I think we'll remove it from our docs. See this PR: Shopify/hydrogen#2150

@blittle blittle closed this as completed Sep 16, 2022
@beachstrider
Copy link

Thanks so much, Frandiox.

Can you explain why Oxygen should be wrapped by function?

@frandiox
Copy link
Contributor

frandiox commented Jan 3, 2023

@jasonheo729 Because code that is not wrapped in functions will be executed before we can polyfill the global Oxygen.env and will get undefined. Therefore, instead of running that code at the very start of the script, you need to delay its execution until the first time it's needed (e.g. when making the first DB/API request).

The whole story is that, in workers runtime, the env object is scoped to a request and is only available in the fetch handler function. That's the first place where we can polyfill the global Oxygen.env:

const v1 = Oxygen?.env?.VALUE_1; // First thing to run, Oxygen.env is undefined
const getV2 = () => Oxygen.env.VALUE_2;

export default {
  fetch(request, env) {
     // Oxygen setup
     global.Oxygen = {env};

     // Run the rest of your app
     v1; // undefined
     getV2(); // This now has access to Oxygen.env
  }
}

We are removing the global Oxygen.env in Hydrogen v2 to avoid this kind of problem. Env vars will be available only by using the original env parameter.

@beachstrider
Copy link

beachstrider commented Jan 3, 2023 via email

@beachstrider
Copy link

Can we expose env vars in index.html?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants