Skip to content

Commit 1b14ada

Browse files
authored
[5.3] Fix missing copyright in media assets (#46146)
1 parent efb7789 commit 1b14ada

File tree

6 files changed

+88
-42
lines changed

6 files changed

+88
-42
lines changed

build/build-modules-js/css-versioning.mjs renamed to build/build-modules-js/stylesheets/css-versioning.mjs

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { readdir, readFile, writeFile } from 'node:fs/promises';
33
import { existsSync, readFileSync } from 'node:fs';
44
import { dirname, extname, resolve } from 'node:path';
55
import { transform, composeVisitors } from 'lightningcss';
6-
import { Timer } from './utils/timer.mjs';
6+
import { Timer } from '../utils/timer.mjs';
77

88
const RootPath = process.cwd();
99
const skipExternal = true;
@@ -37,17 +37,13 @@ function version(urlString, fromFile) {
3737
* @param {from: String} - the filepath for the css file
3838
* @returns {import('lightningcss').Visitor} - A visitor that replaces the url
3939
*/
40-
function urlVersioning(fromFile) {
41-
return {
42-
/**
43-
* @param {import('lightningcss').Url} url - The url object to transform
44-
* @returns {import('lightningcss').Url} - The transformed url object
45-
*/
46-
Url(url) {
47-
return { ...url, ...{ url: version(url.url, fromFile) } };
48-
},
49-
};
50-
}
40+
const urlVersioning = (fromFile) => ({
41+
/**
42+
* @param {import('lightningcss').Url} url - The url object to transform
43+
* @returns {import('lightningcss').Url} - The transformed url object
44+
*/
45+
Url: (url) => ({ ...url, url: version(url.url, fromFile) }),
46+
});
5147

5248
/**
5349
* Adds a hash to the url() parts of the static css
@@ -57,8 +53,25 @@ function urlVersioning(fromFile) {
5753
*/
5854
const fixVersion = async (file) => {
5955
try {
56+
let content = await readFile(file, { encoding: 'utf8' });
57+
// To preserve the licence the comment needs to start at the beginning of the file
58+
const replaceUTF8String = file.endsWith('.min.css') ? '@charset "UTF-8";' : '@charset "UTF-8";\n';
59+
content = content.startsWith(replaceUTF8String) ? content.replace(replaceUTF8String, '') : content;
60+
61+
// Preserve a leading license comment (/** ... */)
62+
const firstLine = content.split(/\r?\n/)[0] || '';
63+
if (firstLine.includes('/*') && !firstLine.includes('/*!')) {
64+
const endCommentIdx = content.indexOf('*/');
65+
if (endCommentIdx !== -1
66+
&& (content.substring(0, endCommentIdx).includes('license')
67+
|| content.substring(0, endCommentIdx).includes('copyright'))
68+
) {
69+
content = firstLine.includes('/**') ? content.replace('/**', '/*!') : content.replace('/*', '/*!');
70+
}
71+
}
72+
6073
const { code } = transform({
61-
code: await readFile(file),
74+
code: Buffer.from(content),
6275
minify: file.endsWith('.min.css'),
6376
visitor: composeVisitors([urlVersioning(file)]),
6477
});
@@ -76,13 +89,15 @@ const fixVersion = async (file) => {
7689
*
7790
* @returns {Promise<void>}
7891
*/
79-
export const cssVersioning = async () => {
92+
const cssVersioningVendor = async () => {
8093
const bench = new Timer('Versioning');
8194

82-
const cssFiles = (await readdir(`${RootPath}/media`, { withFileTypes: true, recursive: true }))
95+
const cssFiles = (await readdir(`${RootPath}/media/vendor`, { withFileTypes: true, recursive: true }))
8396
.filter((file) => (!file.isDirectory() && extname(file.name) === '.css'))
8497
.map((file) => `${file.path}/${file.name}`);
8598

8699
Promise.all(cssFiles.map((file) => fixVersion(file)))
87100
.then(() => bench.stop());
88101
};
102+
103+
export { urlVersioning, cssVersioningVendor };

build/build-modules-js/stylesheets/handle-css.mjs

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,52 @@
11
import { dirname, sep } from 'node:path';
22

33
import pkg from 'fs-extra';
4-
import { transform as transformCss } from 'lightningcss';
4+
import { transform as transformCss, composeVisitors } from 'lightningcss';
5+
import { urlVersioning } from './css-versioning.mjs';
56

67
const {
7-
copy, readFile, writeFile, ensureDir,
8+
readFile, writeFile, ensureDir,
89
} = pkg;
910

1011
export const handleCssFile = async (file) => {
1112
const outputFile = file.replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`);
1213
try {
13-
// CSS file, we will copy the file and then minify it in place
14+
// CSS file, we will process the file and then minify it in place
1415
// Ensure that the directories exist or create them
1516
await ensureDir(dirname(outputFile), { recursive: true, mode: 0o755 });
1617

18+
let content = await readFile(file, { encoding: 'utf8' });
19+
20+
// To preserve the licence the comment needs to start at the beginning of the file
21+
content = content.startsWith('@charset "UTF-8";\n') ? content.replace('@charset "UTF-8";\n', '') : content;
22+
1723
if (file !== outputFile) {
18-
await copy(file, outputFile, { preserveTimestamps: true, overwrite: true });
24+
const { code: css } = transformCss({
25+
code: Buffer.from(content),
26+
minify: false,
27+
visitor: composeVisitors([urlVersioning(file)]), // Adds a hash to the url() parts of the static css
28+
});
29+
30+
// Save optimized css file
31+
await writeFile(
32+
outputFile,
33+
content.startsWith('@charset "UTF-8";')
34+
? css
35+
: `@charset "UTF-8";
36+
${css}`,
37+
{ encoding: 'utf8', mode: 0o644 },
38+
);
1939
}
2040

21-
const content = await readFile(file, { encoding: 'utf8' });
22-
const { code } = transformCss({
41+
// Process the file and minify it in place
42+
const { code: cssMin } = transformCss({
2343
code: Buffer.from(content),
2444
minify: true,
45+
visitor: composeVisitors([urlVersioning(outputFile)]), // Adds a hash to the url() parts of the static css
2546
});
2647

27-
// Ensure the folder exists or create it
28-
await writeFile(outputFile.replace('.css', '.min.css'), `@charset "UTF-8";${code}`, { encoding: 'utf8', mode: 0o644 });
48+
// Save minified css file
49+
await writeFile(outputFile.replace('.css', '.min.css'), `@charset "UTF-8";${cssMin}`, { encoding: 'utf8', mode: 0o644 });
2950

3051
// eslint-disable-next-line no-console
3152
console.log(`✅ CSS file copied/minified: ${file}`);

build/build-modules-js/stylesheets/handle-scss.mjs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import { dirname, sep } from 'node:path';
33

44
import rtlcss from 'rtlcss';
55
import { ensureDir } from 'fs-extra';
6-
import { transform as transformCss, Features } from 'lightningcss';
6+
import { transform as transformCss, Features, composeVisitors } from 'lightningcss';
77
import { compileAsync } from 'sass-embedded';
8+
import { urlVersioning } from './css-versioning.mjs';
89

910
const getOutputFile = (file) => file.replace(`${sep}scss${sep}`, `${sep}css${sep}`).replace('.scss', '.css').replace(`${sep}build${sep}media_source${sep}`, `${sep}media${sep}`);
1011

@@ -23,24 +24,43 @@ export const handleScssFile = async (file) => {
2324
contents = rtlcss.process(contents);
2425
}
2526

27+
// To preserve the licence the comment needs to start at the beginning of the file
28+
contents = contents.startsWith('@charset "UTF-8";\n') ? contents.replace('@charset "UTF-8";\n', '') : contents;
29+
2630
// Ensure the folder exists or create it
2731
await ensureDir(dirname(cssFile), {});
32+
33+
const { code: css } = transformCss({
34+
code: Buffer.from(contents),
35+
minify: false,
36+
exclude: Features.VendorPrefixes,
37+
visitor: composeVisitors([urlVersioning(file)]), // Adds a hash to the url() parts of the static css
38+
});
39+
40+
// Save optimized css file
2841
await writeFile(
2942
cssFile,
30-
`@charset "UTF-8";
31-
${contents}`,
43+
contents.startsWith('@charset "UTF-8";')
44+
? css
45+
: `@charset "UTF-8";
46+
${css}`,
3247
{ encoding: 'utf8', mode: 0o644 },
3348
);
3449

3550
const { code: cssMin } = transformCss({
3651
code: Buffer.from(contents),
3752
minify: true,
3853
exclude: Features.VendorPrefixes,
54+
visitor: composeVisitors([urlVersioning(cssFile)]), // Adds a hash to the url() parts of the static css
3955
});
4056

4157
// Ensure the folder exists or create it
4258
await ensureDir(dirname(cssFile.replace('.css', '.min.css')), {});
43-
await writeFile(cssFile.replace('.css', '.min.css'), `@charset "UTF-8";${cssMin}`, { encoding: 'utf8', mode: 0o644 });
59+
await writeFile(
60+
cssFile.replace('.css', '.min.css'),
61+
`@charset "UTF-8";${cssMin}`,
62+
{ encoding: 'utf8', mode: 0o644 },
63+
);
4464

4565
// eslint-disable-next-line no-console
4666
console.log(`✅ SCSS File compiled: ${cssFile}`);

build/build.mjs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
* node build.mjs --com-media will compile the media manager Vue application
1414
* node build.mjs --watch-com-media will watch and compile the media manager Vue application
1515
* node build.mjs --gzip will create gzip files for all the minified stylesheets and scripts.
16-
* node build.mjs --cssversioning will update all the url entries providing accurate versions for stylesheets.
1716
* node build.mjs --versioning will update all the joomla.assets.json files providing accurate versions for stylesheets and scripts.
1817
*/
1918

@@ -34,10 +33,10 @@ import { recreateMediaFolder } from './build-modules-js/init/recreate-media.mjs'
3433
import { watching } from './build-modules-js/watch.mjs';
3534
import { mediaManager, watchMediaManager } from './build-modules-js/javascript/build-com_media-js.mjs';
3635
import { compressFiles } from './build-modules-js/compress.mjs';
37-
import { cssVersioning } from './build-modules-js/css-versioning.mjs';
3836
import { versioning } from './build-modules-js/versioning.mjs';
3937
import { Timer } from './build-modules-js/utils/timer.mjs';
4038
import { compileCodemirror } from './build-modules-js/javascript/build-codemirror.mjs';
39+
import { cssVersioningVendor } from './build-modules-js/stylesheets/css-versioning.mjs';
4140

4241
const require = createRequire(import.meta.url);
4342

@@ -103,10 +102,6 @@ Program.allowUnknownOption()
103102
)
104103
.option('--gzip', 'Compress all the minified stylesheets and scripts.')
105104
.option('--prepare', 'Run all the needed tasks to initialise the repo')
106-
.option(
107-
'--cssversioning',
108-
'Update all the url() versions on their relative stylesheet files',
109-
)
110105
.option(
111106
'--versioning',
112107
'Update all the .js/.css versions on their relative joomla.assets.json',
@@ -130,6 +125,7 @@ if (cliOptions.copyAssets) {
130125
.then(() => cleanVendors())
131126
.then(() => localisePackages(options))
132127
.then(() => patchPackages(options))
128+
.then(() => cssVersioningVendor())
133129
.then(() => minifyVendor())
134130
.catch((error) => handleError(error, 1));
135131
}
@@ -185,11 +181,6 @@ if (cliOptions.versioning) {
185181
versioning().catch((err) => handleError(err, 1));
186182
}
187183

188-
// Update the url() versions in the .css files
189-
if (cliOptions.cssversioning) {
190-
cssVersioning().catch((err) => handleError(err, 1));
191-
}
192-
193184
// Prepare the repo for dev work
194185
if (cliOptions.prepare) {
195186
const bench = new Timer('Build');
@@ -201,6 +192,7 @@ if (cliOptions.prepare) {
201192
.then(() => minifyVendor())
202193
.then(() => createErrorPages(options))
203194
.then(() => stylesheets(options, Program.args[0]))
195+
.then(() => cssVersioningVendor())
204196
.then(() => scripts(options, Program.args[0]))
205197
.then(() => mediaManager())
206198
.then(() => bootstrapJs())

build/build.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,9 @@ function capture_or_fail(string $command): string
343343
exit(1);
344344
}
345345

346-
run_and_check('npm install --unsafe-perm');
347-
346+
// Install dependencies and build the media assets
348347
// Create version entries of the urls inside the static css files
349-
run_and_check('npm run cssversioning');
348+
run_and_check('npm ci');
350349

351350
// Create gzipped version of the static assets
352351
run_and_check('npm run gzip');

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
"install": "node build/build.mjs --prepare",
2626
"update": "node build/build.mjs --copy-assets && node build/build.mjs --build-pages && node build/build.mjs --compile-js && node build/build.mjs --compile-css && node build/build.mjs --compile-bs && node --env-file=./build/production.env build/build.mjs --com-media",
2727
"gzip": "node build/build.mjs --gzip",
28-
"cssversioning": "node build/build.mjs --cssversioning",
2928
"versioning": "node build/build.mjs --versioning",
3029
"browserlist:update": "npx browserslist@latest --update-db",
3130
"cypress:install": "cypress install",

0 commit comments

Comments
 (0)