From f24db4a89b34855be41652f3996706a4192121f0 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 9 Sep 2022 11:33:20 -0500 Subject: [PATCH 1/2] implement cache bursting based on http header version In 096eea7, we made use of APIs that require special http headers to be configured on the server. This had a side effect of causing the documentation iframe to not load because the browser would cache the headers of the iframe index.html page. We can work around this by providing a header version to do cache bursting via a query parameter on this page. --- config/webpackDevServer.config.js | 1 + src/app/App.tsx | 3 ++- src/app/constants.ts | 11 +++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/config/webpackDevServer.config.js b/config/webpackDevServer.config.js index 9e1e779d..954e48fb 100644 --- a/config/webpackDevServer.config.js +++ b/config/webpackDevServer.config.js @@ -40,6 +40,7 @@ module.exports = function (proxy, allowedHost) { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': '*', 'Access-Control-Allow-Headers': '*', + // items below required by Pybricks Code app 'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp', }, diff --git a/src/app/App.tsx b/src/app/App.tsx index 434af466..a340327e 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -18,6 +18,7 @@ import Terminal from '../terminal/Terminal'; import Toolbar from '../toolbar/Toolbar'; import Tour from '../tour/Tour'; import { isMacOS } from '../utils/os'; +import { httpServerHeadersVersion } from './constants'; const Docs: React.VFC = () => { const { setIsSettingShowDocsEnabled } = useSettingIsShowDocsEnabled(); @@ -115,7 +116,7 @@ const Docs: React.VFC = () => { contentWindow.document.documentElement.classList.add(Classes.DARK); } }} - src={`static/docs/v${docsPackage.version}/index.html`} + src={`static/docs/v${docsPackage.version}/index.html?v${httpServerHeadersVersion}`} allowFullScreen={true} role="documentation" width="100%" diff --git a/src/app/constants.ts b/src/app/constants.ts index d66af0d3..b30abc89 100644 --- a/src/app/constants.ts +++ b/src/app/constants.ts @@ -56,3 +56,14 @@ export const pybricksCopyright = 'Copyright (c) 2020-2022 The Pybricks Authors'; /** LEGO "fair play" disclaimer */ export const legoDisclaimer = 'LEGO® is a trademark of the LEGO Group of companies which does not sponsor, authorize or endorse this site.'; + +/** + * Provides a version for the required headers of this app. + * + * This is used for cache bursting when the required headers change. + * + * Currently, the following headers are required: + * Cross-Origin-Opener-Policy: same-origin + * Cross-Origin-Embedder-Policy: require-corp + */ +export const httpServerHeadersVersion = 2; From 37527630cf8d5ff36a1b7cd27ed14fd6f432fea4 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Fri, 9 Sep 2022 11:37:37 -0500 Subject: [PATCH 2/2] scripts: new web server script This provides a new script for serving the output of `yarn build`. This is needed since the app now requires special http headers to be defined to use certain web APIs. --- CONTRIBUTING.md | 4 ++-- scripts/serve.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) create mode 100755 scripts/serve.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 81b049dc..2dda5cb7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -118,10 +118,10 @@ So for local testing without https, we need to follow To serve the website, run: yarn build - python3 -m http.server --directory build + ./scripts/serve.py Note: the usual `npx serve` doesn't properly serve parts of the site so we use -Python instead. +a custom Python script instead. Then at `chrome://flags/#unsafely-treat-insecure-origin-as-secure`, add: diff --git a/scripts/serve.py b/scripts/serve.py new file mode 100755 index 00000000..79f49f72 --- /dev/null +++ b/scripts/serve.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 + +""" +Serve the build directory using builtin Python web server. +""" + +import http.server +import pathlib +import socketserver + +BUILD_DIR = (pathlib.Path(__file__).parent.parent / "build").resolve() +PORT = 8000 + + +class Handler(http.server.SimpleHTTPRequestHandler): + def __init__( + self, + request: bytes, + client_address: tuple[str, int], + server: socketserver.BaseServer, + directory: str | None = ... + ) -> None: + super().__init__(request, client_address, server, directory=BUILD_DIR) + + def end_headers(self) -> None: + # custom headers needed for some web API features + self.send_header("Cross-Origin-Opener-Policy", "same-origin") + self.send_header("Cross-Origin-Embedder-Policy", "require-corp") + return super().end_headers() + + +with socketserver.TCPServer(("", PORT), Handler) as httpd: + print(f"serving at http://0.0.0.0:{PORT}") + httpd.serve_forever()