Sam Whitmore
Sam Whitmore6mo ago

Q: Marking a Path as External

I've just encountered this error message:
✘ [ERROR] Could not resolve "$env/static/public"

src/lib/api/weather.ts:1:39:
1 │ import { PUBLIC_WEATHER_API_KEY } from '$env/static/public';
╵ ~~~~~~~~~~~~~~~~~~~~

You can mark the path "$env/static/public" as external to exclude it from the bundle, which will
remove this error.
⠋ Preparing Convex functions...
✘ [ERROR] Could not resolve "$env/static/public"

src/lib/api/weather.ts:1:39:
1 │ import { PUBLIC_WEATHER_API_KEY } from '$env/static/public';
╵ ~~~~~~~~~~~~~~~~~~~~

You can mark the path "$env/static/public" as external to exclude it from the bundle, which will
remove this error.
✘ [ERROR] Could not resolve "$env/static/public"

src/lib/api/weather.ts:1:39:
1 │ import { PUBLIC_WEATHER_API_KEY } from '$env/static/public';
╵ ~~~~~~~~~~~~~~~~~~~~

You can mark the path "$env/static/public" as external to exclude it from the bundle, which will
remove this error.
⠋ Preparing Convex functions...
✘ [ERROR] Could not resolve "$env/static/public"

src/lib/api/weather.ts:1:39:
1 │ import { PUBLIC_WEATHER_API_KEY } from '$env/static/public';
╵ ~~~~~~~~~~~~~~~~~~~~

