Skip to content

Commit 344644d

Browse files
committed
Add frontend asset serving based on h-assets package
Enable Via to serve static frontend assets using the same setup as we use in the h and lms apps.
1 parent d33eece commit 344644d

File tree

12 files changed

+150
-14
lines changed

12 files changed

+150
-14
lines changed

Dockerfile

+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
# Stage 1: Build frontend assets
2+
FROM node:19.8.1-alpine as frontend-build
3+
4+
ENV NODE_ENV production
5+
COPY .babelrc rollup.config.mjs gulpfile.mjs package.json yarn.lock ./
6+
COPY via/static ./via/static
7+
8+
RUN yarn install --frozen-lockfile
9+
RUN yarn build
10+
11+
# Stage 2: Build the rest of the app using build output from Stage 1.
12+
113
# Unlike most Hypothesis projects this Docker image is based on Debian,
214
# so it can use glibc's DNS resolver which supports TCP retries. It can be
315
# reverted back to Alpine when Musl v1.2.4 is released.
@@ -24,6 +36,9 @@ COPY requirements/requirements.txt ./
2436
RUN pip install --no-cache-dir -U pip \
2537
&& pip install --no-cache-dir -r requirements.txt
2638

39+
# Copy frontend assets.
40+
COPY --from=frontend-build /build build
41+
2742
COPY ./conf/supervisord.conf ./conf/supervisord.conf
2843
COPY ./conf/nginx/nginx.conf /etc/nginx/nginx.conf
2944
COPY ./conf/nginx/includes /etc/nginx/includes

requirements/dev.txt

+20-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
# This file is autogenerated by pip-compile with Python 3.8
33
# by the following command:
44
#
5-
# pip-compile requirements/dev.in
5+
# pip-compile --allow-unsafe requirements/dev.in
66
#
7+
appnope==0.1.3
8+
# via ipython
79
asttokens==2.2.1
810
# via stack-data
911
attrs==20.3.0
@@ -72,6 +74,8 @@ google-auth-oauthlib==1.0.0
7274
# via -r requirements/requirements.txt
7375
gunicorn==20.1.0
7476
# via -r requirements/requirements.txt
77+
h-assets==1.0.5
78+
# via -r requirements/requirements.txt
7579
h-pyramid-sentry==1.2.4
7680
# via -r requirements/requirements.txt
7781
h-vialib==1.1.0
@@ -196,6 +200,7 @@ pyparsing==3.0.7
196200
pyramid==2.0
197201
# via
198202
# -r requirements/requirements.txt
203+
# h-assets
199204
# h-pyramid-sentry
200205
# pyramid-exclog
201206
# pyramid-ipython
@@ -321,5 +326,17 @@ zope-interface==5.2.0
321326
# wired
322327

323328
# The following packages are considered to be unsafe in a requirements file:
324-
# pip
325-
# setuptools
329+
pip==23.1.2
330+
# via pip-tools
331+
setuptools==67.7.2
332+
# via
333+
# -r requirements/requirements.txt
334+
# gunicorn
335+
# jsonschema
336+
# pastedeploy
337+
# pip-tools
338+
# plaster
339+
# pyramid
340+
# supervisor
341+
# zope-deprecation
342+
# zope-interface

requirements/functests.txt

+17-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# This file is autogenerated by pip-compile with Python 3.8
33
# by the following command:
44
#
5-
# pip-compile requirements/functests.in
5+
# pip-compile --allow-unsafe requirements/functests.in
66
#
77
attrs==20.3.0
88
# via
@@ -51,6 +51,8 @@ google-auth-oauthlib==1.0.0
5151
# via -r requirements/requirements.txt
5252
gunicorn==20.1.0
5353
# via -r requirements/requirements.txt
54+
h-assets==1.0.5
55+
# via -r requirements/requirements.txt
5456
h-matchers==1.2.15
5557
# via -r requirements/functests.in
5658
h-pyramid-sentry==1.2.4
@@ -153,6 +155,7 @@ pyparsing==3.0.7
153155
pyramid==2.0
154156
# via
155157
# -r requirements/requirements.txt
158+
# h-assets
156159
# h-pyramid-sentry
157160
# pyramid-exclog
158161
# pyramid-jinja2
@@ -256,5 +259,16 @@ zope-interface==5.2.0
256259
# wired
257260

