envsafe
envsafe copied to clipboard
Next.js / CRA webpack plugins
Link: https://envsafe-nextjs.katt.vercel.app/
- Created webpack plugin
- Exposes
process.env.browserEnvand 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.envso it forces us to passenv: process.browserEnvwhen usingenvsafe(): https://github.com/KATT/envsafe/blob/6d156a3d55cbd5530ba31b7f19a9cf37345139f1/examples/next.js/utils/browserEnv.js#L11
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;
};
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 🔥 🔥 🔥 🔥