Persistent copyright & licensing information in client-side JavaScript, CSS and similar – feedback and second proposal
At FOSDEM 2025 I presented my (intentionally controversial) proposal how to keep copyright and licensing info in minified JS/CSS and asked for feedback, including from front-end developers.
Two months later, I took the feedback from FOSDEM and held a small workshop session with a group consisting of OSPO leaders, FOSS lawyers and a handful of FOSS developers at LLW 2025.
This blog post was finished1 more than a year after both, so I will not be summarizing my FOSDEM talk, and suggest you listen to it (esp. the Q&A part), if you are interested in the details.
But I will summarize the results of both sessions below.
Are SDPX IDs enough for compliance or not (given their templating)¶
Someone argued that for certain licenses – specifically, e.g. the MIT and BSD family – even the SPDX License List has a some templating in place, and as such identifying it with just an SPDX ID would not fulfil the license obligations, by strict reading of the license.
That is a concern that I identified already in my original proposal and I agree that my proposed approach has a certain amount of “handwaving”, which is not 100% risk-proof.
(Spoiler: we fix this issue in the final proposal. Wait for the next blog post in this series.)
Impact on size of the minifed code¶
A common concern from web developers was how much keeping the SPDX/REUSE tags in the minified code would impact the its size.
With the help of the wonderful Lukas Taegert-Atkinson of Rollup fame, we managed to get a good idea what the impact adding REUSE/SPDX tags to all the files would have on the size of the minified code.
As an PoC Lukas made the following change to the build process of Rollup Browser, so we could compare the size of the minified code before and after the diff.
diff --git a/rollup.config.ts b/rollup.config.ts
--- a/rollup.config.ts (revision 384d5333fbc3d8918b41856822376da2a65ccaa3)
+++ b/rollup.config.ts (date 1742569205307)
@@ -152,7 +152,22 @@
collectLicensesBrowser(),
writeLicenseBrowser(),
cleanBeforeWrite('browser/dist'),
- emitWasmFile()
+ emitWasmFile(),
+ {
+ name: 'add-fake-tags',
+ transform(code) {
+ return {
+ code: `/*!
+* SPDX-SnippetBegin
+* SPDX-SnippetCopyrightText: © 2021 Test Dummy <dummy@test.example>
+* SPDX-License-Identifier: BSD-2-Clause
+*/
+${code}
+/*! SPDX-SnippetEnd */`,
+ map: { mappings: '' }
+ };
+ }
+ }
],
strictDeprecations: true,
treeshake
If Rollup Browser was built as per default, the full minified code resulted in 374 KiB.
After the patch that caused (dummy) snippet-level SPDX tags to be inserted into all the code (Rollup itself and its dependencies), the size grew to 415 KiB though.
That is a 11% increase in size. Not exactly negligible, but definitely far from terrible. And if tooling were to be updated, with de-duplication we could possibly take that number down quite a bit too.
In the previous tiny Svelte + Rollup + Terser PoC, both with and without SPDX tags are 12 KiB, so we need take a magnifying glass to compare 12.681 bytes with tags, and 12.324 bytes without them – that is just a 3% difference.
And in the previous React Scripts (+ WebPack + Terser) PoC, the overall build size is virtually unchanged, but oddly enough while some files become bigger, others become smaller.
With REUSE tags, the total size of build/static/ is 536 KiB (specifically, 531.070 bytes):
build/static/css:
.rw-r--r-- 1.038 hook 3 apr 01:54 main.05c219f8.css
.rw-r--r-- 1.759 hook 3 apr 01:54 main.05c219f8.css.map
build/static/js:
.rw-r--r-- 4.534 hook 3 apr 01:54 453.2a77899f.chunk.js
.rw-r--r-- 10.597 hook 3 apr 01:54 453.2a77899f.chunk.js.map
.rw-r--r-- 143.544 hook 3 apr 01:54 main.608edf8e.js
.rw-r--r-- 1.205 hook 3 apr 01:54 main.608edf8e.js.LICENSE.txt
.rw-r--r-- 368.393 hook 3 apr 01:54 main.608edf8e.js.map
and without the SPDX tags, the total size of build/static/ is also 536 KiB (specifically, 529.880 bytes):
build/static/css:
.rw-r--r-- 779 hook 3 apr 01:53 main.f855e6bc.css
.rw-r--r-- 1.427 hook 3 apr 01:53 main.f855e6bc.css.map
build/static/js:
.rw-r--r-- 4.534 hook 3 apr 01:53 453.2a77899f.chunk.js
.rw-r--r-- 10.597 hook 3 apr 01:53 453.2a77899f.chunk.js.map
.rw-r--r-- 143.544 hook 3 apr 01:53 main.608edf8e.js
.rw-r--r-- 1.070 hook 3 apr 01:53 main.608edf8e.js.LICENSE.txt
.rw-r--r-- 367.929 hook 3 apr 01:53 main.608edf8e.js.map
Which is a difference of measly 0.2%.
Lukas was also quick to point out that a ballpark estimation of how much extra space this would take is quite easy to calculate, as all it is needed is to count all files that would be included in the final JS (or CSS) bundle and multiply that with the size of the SPDX tags. As such, the impact would be bigger on projects that have many very short source code files, while smaller on those that have fewer, but longer source code files. Again, this is without taking any de-duplication into account.
So we can come up with a generic formula:
size = normal_minified_size + (number_of_files × 4_extra_lines)
What was the cause of the problem with the Snippet-Begin and Snippet-End tags?¶
You may recall in my original proposal that there was an issue with the SPDX-Snippet-Begin and SPDX-Snippet-End tags being jumbled in the resulting minified code.
According to Lucas, this is most likely something Terser caused when associating comments to functions and then optimizing the code. He is fairly positive it can be solved though.
(Again, spoiler: this will be a moot issue in the end. Wait for the next blog post.)
Do we need tags in the minified code?¶
Of course, a very good question is whether we need the REUSE/SPDX tags in the minified code itself. Especially, given that we do not require something as strict for other non-source code (e.g. compiled code).
I admit, I do not think we actually need to.
To be honest, why that is in the original proposal, is because I was trying to push just how far we can bring license compliance in client-side JS/CSS by just leveraging already existing standards and tools. It turns out we can push it very far – arguably ad absurdum ;)
So, no, I do not think we need that, but it was a good thought experiment and I think it was necessary to get discussion going2.
Alternative proposal: SBOM¶
But if we do not keep it in the code we ship, where do we keep the license/copyright info then?
At LLW 2025 we had a pretty intense session where ultimately we came up with an alternative proposal to generate an SBOM and ship that instead. This solves a lot of issues and is something that license compliance officers are already familiar with. It would also bring it closer to how we manage licensing when shipping non-web software.
The SBOM approach would require use of tooling and by the end of the day we were left with a bunch of loose threads, but in general, this sounds like a good way forward.
Conclusion: plan B in the making¶
Was all the effort now wasted?
Not at all.
Web pages and (SaaS) web applications are still a bit of a different beast, so we learned a lot in the past two years due to this exercise.
I am pretty confident we now have a way how to fulfil the license obligations:
- without making the web page too heavy;
- burdening web developers any more than other programmers;
- shipping machine-readable compliance artifacts; as well as
- making the information ready for human consumption too.
In the next blog post I will present the final proposal.
hook out → I think we’re slowly onto something …