258261
# The following packages are considered to be unsafe in a requirements file:
259-
# pip
260-
# setuptools
262+
pip==23.1.2
263+
# via pip-tools
264+
setuptools==67.7.2
265+
# via
266+
# -r requirements/requirements.txt
267+
# gunicorn
268+
# jsonschema
269+
# pastedeploy
270+
# pip-tools
271+
# plaster
272+
# pyramid
273+
# zope-deprecation
274+
# zope-interface

requirements/lint.txt

+22-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# This file is autogenerated by pip-compile with Python 3.8
33
# by the following command:
44
#
5-
# pip-compile requirements/lint.in
5+
# pip-compile --allow-unsafe requirements/lint.in
66
#
77
astroid==2.15.2
88
# via pylint
@@ -85,6 +85,10 @@ gunicorn==20.1.0
8585
# via
8686
# -r requirements/requirements.txt
8787
# -r requirements/tests.txt
88+
h-assets==1.0.5
89+
# via
90+
# -r requirements/requirements.txt
91+
# -r requirements/tests.txt
8892
h-matchers==1.2.15
8993
# via -r requirements/tests.txt
9094
h-pyramid-sentry==1.2.4
@@ -234,6 +238,7 @@ pyramid==2.0
234238
# via
235239
# -r requirements/requirements.txt
236240
# -r requirements/tests.txt
241+
# h-assets
237242
# h-pyramid-sentry
238243
# pyramid-exclog
239244
# pyramid-jinja2
@@ -389,5 +394,19 @@ zope-interface==5.2.0
389394
# wired
390395

391396
# The following packages are considered to be unsafe in a requirements file:
392-
# pip
393-
# setuptools
397+
pip==23.1.2
398+
# via
399+
# -r requirements/tests.txt
400+
# pip-tools
401+
setuptools==67.7.2
402+
# via
403+
# -r requirements/requirements.txt
404+
# -r requirements/tests.txt
405+
# gunicorn
406+
# jsonschema
407+
# pastedeploy
408+
# pip-tools
409+
# plaster
410+
# pyramid
411+
# zope-deprecation
412+
# zope-interface

requirements/requirements.in

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
gunicorn
22
checkmatelib
3+
h-assets
34
h-pyramid-sentry
45
h-vialib
56
importlib_resources

requirements/requirements.txt

+13-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# This file is autogenerated by pip-compile with Python 3.8
33
# by the following command:
44
#
5-
# pip-compile requirements/requirements.in
5+
# pip-compile --allow-unsafe requirements/requirements.in
66
#
77
attrs==20.3.0
88
# via jsonschema
@@ -28,6 +28,8 @@ google-auth-oauthlib==1.0.0
2828
# via -r requirements/requirements.in
2929
gunicorn==20.1.0
3030
# via -r requirements/requirements.in
31+
h-assets==1.0.5
32+
# via -r requirements/requirements.in
3133
h-pyramid-sentry==1.2.4
3234
# via -r requirements/requirements.in
3335
h-vialib==1.1.0
@@ -82,6 +84,7 @@ pyparsing==3.0.7
8284
pyramid==2.0
8385
# via
8486
# -r requirements/requirements.in
87+
# h-assets
8588
# h-pyramid-sentry
8689
# pyramid-exclog
8790
# pyramid-jinja2
@@ -148,4 +151,12 @@ zope-interface==5.2.0
148151
# wired
149152

150153
# The following packages are considered to be unsafe in a requirements file:
151-
# setuptools
154+
setuptools==67.7.2
155+
# via
156+
# gunicorn
157+
# jsonschema
158+
# pastedeploy
159+
# plaster
160+
# pyramid
161+
# zope-deprecation
162+
# zope-interface

requirements/tests.txt

