Skip to content

Instantly share code, notes, and snippets.

@devinrhode2
Last active July 21, 2022 04:11
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devinrhode2/e033cf8ec4653cfb70d34389db86cb72 to your computer and use it in GitHub Desktop.
Save devinrhode2/e033cf8ec4653cfb70d34389db86cb72 to your computer and use it in GitHub Desktop.
next.config.js typed with jsdoc, and shared modules. Next 12 + webpack 5. See prior revisions for next 11 support.
const { safeEnv } = require('./src/env')
// Note: NextConfig type allows any keys, so we are plucking the specific keys we want to type-check.
/**
* @type {Pick<
* import('next').NextConfig,
* | 'webpack'
* | 'env'
* >}
*/
const nextConfig = {
/**
* @type {(
* config: import('webpack').Configuration,
* context: {
* dev: boolean
* webpack: import('webpack')
* }
* ) => import('webpack').Configuration}
*/
webpack: (config, { dev, webpack }) => {
// ...
return config
},
env: safeEnv,
}
module.exports = nextConfig
/**
* @type {(rawEnv: {
* readonly [x: string]: string | undefined
* }) => (varName: string) => string}
*/
module.exports = (rawEnv) => (varName) => {
const envVar = rawEnv[varName]
if (!envVar) {
console.log('environment variables:', process.env)
if (envVar === undefined) {
throw new Error(
[
`environment variable ${varName} is undefined.`,
rawEnv.CI
? `It may not be getting passed to "yarn build:ci" in azure-pipelines.yml`
: `Add it to your .env.local file`,
].join('\n'),
)
}
if (envVar === '') {
throw new Error(
[
`environment variable ${varName} is an empty string.`,
rawEnv.CI
? `Check Azure Pipeline Variables Library for "Development" Environment`
: `Please put some value into your .env.local file`,
].join('\n'),
)
}
throw new Error(
`environment variable ${varName} is unknown falsey value: ${envVar}`,
)
}
return envVar
}
// .js since this is used in next.config.js
// Fingers crossed Next will support next.config.TS soon: https://github.com/vercel/next.js/issues/5318
const createGetEnvVar = require('./createGetEnvVar')
// @ts-expect-error - this is the only code allowed to reference `process.env`
const getEnvVar = createGetEnvVar(process.env)
// Using object instead of array, for jsdoc.
// MANUALLY sync `src/env.js` and azure-pipelines.yml (az webapp config, build:ci, envLocal)
// Only vars prefixed with `NEXT_PUBLIC_` will be exposed to browser. Rest are for server side use.
module.exports = {
// Just type `safeEnv<TAB>` and viola!
// 1. Without this line, hovering over `safeEnv` will show just `import safeEnv` :)
// By namespacing, we get fuller hover annotation
// 2. Using name `safeEnv` allows you to type just `saveEnv<TAB>` and auto-import correct module.
// Typing just `env<TAB>` will give you `import env from 'yargs'` :)
// Filename does not match export name, because you have to choose between default export, and this named export.
safeEnv: {
/** Ex: `'myapp staging'` - create unique name for your local configs: "devin-jan-14" */
APPLICATION_TITLE: getEnvVar('APPLICATION_TITLE'),
// ...
},
}
declare namespace NodeJS {
interface Process {
/** @deprecated use `safeEnv` instead */
env: "Use `safeEnv` from 'src/env' instead."
// Upon typing `process.env.foo` you will get this type error:
// "Property 'foo' does not exist on type '"Use `safeEnv` from 'src/env' instead."'.ts(2339)"
// Ideally we use no-process-env eslint rule,
// but we need support for custom message: https://github.com/mysticatea/eslint-plugin-node/issues/318
}
}
{
"compilerOptions": {
"module": "esnext",
"target": "es2017",
"lib": ["dom", "dom.iterable", "esnext"],
"jsx": "preserve",
"allowJs": true,
"checkJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true
},
"typeRoots": ["./src/global-types", "./node_modules/@types"],
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
"**/*.js",
"**/.*rc.js",
"**/*.jsx"
],
"exclude": [
"node_modules",
".next",
"out",
"public",
"coverage"
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment