Skip to content

Commit dc26289

Browse files
anoadragon453richvdh
authored andcommitted
Opt for serving new spec JS/CSS dependencies locally instead of downloading from CDNs (#3036)
This PR does two things: * Updates the git submodule for the new spec hugo theme ([google/docsy](https://github.com/google/docsy)) to our fork ([matrix-org/docsy](https://github.com/matrix-org/docsy)) which has a couple changes to load JS from local sources instead of remote, as well as allowing sites to override the URL that font CSS files are loaded from. Note that my definition of "font CSS" files here as CSS files that contain settings and point to locations of where font files (`.woff2`) are located. * Adds a script (and the files generated as a result of running that script) that can take a google fonts URL, download the fonts it points to and spit out those fonts as well as a font CSS file pointing to them for local distribution. We then use the resulting font CSS file in our project variables. This brings the benefit of not serving files from a CDN which can track users across the web, as well as inadvertently pinning docsy to a specific commit. The downside is that we need to remember to update [matrix-org/docsy](https://github.com/matrix-org/docsy) when needed (and apply the patches on top, though they're quite small).
1 parent 41e61b0 commit dc26289

28 files changed

+341
-3
lines changed

.gitmodules

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
[submodule "themes/docsy"]
22
path = themes/docsy
3-
url = https://github.com/google/docsy.git
3+
url = https://github.com/matrix-org/docsy.git
4+
branch = master

assets-hugo/scss/_variables_project.scss

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,9 @@ $warning-background: #FFE0E0;
3333
$table-row-alternate: $secondary-lightest-background;
3434
$table-row-default: $secondary-lighter-background;
3535

36+
/*
37+
Opt to serve fonts locally by overriding web-font-path to be a non-google fonts URL.
38+
This is only possible with our modified docsy theme: https://github.com/matrix-org/docsy
39+
*/
40+
$web-font-path: "../css/fonts/Inter.css";
3641
$google_font_name: "Inter";
37-
$google_font_family: "Inter:300,300i,400,400i,700,700i";

static/css/fonts/Inter.css

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/* cyrillic-ext */
2+
@font-face {
3+
font-family: 'Inter';
4+
font-style: normal;
5+
font-weight: 300;
6+
src: url(../../fonts/Inter-cyrillic-ext-normal-300.woff2);
7+
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
8+
}
9+
/* cyrillic */
10+
@font-face {
11+
font-family: 'Inter';
12+
font-style: normal;
13+
font-weight: 300;
14+
src: url(../../fonts/Inter-cyrillic-normal-300.woff2);
15+
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
16+
}
17+
/* greek-ext */
18+
@font-face {
19+
font-family: 'Inter';
20+
font-style: normal;
21+
font-weight: 300;
22+
src: url(../../fonts/Inter-greek-ext-normal-300.woff2);
23+
unicode-range: U+1F00-1FFF;
24+
}
25+
/* greek */
26+
@font-face {
27+
font-family: 'Inter';
28+
font-style: normal;
29+
font-weight: 300;
30+
src: url(../../fonts/Inter-greek-normal-300.woff2);
31+
unicode-range: U+0370-03FF;
32+
}
33+
/* vietnamese */
34+
@font-face {
35+
font-family: 'Inter';
36+
font-style: normal;
37+
font-weight: 300;
38+
src: url(../../fonts/Inter-vietnamese-normal-300.woff2);
39+
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
40+
}
41+
/* latin-ext */
42+
@font-face {
43+
font-family: 'Inter';
44+
font-style: normal;
45+
font-weight: 300;
46+
src: url(../../fonts/Inter-latin-ext-normal-300.woff2);
47+
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
48+
}
49+
/* latin */
50+
@font-face {
51+
font-family: 'Inter';
52+
font-style: normal;
53+
font-weight: 300;
54+
src: url(../../fonts/Inter-latin-normal-300.woff2);
55+
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
56+
}
57+
/* cyrillic-ext */
58+
@font-face {
59+
font-family: 'Inter';
60+
font-style: normal;
61+
font-weight: 400;
62+
src: url(../../fonts/Inter-cyrillic-ext-normal-400.woff2);
63+
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
64+
}
65+
/* cyrillic */
66+
@font-face {
67+
font-family: 'Inter';
68+
font-style: normal;
69+
font-weight: 400;
70+
src: url(../../fonts/Inter-cyrillic-normal-400.woff2);
71+
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
72+
}
73+
/* greek-ext */
74+
@font-face {
75+
font-family: 'Inter';
76+
font-style: normal;
77+
font-weight: 400;
78+
src: url(../../fonts/Inter-greek-ext-normal-400.woff2);
79+
unicode-range: U+1F00-1FFF;
80+
}
81+
/* greek */
82+
@font-face {
83+
font-family: 'Inter';
84+
font-style: normal;
85+
font-weight: 400;
86+
src: url(../../fonts/Inter-greek-normal-400.woff2);
87+
unicode-range: U+0370-03FF;
88+
}
89+
/* vietnamese */
90+
@font-face {
91+
font-family: 'Inter';
92+
font-style: normal;
93+
font-weight: 400;
94+
src: url(../../fonts/Inter-vietnamese-normal-400.woff2);
95+
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
96+
}
97+
/* latin-ext */
98+
@font-face {
99+
font-family: 'Inter';
100+
font-style: normal;
101+
font-weight: 400;
102+
src: url(../../fonts/Inter-latin-ext-normal-400.woff2);
103+
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
104+
}
105+
/* latin */
106+
@font-face {
107+
font-family: 'Inter';
108+
font-style: normal;
109+
font-weight: 400;
110+
src: url(../../fonts/Inter-latin-normal-400.woff2);
111+
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
112+
}
113+
/* cyrillic-ext */
114+
@font-face {
115+
font-family: 'Inter';
116+
font-style: normal;
117+
font-weight: 700;
118+
src: url(../../fonts/Inter-cyrillic-ext-normal-700.woff2);
119+
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
120+
}
121+
/* cyrillic */
122+
@font-face {
123+
font-family: 'Inter';
124+
font-style: normal;
125+
font-weight: 700;
126+
src: url(../../fonts/Inter-cyrillic-normal-700.woff2);
127+
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
128+
}
129+
/* greek-ext */
130+
@font-face {
131+
font-family: 'Inter';
132+
font-style: normal;
133+
font-weight: 700;
134+
src: url(../../fonts/Inter-greek-ext-normal-700.woff2);
135+
unicode-range: U+1F00-1FFF;
136+
}
137+
/* greek */
138+
@font-face {
139+
font-family: 'Inter';
140+
font-style: normal;
141+
font-weight: 700;
142+
src: url(../../fonts/Inter-greek-normal-700.woff2);
143+
unicode-range: U+0370-03FF;
144+
}
145+
/* vietnamese */
146+
@font-face {
147+
font-family: 'Inter';
148+
font-style: normal;
149+
font-weight: 700;
150+
src: url(../../fonts/Inter-vietnamese-normal-700.woff2);
151+
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
152+
}
153+
/* latin-ext */
154+
@font-face {
155+
font-family: 'Inter';
156+
font-style: normal;
157+
font-weight: 700;
158+
src: url(../../fonts/Inter-latin-ext-normal-700.woff2);
159+
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
160+
}
161+
/* latin */
162+
@font-face {
163+
font-family: 'Inter';
164+
font-style: normal;
165+
font-weight: 700;
166+
src: url(../../fonts/Inter-latin-normal-700.woff2);
167+
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
168+
}

static/css/fonts/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Fonts
2+
3+
## Inter.css
4+
5+
`Inter.css` is a local copy of
6+
https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i, modified to pull
7+
font files (`.woff2`) from local sources. It was created
8+
using `download_google_fonts_css.py`.
9+
10+
## download_google_fonts_css.py
11+
12+
`download_google_fonts_css.py` is a script that takes a google fonts CSS URL, downloads
13+
the file and linked fonts, then saves the fonts locally along with a modified CSS file to
14+
load them. Example call:
15+
16+
```sh
17+
python3 download_google_fonts_css.py \
18+
"https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i" \
19+
../../fonts \
20+
../../fonts
21+
```
22+
23+
Which would pop out a `Inter.css` file that should be `@import url("Inter.css")`d
24+
somewhere in the site's SCSS (currently in
25+
[/assets-hugo/scss/_variables_project.scss](/assets-hugo/scss/_variables_project.scss)).
26+
27+
Re-running the script and committing any new files is only necessary when a desired
28+
font updates (not very often), or we want to change the font we're using. In that case,
29+
remove the existing font files at `/static/fonts/*.woff2` and re-run the script with a
30+
different URL.
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2021 The Matrix.org Foundation C.I.C.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
# This script takes a google fonts CSS URL, downloads the referenced fonts locally
17+
# and spits out a modified CSS file which now points to those local fonts.
18+
#
19+
# Purely for the purposes of converting a website to use local font files instead of
20+
# making requests to Google Fonts.
21+
22+
import re
23+
import requests
24+
import subprocess
25+
import sys
26+
27+
# Pull the font filename to process and output directory to point at
28+
if len(sys.argv) < 4:
29+
print(f"""
30+
Error: Not enough arguments.
31+
32+
Usage: {sys.argv[0]} google_fonts_url font_directory css_font_path
33+
* google fonts url: A URL leading to a google font css file (i.e https://fonts.googleapis.com/css?family=Inter)
34+
* font directory: The location that font files will be downloaded to (i.e ../../fonts)
35+
* font path: The directory the resulting CSS will be pointing to, relative to site root (i.e /unstable/css/fonts).
36+
This is where the browser will look for fonts.
37+
""")
38+
sys.exit(1)
39+
40+
google_fonts_url = sys.argv[1]
41+
font_output_dir = sys.argv[2]
42+
css_font_path = sys.argv[3]
43+
44+
# Get font name
45+
if google_fonts_url.count(":") > 1:
46+
# Account for font weights specified in the URL
47+
# (i.e https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i)
48+
url_match = re.match(r".*family=(.*):", google_fonts_url)
49+
else:
50+
url_match = re.match(r".*family=(.*)", google_fonts_url)
51+
52+
if not url_match:
53+
print("Unable to extract font name, invalid google fonts URL:", google_fonts_url)
54+
print("URL should look something like: https://fonts.googleapis.com/css?family=Inter...")
55+
sys.exit(1)
56+
57+
font_name = url_match.group(1)
58+
59+
# Ensure font paths end with a trailing slash
60+
if not font_output_dir.endswith("/"):
61+
font_output_dir += "/"
62+
if not css_font_path.endswith("/"):
63+
css_font_path += "/"
64+
65+
# Download the css file and split by newline
66+
resp = requests.get(
67+
google_fonts_url,
68+
# We need to set a believable user-agent, else google fonts won't give us
69+
# all of the font weights we requested for some reason
70+
headers={
71+
"User-Agent": "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:86.0) Gecko/20100101 Firefox/86.0"
72+
}
73+
)
74+
if resp.status_code != 200:
75+
print("Failed to download:", google_fonts_url, resp.status_code)
76+
sys.exit(1)
77+
78+
original_contents = resp.text.split("\n")
79+
80+
# Download all referenced font files and write out new font file
81+
new_css_file_lines = []
82+
83+
# Store metadata for helping give friendly names to each font file
84+
font_lang = None
85+
font_family = None
86+
font_style = None
87+
font_weight = 0
88+
for line in original_contents:
89+
# Check if this line contains a font URL
90+
match = re.match(r".*url\((.*)\) format.*", line)
91+
if match:
92+
# Download the font file
93+
font_url = match.group(1)
94+
print("Downloading font:", font_url)
95+
96+
resp = requests.get(font_url)
97+
if resp.status_code == 200:
98+
# Save the font file
99+
filename = "%s-%s-%s-%d.woff2" % (
100+
font_family, font_lang, font_style, font_weight
101+
)
102+
font_filepath = font_output_dir + filename
103+
with open(font_filepath, "w") as f:
104+
print("Writing font file:", font_filepath)
105+
f.write(resp.text)
106+
107+
# Replace google URL with local URL
108+
line = re.sub(r"url\(.+\)", f"url({css_font_path + filename})", line)
109+
else:
110+
print("Warning: failed to download font file:", font_url)
111+
112+
# Check for font metadata. If there is some, we'll note it down and use it to help
113+
# name font files when we write them out.
114+
# Makes for nicer font filenames than fvQtMwCp50KnMw2boKod... etc.
115+
font_lang_match = re.match(r"^/\* (.+) \*/$", line)
116+
if font_lang_match:
117+
font_lang = font_lang_match.group(1)
118+
font_family_match = re.match(r".*font-family: '(.+)';$", line)
119+
if font_family_match:
120+
font_family = font_family_match.group(1)
121+
font_style_match = re.match(r".*font-style: (.+);$", line)
122+
if font_style_match:
123+
font_style = font_style_match.group(1)
124+
font_weight_match = re.match(r".*font-weight: (.+);$", line)
125+
if font_weight_match:
126+
font_weight = int(font_weight_match.group(1))
127+
128+
# Append the potentially modified line to the new css file
129+
new_css_file_lines.append(line)
130+
131+
# Write out the new font css file
132+
with open(font_name + ".css", "w") as f:
133+
new_css_file_contents = "\n".join(new_css_file_lines)
134+
f.write(new_css_file_contents)

static/css/fonts/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
requests
18.3 KB
Binary file not shown.
17.2 KB
Binary file not shown.
18.8 KB
Binary file not shown.
11.9 KB
Binary file not shown.

0 commit comments

Comments
 (0)