envsafe icon indicating copy to clipboard operation
envsafe copied to clipboard

Next.js / CRA webpack plugins

Open KATT opened this issue 5 years ago • 2 comments

Link: https://envsafe-nextjs.katt.vercel.app/

  • Created webpack plugin
  • Exposes process.env.browserEnv and breaks compile-time when deploying if env vars are missing
  • Useage: https://github.com/KATT/envsafe/blob/6d156a3d55cbd5530ba31b7f19a9cf37345139f1/examples/next.js/next.config.js#L1-L10

Good

  • Gets rid of input:-prop
  • Breaks compile-time instead of runtime

Bad

  • Configuration needed to use
  • TSDX doesn't support multiple output files so it'll be bundled with the rest
  • I don't wanna risk colliding with any internals of nextjs' usage of process.env so it forces us to pass env: process.browserEnv when using envsafe(): https://github.com/KATT/envsafe/blob/6d156a3d55cbd5530ba31b7f19a9cf37345139f1/examples/next.js/utils/browserEnv.js#L11

KATT avatar Sep 17 '20 15:09 KATT

The webpack CRA-plugin is confirmed working for my private repo

config-overrides.js

const webpack = require('webpack');
const rewireReactHotLoader = require('react-app-rewire-hot-loader');
const { env: browserEnv } = require('./src/utils/env');
const { craWebpackPlugin } = require('envsafe');

/* config-overrides.js */
module.exports = function override(config, env) {
  config = rewireReactHotLoader(config, env);
  config.plugins.push(craWebpackPlugin({ browserEnv, webpack }));

  return config;
};

KATT avatar Sep 18 '20 13:09 KATT

Good work @KATT!

I have a few thoughts.

First, for a drop in config for Next/Blitz, you also need to support defining env variables in the next.config.js or blitz.config.js files as described here.

I think you can simply do that with something like this:

import getConfig from "next/config"

const clientEnv = getConfig().env

Secondly, importing browserEnv and passing to the webpack plugin is a good idea, but that won't work if your env config file is Typescript, because next.config.js isn't transpiled or anything.


Now for some thoughts about optimal UX.

I think the UX for this isomorphic/server stuff can be improved. I envision something like this:

export const {clientEnv, serverEnv} = envsafe({
  isomorphic: {
    API_URL: url(),
  },
  serverOnly: {
    SECRET_KEY: str(),
  }
});

The serverOnly config would only parse the env vars on the server, and use a proxy on the client that throws an error if you try to access it. (removing the need for the user to do that themself).

Furthermore, what I would really like is to be able to entirely skip NEXT_PUBLIC_ or env in next.config.js and just use envsafe as shown above. Probably this would require a babel plugin that would convert the above config into static runtime code. This is what Tim was suggesting too. And with this babel plugin approach, you could totally skip the webpack plugin.

The output of the babel plugin would be something like:

export const {clientEnv, serverEnv} = {
  clientEnv: {
    API_URL: 'example.com',  // <-- actual value inlined as a string here
    isProduction: true,
  },
  get serverOnly(): {
    if (typeof window !== 'undefined') throw new Error("can't use on client")
    return {
      SECRET_KEY: process.env.SECRET_KEY,  // <-- pull from Node env at runtime, not inlined in bundle
      // clientEnv also included here:
      API_URL: 'example.com',  
      isProduction: true,
    }
  }
});

This would be 🔥 🔥 🔥 🔥

flybayer avatar Sep 18 '20 17:09 flybayer