+17-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# This file is autogenerated by pip-compile with Python 3.8
33
# by the following command:
44
#
5-
# pip-compile requirements/tests.in
5+
# pip-compile --allow-unsafe requirements/tests.in
66
#
77
attrs==20.3.0
88
# via
@@ -57,6 +57,8 @@ google-auth-oauthlib==1.0.0
5757
# via -r requirements/requirements.txt
5858
gunicorn==20.1.0
5959
# via -r requirements/requirements.txt
60+
h-assets==1.0.5
61+
# via -r requirements/requirements.txt
6062
h-matchers==1.2.15
6163
# via -r requirements/tests.in
6264
h-pyramid-sentry==1.2.4
@@ -159,6 +161,7 @@ pyparsing==3.0.7
159161
pyramid==2.0
160162
# via
161163
# -r requirements/requirements.txt
164+
# h-assets
162165
# h-pyramid-sentry
163166
# pyramid-exclog
164167
# pyramid-jinja2
@@ -267,5 +270,16 @@ zope-interface==5.2.0
267270
# wired
268271

269272
# The following packages are considered to be unsafe in a requirements file:
270-
# pip
271-
# setuptools
273+
pip==23.1.2
274+
# via pip-tools
275+
setuptools==67.7.2
276+
# via
277+
# -r requirements/requirements.txt
278+
# gunicorn
279+
# jsonschema
280+
# pastedeploy
281+
# pip-tools
282+
# plaster
283+
# pyramid
284+
# zope-deprecation
285+
# zope-interface

tests/unit/via/assets_test.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from via.assets import includeme
2+
3+
4+
def test_includeme(pyramid_config):
5+
includeme(pyramid_config)
6+
7+
assets_env = pyramid_config.registry["assets_env"]
8+
assert assets_env.assets_base_url == "/assets"

via/app.py

+9
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@
3030
}
3131

3232

33+
def configure_jinja2_assets(config):
34+
jinja2_env = config.get_jinja2_environment()
35+
jinja2_env.globals["asset_url"] = config.registry["assets_env"].url
36+
jinja2_env.globals["asset_urls"] = config.registry["assets_env"].urls
37+
38+
3339
def load_settings(settings):
3440
"""Load application settings from a dict or environment variables.
3541
@@ -65,6 +71,7 @@ def create_app(_=None, **settings):
6571
config.include("pyramid_services")
6672
config.include("h_pyramid_sentry")
6773

74+
config.include("via.assets")
6875
config.include("via.views")
6976
config.include("via.services")
7077

@@ -84,6 +91,8 @@ def create_app(_=None, **settings):
8491
# Add this as near to the end of your config as possible:
8592
config.include("pyramid_sanity")
8693

94+
config.action(None, configure_jinja2_assets, args=(config,))
95+
8796
app = WhiteNoise(
8897
config.make_wsgi_app(),
8998
index_file=True,

via/assets.ini

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[bundles]
2+
3+
video_player_js =
4+
scripts/video_player.bundle.js

via/assets.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""View for serving static assets under `/assets`."""
2+
3+
import importlib_resources
4+
from h_assets import Environment, assets_view
5+
6+
7+
def includeme(config):
8+
# Auto reload asset manifest when it changes in development.
9+
auto_reload = config.registry.settings["dev"]
10+
via_files = importlib_resources.files("via")
11+
12+
assets_env = Environment(
13+
assets_base_url="/assets",
14+
bundle_config_path=via_files / "assets.ini",
15+
manifest_path=via_files / "../build/manifest.json",
16+
auto_reload=auto_reload,
17+
)
18+
19+
# Store asset environment in registry for use in registering `asset_urls`
20+
# Jinja2 helper in `app.py`.
21+
config.registry["assets_env"] = assets_env
22+
23+
config.add_view(route_name="assets", view=assets_view(assets_env))

via/views/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
def add_routes(config): # pragma: no cover
66
"""Add routes to pyramid config."""
77

8+
config.add_route("assets", "/assets/*subpath")
89
config.add_route("index", "/", factory=QueryURLResource)
910
config.add_route("get_status", "/_status")
1011
config.add_route("view_pdf", "/pdf", factory=QueryURLResource)

0 commit comments

Comments
 (0)