Current section: Scripting 7 exercises

Exposing Environment Variables in a Web Application


00:00 Let's go to our root.tsx and here we're going to have to in our loader access all of the environment variables. So, actually what I'm going to do is add a console.log, we need an L right there, env,

00:17 save that, and I'm going to pull up our output from the playground here. So I refresh and we get our mode development. So that's the terminal output from the workshop app that is running right now. So perfect, that's exactly what we would expect.

00:33 If I were to move that into our app and save this here, then we should actually get that output as well right here, but the client isn't super jazzed about this. It's saying env is not defined. Now TypeScript is actually okay with env because we have it all set up.

00:49 If I dive into where this is, we've declared that here, but we haven't actually set this up quite yet to work. That's the job that we're trying to accomplish here. So the point is that we can't just magically get the process env variables over to the client. We have to send them.

01:06 And so to do that, we're going to add an env property that calls getenv. Technically we can actually also do it this way because env is global, but I evaluated

01:19 that and I feel better about calling getenv here just because it feels more obvious what's going on. So now that we have our env there, we can actually say data.env right here, and if I refresh and take a look at the console output, we've got our mode development right there.

01:38 And then also in our terminal output, we get that mode development right there as well. So the last thing we need to do to make this data env accessible as just simply env on both the client as well as the server is we come down here and add a script tag.

01:54 So script, and we're going to say dangerously set inner HTML. That's going to have a property called HTML. They make it really intentionally difficult to do this because it is technically a dangerous thing.

02:07 If you were to put some user submitted information or data into this, then the user could actually implement what is known as a cross-site scripting vulnerability. So they could steal your user's data and all sorts of terrible things.

02:25 Go look up cross-site scripting. The React protects us from that automatically, and we have to opt out of that protection by using dangerously set inner HTML. But again, the only time that's ever a danger is if you're using user submitted data in

02:43 the contents here, and we are not. This data.env is controlled by us, and so we're safe. Okay, so what we're doing here is we're saying window.env equals the stringified version of our data.env. So on the server render, actually, let's take a look at what the server render looks like.

03:00 env equals right here. Where's our window.env? Oh, I need to save the file first. There we go. So window.env is right there, equals the JSON stringified version of our env.

03:16 So now, when all of this gets evaluated before our JavaScript actually runs and hydrates and all that stuff, we now have a window.env variable that we can use anywhere. And because we have this set up in our entry server as well, we can just use simply env,

03:34 and now we'll have access to all of our environment variables that we expose to both the client and the server just on that global. This is why there's this big warning to only add environment variables that you're comfortable sending to the client, because now we are.

03:50 We could have a super secret, and we'd say whatever, and we save that, and boom, now that's headed off to the client. Where's my window.env? There it is. Here, try that again. Super secret. Whatever. Not good.

04:09 Make sure to not send anything super secret there. Okay, so with that set up now, I can get rid of this, and we can go back to here and take a look at our console log of the all caps env, so now we have access to that.

04:26 All right, so again, the primary learning outcome from this exercise is for you to learn how to do this, to have some dynamic scripts as needed. But we're also going to use this for something practical as well, and that is in our entry

04:42 client before this JavaScript evaluates, we'll have this inline script be evaluated, and so we're able to access env, so we'll say if env.mode is development, then we're going

04:57 to do a dynamic import of our DevTools file, and then we'll call init on that DevTools file. And so with that, we have DevTools initialized.

05:11 And so then DevTools or custom DevTools can be quite handy, and so I do recommend building out something like this for your organization, whatever you're doing, and I linked to a blog post that you can take a look at some of the ideas of things that you can do with custom DevTools.

05:30 But this is only possible because we have access to our environment variables that we're okay exposing to the client, and we're keying off of that to know whether or not we want to bring in those DevTools. If we were anything else, then we're not going to bring in those DevTools at all, because

05:47 this is dynamically imported, so we don't have to worry about bringing them in unnecessarily. And that is how you get some custom scripts running for whatever custom thing you want to do. Another thing you might consider that we're not going to do, but another thing you could

06:04 do if you wanted to do something like this, like an alternative mechanism for doing what we just did, is to do a script source and then resources and env thing, and then you can make a resource route that handles this as well.

06:21 So you've got some options there, but I'm pretty happy with this, so we're going to stick with that. I hope that helps with the goals that you have for yourself, and I hope you had a good time with that exercise. I know it was a little bit bigger than some of the other ones, a lot of extra context,

06:36 but hopefully that gives you an idea of some of the different pieces that make up our client and server connections here.