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

Environment variables on process.env sometimes not available in hooks.js in local dev #3030

Closed
josefaidt opened this issue Dec 12, 2021 · 8 comments
Labels
p3-edge-case SvelteKit cannot be used in an uncommon way

Comments

@josefaidt
Copy link
Contributor

josefaidt commented Dec 12, 2021

Describe the bug

I'm looking to use the handle hook to add authentication and authorization middleware to my API routes, however the variables needed to verify user JWT's are sometimes not available when the hook runs, but only in local development. In my experience these variables were available just once after upgrading dependencies to use Vite 2.7.1, however on subsequent attempts/restarts of the dev server these variables were no longer available and thus all API attempts would be unauthorized. I've attempted to remove the .svelte-kit directory, node_modules, lockfile, and reinstall to no avail.

It is important to note this is only experienced during local development with svelte-kit dev, and may actually be a Vite-related issue (given the Svelte-Kit scope I decided to file here first to see what y'all's thoughts are).

This can be mitigated by adding a small Vite plugin to load secrets with dotenv

// svelte.config.js
// ...
/** @type {import('@sveltejs/kit').Config} */
const config = {
  kit: {
    adapter: adapter(),

    // hydrate the <div id="svelte"> element in src/app.html
    target: '#svelte',

+   vite: {
+     plugins: [
+       (function LoadSecrets() {
+         return {
+           name: 'load-secrets',
+           configureServer: async () => {
+             ;(await import('dotenv')).config()
+           }
+         }
+       })()
+     ]
+   }
  }
}

And for reference, the hooks.js file:

export async function handle({ request, resolve }) {
  let user = await authenticate(request) // verifies JWT, requires 3 server-side env vars

  request.locals.user = user
  request.locals.isAuthenticated = !!user

  if (request.path.startsWith('/api')) {
    if (!user) {
      return {
        status: 401,
        body: JSON.stringify({
          error: {
            message: 'Unauthorized'
          }
        })
      }
    }

    if (request.path.startsWith('/api/admin') && !isAdmin(user)) {
      return {
        status: 403,
        body: JSON.stringify({
          error: {
            message: 'Invalid Admin'
          }
        })
      }
    }
  }

  const response = await resolve(request)
  return response
}

Reproduction

  1. Create a Svelte-Kit app with npm init svelte@next my-app
  2. Create a .env file in the project root, add an environment variable
    MY_VAR="hello, world!"
    
  3. Create src/hooks.js:
    export async function handle({ request, resolve }) {
      console.log(process.env['MY_VAR']) // sometimes undefined
      const response = await resolve(request)
      return response
    }
  4. Run the dev server with svelte-kit dev and observe error

Logs

No response

System Info

System:
    OS: macOS 11.5.1
    CPU: (4) x64 Intel(R) Core(TM) i7-7567U CPU @ 3.50GHz
    Memory: 30.61 MB / 16.00 GB
    Shell: 3.3.1 - /usr/local/bin/fish
  Binaries:
    Node: 16.13.0 - /var/folders/pp/ty2pnrf50xg0zgv3033j83_m0000gn/T/fnm_multishells/917_1639061469329/bin/node
    Yarn: 1.23.0-20210726.1745 - /var/folders/pp/ty2pnrf50xg0zgv3033j83_m0000gn/T/fnm_multishells/917_1639061469329/bin/yarn
    npm: 8.1.0 - /var/folders/pp/ty2pnrf50xg0zgv3033j83_m0000gn/T/fnm_multishells/917_1639061469329/bin/npm
  Browsers:
    Brave Browser: 92.1.28.105
    Chrome: 96.0.4664.93
    Chrome Canary: 98.0.4758.2
    Edge: 96.0.1054.43
    Firefox: 94.0.1
    Firefox Developer Edition: 68.0
    Safari: 14.1.2
  npmPackages:
    @sveltejs/adapter-auto: next => 1.0.0-next.3 
    @sveltejs/adapter-vercel: next => 1.0.0-next.31 
    @sveltejs/kit: next => 1.0.0-next.201 
    svelte: ^3.44.0 => 3.44.2 

dependencies are installed with pnpm, Vite version is 2.7.1

Severity

serious, but I can work around it

Additional Information

No response

@korywka
Copy link

korywka commented Dec 14, 2021

Thanks for workaround. Confirm this bug with 1.0.0-next.202 too.

@jitheshkt
Copy link

I am also facing the same issue. Your walkaround works perfectly, but only on Development. On production, MY_VAR is always undefined. Any way to bypass?

@Feuerhamster
Copy link

Same issue here

@bluwy
Copy link
Member

bluwy commented Dec 28, 2021

SvelteKit/Vite had never load .env variables for the server-side, so I'm not sure how it used to work before. dotenv would be needed if you want to use .env variables, though I'm not familiar where to place this, perhaps the workaround vite plugin is the right way (?). With that said, SvelteKit hasn't officially supported it since process.env isn't available in all environments, and we don't have a solution for it yet.

Note: We have a brief documentation about it.

@bluwy bluwy added the p3-edge-case SvelteKit cannot be used in an uncommon way label Dec 28, 2021
@josefaidt
Copy link
Contributor Author

Hey @bluwy thanks for the confirmation. I haven't run into issues using process.env elsewhere in the app (like api routes), but it seems this issue only affects the hooks.js file. Vite's dev server should read from .env, where this is sufficient for local development as I am not uploading the .env file to production.

It's worth noting this is only affecting my dev environment, and production (on Vercel, using the Vercel adapter) is okay. I guess the confusion that motivated me filing this issue is due to how we're able to use process.env in API routes but not in hooks, sometimes.

@korywka
Copy link

korywka commented Dec 29, 2021

this solution works for DEV env. I hope it works for production env too:

vite: {
      define: (() => {
        const result = {};
        const env = dotenv.config().parsed;
        Object.entries(env).forEach(([k, v]) => result[`process.env.${k}`] = `'${v}'`);
        return result;
      })(),
},

@10p-freddo
Copy link

You don't need a plugin, either of these will work:

NODE_OPTIONS='-r dotenv/config' npm run dev
npx --node-options='-r dotenv/config' svelte-kit dev

@Rich-Harris
Copy link
Member

Going to close this in favour of #4296, which covers this along with various other aspects of env vars

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
p3-edge-case SvelteKit cannot be used in an uncommon way
Projects
None yet
Development

No branches or pull requests

7 participants