Adding CSS and JS Files Via Custom Framework

Question:
So I am making a Framework in Python similar to Flask but instead of HTML it is only Python (as some find it easier this way). I want to be able to add styles but I can’t figure out how to link a CSS and JS file to my app.py file.

Repl link:
https://replit.com/@SalladShooter/VIAL

app.py

from werkzeug.exceptions import HTTPException, NotFound
from werkzeug.wrappers import Request, Response
from werkzeug.serving import run_simple
from werkzeug.routing import Map, Rule
from src import App, route, tags

class MyApp(App):
    def __init__(self):
        self.url_map = Map([
            Rule('/', endpoint='index')
        ])

    def dispatch_request(self, request):
        adapter = self.url_map.bind_to_environ(request.environ)
        try:
            endpoint, args = adapter.match()
            handler = getattr(self, endpoint)
            if handler is None:
                raise NotFound("Endpoint not found")
            return handler(request, **args)
        except HTTPException as e:
            return e
        except Exception as e:
            return Response(f"An error occurred: {str(e)}", status=500)
            
    def index(self, request):
        html_content = []
        list_items = [
            tags.li("Item  1"),
            tags.li("Item  2"),
            tags.li("Item  3")
        ]
        html_content.append(str(tags.ul().add_children(*list_items)))
        html_content.append(str(tags.p("Hello, World!").attribute('class', 'p').id('p').add_children(tags.div())))
        html_content.append(str(tags.h1("Hello, World!").attribute('class', 'h1').id('h1').add_children(tags.div())))
        
        response = Response(html_content, mimetype='text/html')

        return response

    def serve_static(self, filename, directory):
        path = os.path.join(directory, filename)
        if os.path.isfile(path):
            with open(path, 'rb') as f:
                return Response(FileWrapper(f), mimetype=mimetypes.guess_type(path)[0])
        else:
            return NotFound("File not found")

    def __call__(self, environ, start_response):
        request = Request(environ)
        response = self.dispatch_request(request)
        return response(environ, start_response)

if __name__ == '__main__':
    app = MyApp()
    app.url_map.add(Rule('/static/styles.css/css', endpoint='serve_static'))
    run_simple('0.0.0.0',   5000, app)
1 Like

You need to add a rule to serve static files from a dir named ‘static’, it should point to a generic path like /static/<filename> and then use this path to serve any file from the static directory. And update the serve_static method to take a filename parameter.

For example:

import os
import mimetypes #when you serve a file over HTTP, it's important to set the correct MIME type so that the client know how to handle the file.
from wekzeug.wsgi import FileWrapper

class MyApp(App):

    def index(self, request):
        # Link to your CSS and JS files
        css_link = '<link rel="stylesheet" type="text/css" href="/static/styles.css">'
        js_link = '<script src="/static/script.js"></script>'

        html_content = [css_link, js_link]


    def serve_static(self, filename):
        directory = 'static'  # Static files directory
        path = os.path.join(directory, filename)

if __name__ == '__main__':
    app = MyApp()
    app.url_map.add(Rule('/static/<filename>', endpoint='serve_static'))
    run_simple('0.0.0.0', 5000, app)
2 Likes

Hey @WindLother!

Thanks, I tried incorporating what you had but it throws errors (not specifics just 500’s) →

172.31.196.55 - - [09/Feb/2024 20:54:40] "GET / HTTP/1.1" 200 -
172.31.196.55 - - [09/Feb/2024 20:54:40] "GET /static/styles.css HTTP/1.1" 500
172.31.196.55 - - [09/Feb/2024 20:54:40] "GET /static/script.js HTTP/1.1" 500 -

app.py

import mimetypes
from werkzeug.exceptions import HTTPException, NotFound
from werkzeug.wrappers import Request, Response
from werkzeug.serving import run_simple
from werkzeug.routing import Map, Rule
from werkzeug.wsgi import FileWrapper
from src import App, route, tags

class MyApp(App):
    def __init__(self):
        self.url_map = Map([
            Rule('/', endpoint='index')
        ])

    def dispatch_request(self, request):
        adapter = self.url_map.bind_to_environ(request.environ)
        try:
            endpoint, args = adapter.match()
            handler = getattr(self, endpoint)
            if handler is None:
                raise NotFound("Endpoint not found")
            return handler(request, **args)
        except HTTPException as e:
            return e
        except Exception as e:
            return Response(f"An error occurred: {str(e)}", status=500)
            
    def index(self, request):
        css_link = '<link rel="stylesheet" type="text/css" href="/static/styles.css">'
        js_link = '<script src="/static/script.js"></script>'

        html_content = [css_link, js_link]

        list_items = [
            tags.li("Item  1"),
            tags.li("Item  2"),
            tags.li("Item  3")
        ]
        html_content.append(str(tags.ul().add_children(*list_items)))
        html_content.append(str(tags.p("Hello, World!").attribute('class', 'p').id('p').add_children(tags.div())))
        html_content.append(str(tags.h1("Hello, World!").attribute('class', 'h1').id('h1').add_children(tags.div())))
        response = Response(html_content, mimetype='text/html')

        return response

    def serve_static(self, filename, directory):
        path = os.path.join(directory, filename)
        if os.path.isfile(path):
            with open(path, 'rb') as f:
                return Response(FileWrapper(f), mimetype=mimetypes.guess_type(path)[0])
        else:
            return NotFound("File not found")

    def __call__(self, environ, start_response):
        request = Request(environ)
        response = self.dispatch_request(request)
        return response(environ, start_response)

def serve_static(self, filename):
    directory = 'static'  # Static files directory
    path = os.path.join(directory, filename)

if __name__ == '__main__':
    app = MyApp()
    app.url_map.add(Rule('/static/<filename>', endpoint='serve_static'))
    run_simple('0.0.0.0', 5000, app)

You’ve defined serve_static twice in your code. The second definition is outside the MyApp class and incomplete. Remove the second one.

1 Like

@WindLother Thank you, I followed your instructions and did a bit of troubleshooting and it worked!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.