From 1f6efb4db3faa62cdf499c77c42db2d8fd86f5f0 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 25 Mar 2022 11:35:27 +0530 Subject: [PATCH 1/7] Write plugin code --- .../rollup-plugin-build-themes.js | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 scripts/build-plugins/rollup-plugin-build-themes.js diff --git a/scripts/build-plugins/rollup-plugin-build-themes.js b/scripts/build-plugins/rollup-plugin-build-themes.js new file mode 100644 index 00000000..dd52ef77 --- /dev/null +++ b/scripts/build-plugins/rollup-plugin-build-themes.js @@ -0,0 +1,64 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +async function readCSSSource(location) { + const fs = require("fs").promises; + const path = require("path"); + const resolvedLocation = path.resolve(__dirname, "../../", `${location}/theme.css`); + const data = await fs.readFile(resolvedLocation); + return data; +} + +async function appendVariablesToCSS(variables, cssSource) { + return cssSource + `:root{\n${Object.entries(variables).reduce((acc, [key, value]) => acc + `--${key}: ${value};\n`, "")} }\n\n`; +} + +module.exports = function buildThemes(options) { + let manifest, variants; + + return { + name: "build-themes", + enforce: "pre", + + async buildStart() { + const { manifestLocations } = options; + for (const location of manifestLocations) { + manifest = require(`${location}/manifest.json`); + variants = manifest.values.variants; + for (const [variant] of Object.entries(variants)) { + const themeName = manifest.name; + // emit the css as built theme bundle + this.emitFile({ + type: "chunk", + id: `${location}/theme.css?variant=${variant}`, + fileName: `theme-${themeName}-${variant}.css`, + }); + } + } + }, + + async load(id) { + const result = id.match(/(.+)\/theme.css\?variant=(.+)/); + if (result) { + const [, location, variant] = result; + const cssSource = await readCSSSource(location); + const config = variants[variant]; + return await appendVariablesToCSS(config.variables, cssSource); + } + return null; + }, + } +} From 32eb95734a6ca17241fda7bf577eaf9c2641cb69 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 28 Mar 2022 18:02:53 +0530 Subject: [PATCH 2/7] Add default themes to index html --- .../rollup-plugin-build-themes.js | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/scripts/build-plugins/rollup-plugin-build-themes.js b/scripts/build-plugins/rollup-plugin-build-themes.js index dd52ef77..770f48b7 100644 --- a/scripts/build-plugins/rollup-plugin-build-themes.js +++ b/scripts/build-plugins/rollup-plugin-build-themes.js @@ -27,7 +27,7 @@ async function appendVariablesToCSS(variables, cssSource) { } module.exports = function buildThemes(options) { - let manifest, variants; + let manifest, variants, defaultDark, defaultLight; return { name: "build-themes", @@ -38,13 +38,23 @@ module.exports = function buildThemes(options) { for (const location of manifestLocations) { manifest = require(`${location}/manifest.json`); variants = manifest.values.variants; - for (const [variant] of Object.entries(variants)) { + for (const [variant, details] of Object.entries(variants)) { const themeName = manifest.name; + const fileName = `theme-${themeName}-${variant}.css`; + if (details.default) { + // This theme is the default for when Hydrogen launches for the first time + if (details.dark) { + defaultDark = fileName; + } + else { + defaultLight = fileName; + } + } // emit the css as built theme bundle this.emitFile({ type: "chunk", id: `${location}/theme.css?variant=${variant}`, - fileName: `theme-${themeName}-${variant}.css`, + fileName, }); } } @@ -60,5 +70,37 @@ module.exports = function buildThemes(options) { } return null; }, + + transformIndexHtml(_, ctx) { + let darkThemeLocation, lightThemeLocation; + for (const [, bundle] of Object.entries(ctx.bundle)) { + if (bundle.name === defaultDark) { + darkThemeLocation = bundle.fileName; + } + if (bundle.name === defaultLight) { + lightThemeLocation = bundle.fileName; + } + } + return [ + { + tag: "link", + attrs: { + rel: "stylesheet", + type: "text/css", + media: "(prefers-color-scheme: dark)", + href: `./${darkThemeLocation}`, + } + }, + { + tag: "link", + attrs: { + rel: "stylesheet", + type: "text/css", + media: "(prefers-color-scheme: light)", + href: `./${lightThemeLocation}`, + } + }, + ]; + } } } From 86c45b5b998685febc6f444e78b6e1da70937308 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 29 Mar 2022 11:46:06 +0530 Subject: [PATCH 3/7] Emit runtime bundle --- scripts/build-plugins/rollup-plugin-build-themes.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/build-plugins/rollup-plugin-build-themes.js b/scripts/build-plugins/rollup-plugin-build-themes.js index 770f48b7..0b9ec4bf 100644 --- a/scripts/build-plugins/rollup-plugin-build-themes.js +++ b/scripts/build-plugins/rollup-plugin-build-themes.js @@ -38,8 +38,8 @@ module.exports = function buildThemes(options) { for (const location of manifestLocations) { manifest = require(`${location}/manifest.json`); variants = manifest.values.variants; + const themeName = manifest.name; for (const [variant, details] of Object.entries(variants)) { - const themeName = manifest.name; const fileName = `theme-${themeName}-${variant}.css`; if (details.default) { // This theme is the default for when Hydrogen launches for the first time @@ -57,6 +57,12 @@ module.exports = function buildThemes(options) { fileName, }); } + // emit the css as runtime theme bundle + this.emitFile({ + type: "chunk", + id: `${location}/theme.css`, + fileName: `theme-${themeName}-runtime.css`, + }); } }, From d5b5e10230cd8d9c5272d9ef67c7bd0f7e0285b6 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 1 Apr 2022 14:27:24 +0530 Subject: [PATCH 4/7] Produce manifest.jsom --- .../rollup-plugin-build-themes.js | 59 ++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/scripts/build-plugins/rollup-plugin-build-themes.js b/scripts/build-plugins/rollup-plugin-build-themes.js index 0b9ec4bf..cd4dc495 100644 --- a/scripts/build-plugins/rollup-plugin-build-themes.js +++ b/scripts/build-plugins/rollup-plugin-build-themes.js @@ -26,6 +26,46 @@ async function appendVariablesToCSS(variables, cssSource) { return cssSource + `:root{\n${Object.entries(variables).reduce((acc, [key, value]) => acc + `--${key}: ${value};\n`, "")} }\n\n`; } +function parseBundle(bundle) { + const chunkMap = new Map(); + const assetMap = new Map(); + let runtimeThemeChunk; + for (const [fileName, info] of Object.entries(bundle)) { + if (!fileName.endsWith(".css")) { + continue; + } + if (info.type === "asset") { + /** + * So this is the css assetInfo that contains the asset hashed file name. + * We'll store it in a separate map indexed via fileName (unhashed) to avoid + * searching through the bundle array later. + */ + assetMap.set(info.name, info); + continue; + } + if (info.facadeModuleId?.includes("type=runtime")) { + /** + * We have a separate field in manifest.source just for the runtime theme, + * so store this separately. + */ + runtimeThemeChunk = info; + continue; + } + const location = info.facadeModuleId?.match(/(.+)\/.+\.css/)?.[1]; + if (!location) { + throw new Error("Cannot find location of css chunk!"); + } + const array = chunkMap.get(location); + if (!array) { + chunkMap.set(location, [info]); + } + else { + array.push(info); + } + } + return { chunkMap, assetMap, runtimeThemeChunk }; +} + module.exports = function buildThemes(options) { let manifest, variants, defaultDark, defaultLight; @@ -60,7 +100,7 @@ module.exports = function buildThemes(options) { // emit the css as runtime theme bundle this.emitFile({ type: "chunk", - id: `${location}/theme.css`, + id: `${location}/theme.css?type=runtime`, fileName: `theme-${themeName}-runtime.css`, }); } @@ -107,6 +147,23 @@ module.exports = function buildThemes(options) { } }, ]; + }, + + generateBundle(_, bundle) { + const { assetMap, chunkMap, runtimeThemeChunk } = parseBundle(bundle); + for (const [location, chunkArray] of chunkMap) { + const manifest = require(`${location}/manifest.json`); + manifest.source = { + "built-asset": chunkArray.map(chunk => assetMap.get(chunk.fileName).fileName), + "runtime-asset": assetMap.get(runtimeThemeChunk.fileName).fileName, + }; + const name = `theme-${manifest.name}.json`; + this.emitFile({ + type: "asset", + name, + source: JSON.stringify(manifest), + }); + } } } } From b0f082e81f555c8ba2faeefb565eb6098ea261a6 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 1 Apr 2022 20:27:33 +0530 Subject: [PATCH 5/7] Add derived variables to source section --- scripts/build-plugins/rollup-plugin-build-themes.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/build-plugins/rollup-plugin-build-themes.js b/scripts/build-plugins/rollup-plugin-build-themes.js index cd4dc495..b5768e8c 100644 --- a/scripts/build-plugins/rollup-plugin-build-themes.js +++ b/scripts/build-plugins/rollup-plugin-build-themes.js @@ -153,9 +153,11 @@ module.exports = function buildThemes(options) { const { assetMap, chunkMap, runtimeThemeChunk } = parseBundle(bundle); for (const [location, chunkArray] of chunkMap) { const manifest = require(`${location}/manifest.json`); + const derivedVariables = options.compiledVariables.get(location)["derived-variables"]; manifest.source = { "built-asset": chunkArray.map(chunk => assetMap.get(chunk.fileName).fileName), "runtime-asset": assetMap.get(runtimeThemeChunk.fileName).fileName, + "derived-variables": derivedVariables, }; const name = `theme-${manifest.name}.json`; this.emitFile({ From 7f9af5b5fa0ff932231c09247a043914e733890b Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Sun, 3 Apr 2022 16:30:35 +0530 Subject: [PATCH 6/7] Add icon to manifest --- scripts/build-plugins/rollup-plugin-build-themes.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/build-plugins/rollup-plugin-build-themes.js b/scripts/build-plugins/rollup-plugin-build-themes.js index b5768e8c..2355a136 100644 --- a/scripts/build-plugins/rollup-plugin-build-themes.js +++ b/scripts/build-plugins/rollup-plugin-build-themes.js @@ -153,11 +153,14 @@ module.exports = function buildThemes(options) { const { assetMap, chunkMap, runtimeThemeChunk } = parseBundle(bundle); for (const [location, chunkArray] of chunkMap) { const manifest = require(`${location}/manifest.json`); - const derivedVariables = options.compiledVariables.get(location)["derived-variables"]; + const compiledVariables = options.compiledVariables.get(location); + const derivedVariables = compiledVariables["derived-variables"]; + const icon = compiledVariables["icon"]; manifest.source = { "built-asset": chunkArray.map(chunk => assetMap.get(chunk.fileName).fileName), "runtime-asset": assetMap.get(runtimeThemeChunk.fileName).fileName, "derived-variables": derivedVariables, + "icon": icon }; const name = `theme-${manifest.name}.json`; this.emitFile({ From f75ee86c0e30288aa5af9cf1906fe76a0ccfbd2c Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 5 Apr 2022 16:27:23 +0530 Subject: [PATCH 7/7] Change comment --- scripts/build-plugins/rollup-plugin-build-themes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build-plugins/rollup-plugin-build-themes.js b/scripts/build-plugins/rollup-plugin-build-themes.js index 2355a136..74fe4daf 100644 --- a/scripts/build-plugins/rollup-plugin-build-themes.js +++ b/scripts/build-plugins/rollup-plugin-build-themes.js @@ -82,7 +82,7 @@ module.exports = function buildThemes(options) { for (const [variant, details] of Object.entries(variants)) { const fileName = `theme-${themeName}-${variant}.css`; if (details.default) { - // This theme is the default for when Hydrogen launches for the first time + // This is one of the default variants for this theme. if (details.dark) { defaultDark = fileName; }