Custom Scripts

Please note that the learning objective for this part of the exercise is the use of custom inline scripts. The specific script used is to expose environment variables following a pattern I still need to write an article about. If you struggle to follow the pattern, don't worry about that. Focus on what it takes to get a custom inline script running.
๐Ÿฆ‰ For this step, you need a little more background info about Remix. In Remix, you have two "bundles" of JavaScript: the server bundle and the client bundle. Each of these has its own "entry" file which is the first file that gets executed when the bundle is loaded. Remix has a default entry file for the server and the client, but you can override these with your own entry files by creating a file named entry.server.tsx or entry.client.tsx in your app directory. We'll be customizing both of these in this exercise, so they've been added.
๐Ÿ‘จโ€๐Ÿ’ผ We want to have some custom dev tools for our app (learn about this concept in Make your own DevTools). We want to make sure we only load these in development mode. So we need a way to dynamically load this into the client during development. We determine whether we're in development based on the environment variable NODE_ENV.
You may be used to using process.env to access environment variables, but the browser doesn't have access to our server's process.env (thank goodness). Instead, we need to explicitly provide those variable's values to our app using 's loader.
๐Ÿงโ€โ™‚๏ธ I added a file which is responsible for ensuring we have the right environment variables in our server and makes it easy to get the environment variables that are public and should be accessible to our UI code.
Remember that UI code runs both on the server and the client. So what we want is something that allows us to have a common global variable that has all the environment variables that are public and should be accessible to our UI code. For example:
function ConnectDiscord() {
	return <a href={getDiscordAuthorizeURL()}>Connect to Discord</a>
}

function getDiscordAuthorizeURL(domainUrl: string) {
	const url = new URL('https://discord.com/api/oauth2/authorize')
	url.searchParams.set('client_id', ENV.DISCORD_CLIENT_ID)
	url.searchParams.set('redirect_uri', `https://example.com/discord/callback`)
	url.searchParams.set('response_type', 'code')
	url.searchParams.set('scope', 'identify guilds.join email guilds')
	return url.toString()
}
๐Ÿงโ€โ™‚๏ธ To do this, I've also created custom and files which override the default entry files for the server and client in Remix.
With the entry.server.tsx, we can take care of the server-side of setting this global variable which I have done on line 6 with:
import { getEnv } from './utils/env.server.ts'

global.ENV = getEnv()
The env.server.ts file we have sets up TypeScript to auto-complete the ENV global variable.
๐Ÿ‘จโ€๐Ÿ’ผ In this part of the exercise, we need to set the global ENV variable on the client. So when our code hydrates we have access to runtime environment variables using the same global variable in either environment (server or client).
Right now, all we need in our app is a MODE environment variable which is development or production.
Effectively, what we need is a script that does this:
window.ENV = { MODE: 'development' }
We can do this in and then we'll use that ENV.MODE variable in to dynamically load some devtools (found in ) when we're in development mode (ENV.MODE === 'development').