Skip to content

Commit

Permalink
Merge pull request #5028 from open-formulieren/feature/sdk-76-use-esm…
Browse files Browse the repository at this point in the history
…-bundle

Opt-in to ESM bundle of SDK
  • Loading branch information
sergei-maertens authored Jan 22, 2025
2 parents a4d0095 + 56a5a55 commit 4a6b8a9
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 11 deletions.
6 changes: 4 additions & 2 deletions src/openforms/forms/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ def sdk_urls(request):
if settings.SDK_RELEASE != "latest":
sdk_path /= settings.SDK_RELEASE

js_path = str(sdk_path / "open-forms-sdk.js")
css_path = str(sdk_path / "open-forms-sdk.css")
umd_bundle_path = str(sdk_path / "open-forms-sdk.js")
esm_bundle_path = str(sdk_path / "open-forms-sdk.mjs")

return {
"sdk_js_url": static(js_path),
"sdk_esm_url": static(esm_bundle_path),
"sdk_umd_url": static(umd_bundle_path),
"sdk_css_url": static(css_path),
"sdk_sentry_dsn": settings.SDK_SENTRY_DSN,
"sdk_sentry_env": settings.SDK_SENTRY_ENVIRONMENT,
Expand Down
2 changes: 1 addition & 1 deletion src/openforms/forms/templates/forms/sdk_info_banner.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% load i18n %}{% if enabled %}
<div class="info-bar">
<span>{% trans "Javascript SDK used" %}</span>
<code>{{ sdk_js_url }}</code>
<code>{{ sdk_umd_url }}</code>
</div>
{% endif %}
24 changes: 20 additions & 4 deletions src/openforms/forms/templates/forms/sdk_snippet.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
{% load openforms %}{% if form %}{% with 'openforms-container' as div_id %}
<div id="{{ div_id }}"></div>
<script src="{{ sdk_js_url }}"></script>
<script nonce="{{ request.csp_nonce }}">
{% load openforms static %}{% if form %}{% with 'openforms-container' as div_id %}
{# Preload the module #}
<link href="{{ sdk_esm_url }}" rel="modulepreload" />
<div
class="open-forms-sdk-root"
id="{{ div_id }}"
data-sdk-module="{{ sdk_esm_url }}"
data-form-id="{{ form.slug }}"
data-base-url="{% api_base_url %}"
data-base-path="{% if base_path %}{{ base_path }}{% else %}{% url 'forms:form-detail' slug=form.slug %}{% endif %}"
data-csp-nonce="{{ request.csp_nonce }}"
{% if sdk_sentry_dsn %}data-sentry-dsn{% endif %}
{% if sdk_sentry_env %}data-sentry-env{% endif %}
></div>
{# Modern browsers support modules, legacy browsers ignore this and use the fallback #}
<script type="module" src="{% static 'sdk-wrapper.mjs' %}"></script>

{# Fallback #}
<script src="{{ sdk_umd_url }}" nomodule></script>
<script nonce="{{ request.csp_nonce }}" nomodule>
const formId = '{{ form.slug|escapejs }}';
const baseUrl = '{% filter escapejs %}{% api_base_url %}{% endfilter %}';
const targetNode = document.getElementById('{{ div_id|escapejs }}');
Expand Down
38 changes: 38 additions & 0 deletions src/openforms/static/sdk-wrapper.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// NOTE - this file must be in the static folder and loaded as type="module", since
// it's intended for modern browsers only and must be ignored by browsers that don't
// natively support modules.

/**
* Given a form node on the page, extract the options from the data-* attributes and
* initialize it.
* @param {HTMLDivElement} node The root node for the SDK where the form must be
* rendered. It must have the expected data attributes.
* @return {Void}
*/
const initializeSDK = async node => {
const {
sdkModule,
formId,
baseUrl,
basePath,
cspNonce,
sentryDsn = '',
sentryEnv = '',
} = node.dataset;
const {OpenForm} = await import(sdkModule);

// initialize the SDK
const options = {
baseUrl,
formId,
basePath,
CSPNonce: cspNonce,
};
if (sentryDsn) options.sentryDSN = sentryDsn;
if (sentryEnv) options.sentryEnv = sentryEnv;
const form = new OpenForm(node, options);
form.init();
};

const sdkNodes = document.querySelectorAll('.open-forms-sdk-root');
sdkNodes.forEach(node => initializeSDK(node));
10 changes: 10 additions & 0 deletions src/openforms/utils/tests/test_sdk_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ def test_sdk_latest(self):
fetch_redirect_response=False,
)

mjs_url = f"{base}open-forms-sdk.mjs"
with self.subTest(js_url=mjs_url):
js_response = self.client.get(mjs_url)

self.assertRedirects(
js_response,
f"{base}1.2.3/open-forms-sdk.mjs",
fetch_redirect_response=False,
)

css_url = f"{base}open-forms-sdk.css"
with self.subTest(css_url=css_url):
css_response = self.client.get(css_url)
Expand Down
13 changes: 9 additions & 4 deletions src/openforms/utils/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,15 @@ class SDKRedirectView(RedirectView):

def get_redirect_url(self, ext: str):
urls = sdk_urls(self.request)
key = f"sdk_{ext}_url"
if key not in urls:
raise BadRequest(f"Invalid extension '{ext}'")
return urls[key]
match ext:
case "js":
return urls["sdk_umd_url"]
case "mjs":
return urls["sdk_esm_url"]
case "css":
return urls["sdk_css_url"]
case _:
raise BadRequest(f"Invalid extension '{ext}'")


class DevViewMixin(LoginRequiredMixin, UserPassesTestMixin):
Expand Down

0 comments on commit 4a6b8a9

Please sign in to comment.