You can mark the path "$env/static/public" as external to exclude it from the bundle, which will
remove this error.
From this code:
export const add = mutation({
args: {
quant: v.number(),
qual: v.string(),
user: v.string(),
latitude: v.string(),
longitude: v.string()
},
handler: async (ctx, args) => {
const weather = (await getWeatherInformationFromCoordinates(
args.latitude,
args.longitude
)) as WeatherAPIData;
return await ctx.db.insert('responses', {
user: 'Sam',
quant: args.quant,
qual: args.qual,
latitude: args.latitude,
longitude: args.longitude,
country: weather.location.country,
region: weather.location.region,
datetime: new Date().toJSON(),
isDay: weather.current.is_day,
weather: weather.current.condition.text,
cloudCover_percent: weather.current.cloud,
humidity_percent: weather.current.humidity,
heatIndex_C: weather.current.heatindex_c,
temp_C: weather.current.temp_c,
tempFeelsLike_C: weather.current.feelslike_c
});
}
export const add = mutation({
args: {
quant: v.number(),
qual: v.string(),
user: v.string(),
latitude: v.string(),
longitude: v.string()
},
handler: async (ctx, args) => {
const weather = (await getWeatherInformationFromCoordinates(
args.latitude,
args.longitude
)) as WeatherAPIData;
return await ctx.db.insert('responses', {
user: 'Sam',
quant: args.quant,
qual: args.qual,
latitude: args.latitude,
longitude: args.longitude,
country: weather.location.country,
region: weather.location.region,
datetime: new Date().toJSON(),
isDay: weather.current.is_day,
weather: weather.current.condition.text,
cloudCover_percent: weather.current.cloud,
humidity_percent: weather.current.humidity,
heatIndex_C: weather.current.heatindex_c,
temp_C: weather.current.temp_c,
tempFeelsLike_C: weather.current.feelslike_c
});
}
34 Replies
Sam Whitmore
Sam WhitmoreOP6mo ago
How can I refactor my code to avoid this error? My initial thought is to mark that path as external, and I'm struggling to do that. Further research also seems to show that I ought to separate my API fetch call from my mutation function, placing it within an Action rather than the Mutation... Is this the real solution? and if so, how can I achieve this?
ballingt
ballingt6mo ago
Is this a Svelte thing, the dollar sign env?
Sam Whitmore
Sam WhitmoreOP6mo ago
Yes 😅
ballingt
ballingt6mo ago
if there's no actual file called $env/static/public then it might be only something you can use in .svelte files
ballingt
ballingt6mo ago
No description
ballingt
ballingt6mo ago
This sounds like it's a substitution made by the Svelte bundler, but Convex uses esbuild so doesn't have this behavior built in not just in .svelte files, but it does need to be processed by the Svelte bundler
Sam Whitmore
Sam WhitmoreOP6mo ago
okay, so I ought to substitute in the older (and more conventional) replacement for $env/static/... this would look something like process.env...., yeah?
ballingt
ballingt6mo ago
As esbuild is configured in the Convex CLI there's no macro-like syntax for substituting in env vars, instead all environment variables are runtime lookups that you need to add to the Convex dashboard:
No description
ballingt
ballingt6mo ago
It's something we could add if there's demand, but right now process.env.FOO is always a runtime lookup, not a bundler substitution.
Sam Whitmore
Sam WhitmoreOP6mo ago
So I ought to add PUBLIC_WEATHER_API_KEY to my Convex team's Environment Variables within Settings?
ballingt
ballingt6mo ago
Yeah side note, anything starting with PUBLIC_ sounds like it's a client-side thing
Sam Whitmore
Sam WhitmoreOP6mo ago
Will I need to do anything else on my codebase's side?
ballingt
ballingt6mo ago
but makes sense you might also need it on the server no, just `process.env.PUBLIC_WHEATHER_API_KEY and if you use preview deployments or have teammates joining the project, you might add this environment variable to the project's defaulst
Sam Whitmore
Sam WhitmoreOP6mo ago
I figured I was calling my function whenever my user clicks submit, so that would be needed on the PUBLIC side
ballingt
ballingt6mo ago
Ah that's true, yes it runs when someone clicks the button — but it runs on the server!
Sam Whitmore
Sam WhitmoreOP6mo ago
one of these days I'll surely be extending the scope of the team beyond one – so yeah, that's a greta idea
ballingt
ballingt6mo ago
All your Convex functions only run on your Convex deployment, not in the browser
Sam Whitmore
Sam WhitmoreOP6mo ago
oh okay – I'll remove the PUBLIC then 🙂
ballingt
ballingt6mo ago
yeah my understanding of SvelteKit convention is PUBLIC_ ones are the ones sent to the browser — so if it's a secret API key it shouldn't be public.
Sam Whitmore
Sam WhitmoreOP6mo ago
am I still importing this at the top of my function: import { WEATHER_API_KEY } from 'process.env'; or is it more of a:
const WEATHER_API_KEY = process.env.WEATHER_API_KEY
const WEATHER_API_KEY = process.env.WEATHER_API_KEY
type of deal?
ballingt
ballingt6mo ago
yeah the latter
Sam Whitmore
Sam WhitmoreOP6mo ago
I'm now getting a 500 error because 'process is not defined'
Sam Whitmore
Sam WhitmoreOP6mo ago
oh hahaha within a folder/folder/file titled $lib/api/weather.ts I suppose I ought to remove it from $lib
ballingt
ballingt6mo ago
You can import from here, but it will be the Convex esbuild bundler processing this file instead of the Svelte bundler so anything imported from both places has to work with both syntaxes
Sam Whitmore
Sam WhitmoreOP6mo ago
Is it worth writing the code twice then, once for each format? or can I throw an WEATHER_API_KEY || PUBLIC_WEATHER_API_KEY (for argument's sake)
ballingt
ballingt6mo ago
ideally as little code as possible twice, I think I'd make WEATHER_API_KEY an argument to a function but yeah you can absolutely write it twice, it might be different eventually It sounds sort of unusual to need it both places, but that could make sense if you're doing some API calls from your Svelte backend and some from Convex functions
Sam Whitmore
Sam WhitmoreOP6mo ago
It's a repeated survey where each response fetches the user's local weather data as context for their response, so it's quite possible that I'll want to include the weather data on each submission and also whenever the user is signed in (without responing to the survey) too man, this is frustrating hahaha Should I (re)write it within convex/responses.ts since that's where my mutation function is that adds each survey response?
ballingt
ballingt6mo ago
if you're using an API key then it's probably an action that's making the API call yeah? yeah that sounds reasonable, although there's no need to duplicate. Anywhere you like you can write a function like
async getWeather(apiKey, where) {
const response = await fetch('https://weather-company.com/weather', {
method: "GET",
headers: {
"X-Auth-Token": apiKey,
"Content-Type": "application/json"
}
});
return await response.json();
}
async getWeather(apiKey, where) {
const response = await fetch('https://weather-company.com/weather', {
method: "GET",
headers: {
"X-Auth-Token": apiKey,
"Content-Type": "application/json"
}
});
return await response.json();
}
and the in lib/api/weather.ts you can call that with your $env/static/public value and in the convex folder you can write an action that calls that function with process.env.KEY
Sam Whitmore
Sam WhitmoreOP6mo ago
THATS SO ELEGANT man, coding is such a cooll hobby hahaha after all that, my console is now asking me to place the fetch within an Action rather than within my queries/mutations
ballingt
ballingt6mo ago
yeah mutations and queries just read/write data and transform it deterministically, no network calls similar to SQL
Sam Whitmore
Sam WhitmoreOP6mo ago
How can I plug my WEATHER_API_KEY (now stored within my convex dashboard) within my action that I'm writing?
ian
ian6mo ago
process.env.WEATHER_API_KEY from inside convex code
Sam Whitmore
Sam WhitmoreOP6mo ago
Tom, you're a legend I've been able to set up an initial mutation to insert my user's survey response which then triggers an internalAction to fetch the Weather API data which triggers an internalMutation to patch the initial insertion with the contextual weather data. Thank you so much!

Did you find this page helpful?