Skip to content

BASEPATH not applied to asset configs due to macro scoping bug in @genietools #17

@alex-ten

Description

@alex-ten

Summary

When deploying a Genie app behind an nginx reverse proxy with a subpath (e.g., /projects/genie_apps/), setting ENV["BASEPATH"] before loading GenieFramework does not properly configure asset URLs. Assets are requested without the base path prefix, resulting in 404 errors.

According to the official documentation, setting ENV["BASEPATH"] should automatically configure all asset paths. However, this fails silently due to a macro scoping bug in @genietools.

Environment

  • GenieFramework: v3.0.1
  • Stipple: v0.31.40
  • Julia: 1.12.0
  • Deployment: nginx reverse proxy with path stripping

Nginx Configuration

location /projects/myapp/ {
    proxy_pass http://127.0.0.1:5071/;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
}

Expected Behavior

App code (following documentation):

module App

ENV["BASEPATH"] = "/projects/myapp"

using GenieFramework
@genietools

@app begin
    @in N = 0
    @out msg = ""
    @onchange N begin
        msg = "N = $N"
    end
end

function ui()
    [
        cell([
            p("Enter a number")
            textfield("N", :N)
        ])
        cell([
            bignumber("The value of N is", :N)
        ])
    ]
end

@page("/", ui)
end

Expected result: Asset URLs in generated HTML should include the base path:

<link href="/projects/myapp/stipple.jl/v0.31.40/assets/css/stipplecore.css" rel="stylesheet" />

Actual Behavior

Actual result: Asset URLs are generated without the base path:

<link href="/stipple.jl/v0.31.40/assets/css/stipplecore.css" rel="stylesheet" />

This causes 404 errors for all assets (CSS, JS) and WebSocket connection failures.

Root Cause

When loading the app, the following error appears (caught silently by try/catch):

Loading app┌ Error: 2025-11-26 19:27:16 UndefVarError(:PLUGINS_WITH_ASSETS, 0x000000000000977e, Main.App)
└ @ Main.App ~/.julia/packages/GenieFramework/sLFpM/src/GenieFramework.jl:73

The bug is in /src/GenieFramework.jl at lines 69 and 79:

# Line 69 - inside `__genietools()` function
Genie.Assets.assets_config!([Genie, PLUGINS_WITH_ASSETS..., GenieAutoReload], host = ENV["BASEPATH"])
# Line 79 - inside __genietools() function  
Genie.Assets.assets_config!([Genie, PLUGINS_WITH_ASSETS...], host = Genie.config.cdn_url)

The PLUGINS_WITH_ASSETS constant is defined in the GenieFramework module (line 23), but when the @genietools macro expands, the __genietools() function is defined in the user's module (e.g., Main.App). When this function tries to reference PLUGINS_WITH_ASSETS, it looks for it in Main.App where it doesn't exist, causing an UndefVarError. Compare to line 118 which works correctly:

for plugin in GenieFramework.PLUGINS_WITH_ASSETS  # ← Fully qualified!

The Fix

Change lines 69 and 79 to use the fully qualified module name: Line 69:

# Before (broken):
Genie.Assets.assets_config!([Genie, PLUGINS_WITH_ASSETS..., GenieAutoReload], host = ENV["BASEPATH"])

# After (fixed):
Genie.Assets.assets_config!([Genie, GenieFramework.PLUGINS_WITH_ASSETS..., GenieAutoReload], host = ENV["BASEPATH"])
Line 79:
# Before (broken):
Genie.Assets.assets_config!([Genie, PLUGINS_WITH_ASSETS...], host = Genie.config.cdn_url)

# After (fixed):
Genie.Assets.assets_config!([Genie, GenieFramework.PLUGINS_WITH_ASSETS...], host = Genie.config.cdn_url)

Workaround (until fixed)

Users must manually configure all asset configs after @genietools:

module App

ENV["BASEPATH"] = "/projects/myapp"

using GenieFramework
@genietools

# Manual workaround - should not be necessary!
Genie.config.base_path = ENV["BASEPATH"]
Stipple.assets_config.host = ENV["BASEPATH"]
StippleUI.assets_config.host = ENV["BASEPATH"]
StipplePlotly.assets_config.host = ENV["BASEPATH"]
Genie.Assets.assets_config.host = ENV["BASEPATH"]
StipplePivotTable.assets_config.host = ENV["BASEPATH"]
StippleTable.assets_config.host = ENV["BASEPATH"]
StippleTabs.assets_config.host = ENV["BASEPATH"]
GenieAutoReload.assets_config.host = ENV["BASEPATH"]
Genie.config.websockets_base_path = ENV["BASEPATH"]

# Rest of app...

Related Issues

  • #199 Similar issue reported but not fully diagnosed
  • #10 Related BASEPATH discussion

Testing

I've verified the fix works by editing the local GenieFramework installation and can confirm that with the fully qualified module names, ENV["BASEPATH"] works as documented without requiring manual configuration.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions