hypothesis / h-assets

Pyramid views for serving collections of compiled static assets
BSD 2-Clause "Simplified" License
0 stars 0 forks source link

h-assets

Pyramid views for serving collections of compiled static assets (eg. bundles of JavaScript and CSS).

Compared to Pyramid's builtin static asset functionality , this provides a convenient way to serve assets based on certain assumptions about how assets are generated and opinions about how they should be served:

Additionally h-assets provides a way to define collections (bundles) of assets and methods to generate cache-busted URLs for all assets in the bundle. This is useful for example to render all the <script> or <style> tags that are needed by a certain part of a site.

Usage

Using h-assets in a Pyramid project involves three steps:

  1. Prepare the compiled assets for use with h-assets
  2. During Pyramid application configuration, create an asset Environment to handle asset URL generation and register a view to serve assets from that environment
  3. Expose the URL-generation methods from the asset Environment to your templating system so that templates can generate asset URLs

Preparing assets for use with h-assets

  1. Set up a process to compile or copy assets from source files into an output directory. Conventionally Hypothesis projects use a folder called build in the repository root.

  2. In the output directory generate a JSON manifest file (eg. manifest.json) that maps asset paths to URLs with cache-busting query strings. Example content:

    {
     "scripts/app.bundle.js": "scripts/app.bundle.js?abcdef",
     "scripts/vendor.bundle.js": "scripts/vendor.bundle.js?xyz123"
    }

    Any format is allowed for the cache-buster. Hypothesis projects typically use the first few characters of a hash (eg. SHA-1) of the file's contents.

  3. Create an INI file (eg. assets.ini) that defines collections ("bundles") of assets that are used together. Example content:

    [bundles]
    
    frontend_apps_js =
     scripts/browser_check.bundle.js
     scripts/frontend_apps.bundle.js
    
    frontend_apps_css =
     styles/frontend_apps.css

Registering a Pyramid view to serve assets

To serve assets using h-assets, a Pyramid view needs to be created using the assets_view function.

In the Pyramid app configuration, define a route where the URL is a base URL followed by a *subpath:

def includeme(config):
    config.add_route("assets", "/assets/*subpath")

To register the view associated with this route, first create an Environment to handle generation of asset URLs. Then use assets_view to create the view callable for use with config.add_view:

import os.path

from h_assets import Environment, assets_view

def includeme(config):
    # This assumes the following repository structure:
    #   build/ - Compiled frontend assets
    #     manifest.json
    #   projectname/
    #     assets.py - This module
    #     routes.py - Route definitions
    #     assets.ini
    root_dir = os.path.dirname(__file__)

    assets_env = Environment(
        assets_base_url="/assets",
        bundle_config_path="{root_dir}/assets.ini",
        manifest_path=f"{root_dir}/../build/manifest.json",
    )

    # Store asset environment in registry for use in registering `asset_urls`
    # Jinja2 helper in `app.py`.
    config.registry["assets_env"] = assets_env

    config.add_view(route_name="assets", view=assets_view(assets_env))

Referencing assets in templates

To get a list of asset URLs for assets in a bundle, use the urls method of the asset Environment. A common pattern is to expose these methods as global helpers in the templating environment being used to generate HTML responses. For example, in a project using pyramid_jinja2:

jinja2_env = config.get_jinja2_environment()
jinja2_env.globals["asset_url"] = config.registry["assets_env"].url
jinja2_env.globals["asset_urls"] = config.registry["assets_env"].urls

Then a template can generate URLs using:

{% for url in asset_urls("frontend_apps_js") %}
  <script async defer src="https://github.com/hypothesis/h-assets/raw/main/{{ url }}"></script>
{% endfor %}

Setting up Your h-assets Development Environment

First you'll need to install:

Then to set up your development environment:

git clone https://github.com/hypothesis/h-assets.git
cd h-assets
make help

Releasing a New Version of the Project

  1. First, to get PyPI publishing working you need to go to: https://github.com/organizations/hypothesis/settings/secrets/actions/PYPI_TOKEN and add h-assets to the PYPI_TOKEN secret's selected repositories.

  2. Now that the h-assets project has access to the PYPI_TOKEN secret you can release a new version by just creating a new GitHub release. Publishing a new GitHub release will automatically trigger a GitHub Actions workflow that will build the new version of your Python package and upload it to https://pypi.org/project/h-assets.

Changing the Project's Python Versions

To change what versions of Python the project uses:

  1. Change the Python versions in the cookiecutter.json file. For example:

    "python_versions": "3.10.4, 3.9.12",
  2. Re-run the cookiecutter template:

    make template
  3. Commit everything to git and send a pull request

Changing the Project's Python Dependencies

To change the production dependencies in the setup.cfg file:

  1. Change the dependencies in the .cookiecutter/includes/setuptools/install_requires file. If this file doesn't exist yet create it and add some dependencies to it. For example:

    pyramid
    sqlalchemy
    celery
  2. Re-run the cookiecutter template:

    make template
  3. Commit everything to git and send a pull request

To change the project's formatting, linting and test dependencies:

  1. Change the dependencies in the .cookiecutter/includes/tox/deps file. If this file doesn't exist yet create it and add some dependencies to it. Use tox's factor-conditional settings to limit which environment(s) each dependency is used in. For example:

    lint: flake8,
    format: autopep8,
    lint,tests: pytest-faker,
  2. Re-run the cookiecutter template:

    make template
  3. Commit everything to git and send a pull request