From cd615265f851156fd6f952c8b5e76a79af1a42e6 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 25 Mar 2021 18:08:47 +0100 Subject: [PATCH 1/2] support overriding imports for customizations --- doc/SKINNING.md | 12 +++++++++ scripts/build.mjs | 62 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 doc/SKINNING.md diff --git a/doc/SKINNING.md b/doc/SKINNING.md new file mode 100644 index 00000000..bb5034ee --- /dev/null +++ b/doc/SKINNING.md @@ -0,0 +1,12 @@ +# Skinning + +Any source file can be replaced at build time by mapping the path in a JSON file passed in to the build command, e.g. `yarn build --override-imports customizations.json`. The file should be written like so: + +```json +{ + "src/platform/web/ui/session/room/timeline/TextMessageView.js": "src/platform/web/ui/session/room/timeline/MyTextMessageView.js" +} +``` +The paths are relative to the location of the mapping file, but the mapping file should be in a parent directory of the files you want to replace. + +You should see a "replacing x with y" line (twice actually, for the normal and legacy build). diff --git a/scripts/build.mjs b/scripts/build.mjs index 4d29c9db..1b931f37 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -50,12 +50,16 @@ const cssSrcDir = path.join(projectDir, "src/platform/web/ui/css/"); const parameters = new commander.Command(); parameters .option("--modern-only", "don't make a legacy build") + .option("--override-imports ", "pass in a file to override import paths, see doc/SKINNING.md") parameters.parse(process.argv); -async function build({modernOnly}) { +async function build({modernOnly, overrideImports}) { // get version number const version = JSON.parse(await fs.readFile(path.join(projectDir, "package.json"), "utf8")).version; - + let importOverridesMap; + if (overrideImports) { + importOverridesMap = await readImportOverrides(overrideImports); + } const devHtml = await fs.readFile(path.join(projectDir, "index.html"), "utf8"); const doc = cheerio.load(devHtml); const themes = []; @@ -70,12 +74,12 @@ async function build({modernOnly}) { // copy olm assets const olmAssets = await copyFolder(path.join(projectDir, "lib/olm/"), assets.directory); assets.addSubMap(olmAssets); - await assets.write(`hydrogen.js`, await buildJs("src/main.js", ["src/platform/web/Platform.js"])); + await assets.write(`hydrogen.js`, await buildJs("src/main.js", ["src/platform/web/Platform.js"], importOverridesMap)); if (!modernOnly) { await assets.write(`hydrogen-legacy.js`, await buildJsLegacy("src/main.js", [ 'src/platform/web/legacy-polyfill.js', 'src/platform/web/LegacyPlatform.js' - ])); + ], importOverridesMap)); await assets.write(`worker.js`, await buildJsLegacy("src/platform/web/worker/main.js", ['src/platform/web/worker/polyfill.js'])); } // copy over non-theme assets @@ -177,11 +181,15 @@ async function buildHtml(doc, version, baseConfig, globalHash, modernOnly, asset await assets.writeUnhashed("index.html", doc.html()); } -async function buildJs(mainFile, extraFiles = []) { +async function buildJs(mainFile, extraFiles, importOverrides) { // create js bundle + const plugins = [multi(), removeJsComments({comments: "none"})]; + if (importOverrides) { + plugins.push(overridesAsRollupPlugin(importOverrides)); + } const bundle = await rollup({ input: extraFiles.concat(mainFile), - plugins: [multi(), removeJsComments({comments: "none"})] + plugins }); const {output} = await bundle.generate({ format: 'es', @@ -192,7 +200,7 @@ async function buildJs(mainFile, extraFiles = []) { return code; } -async function buildJsLegacy(mainFile, extraFiles = []) { +async function buildJsLegacy(mainFile, extraFiles, importOverrides) { // compile down to whatever IE 11 needs const babelPlugin = babel.babel({ babelHelpers: 'bundled', @@ -212,13 +220,18 @@ async function buildJsLegacy(mainFile, extraFiles = []) { ] ] }); + const plugins = [multi(), commonjs()]; + if (importOverrides) { + plugins.push(overridesAsRollupPlugin(importOverrides)); + } + plugins.push(nodeResolve(), babelPlugin); // create js bundle const rollupConfig = { // important the extraFiles come first, // so polyfills are available in the global scope // if needed for the mainfile input: extraFiles.concat(mainFile), - plugins: [multi(), commonjs(), nodeResolve(), babelPlugin] + plugins }; const bundle = await rollup(rollupConfig); const {output} = await bundle.generate({ @@ -488,4 +501,37 @@ class AssetMap { } } +async function readImportOverrides(filename) { + const json = await fs.readFile(filename, "utf8"); + const mapping = new Map(Object.entries(JSON.parse(json))); + return { + basedir: path.dirname(path.resolve(filename))+path.sep, + mapping + }; +} + +function overridesAsRollupPlugin(importOverrides) { + const {mapping, basedir} = importOverrides; + return { + name: "rewrite-imports", + resolveId (source, importer) { + let file; + if (source.startsWith(path.sep)) { + file = source; + } else { + file = path.join(path.dirname(importer), source); + } + if (file.startsWith(basedir)) { + const searchPath = file.substr(basedir.length); + const replacingPath = mapping.get(searchPath); + if (replacingPath) { + console.info(`replacing ${searchPath} with ${replacingPath}`); + return path.join(basedir, replacingPath); + } + } + return null; + } + }; +} + build(parameters).catch(err => console.error(err)); From 2a0045bed7f7e97f5f5fa3247835951f22ea81ba Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 25 Mar 2021 18:54:10 +0100 Subject: [PATCH 2/2] support override main css file --- doc/SKINNING.md | 12 +++++++++++- scripts/build.mjs | 12 ++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/doc/SKINNING.md b/doc/SKINNING.md index bb5034ee..5f1c735d 100644 --- a/doc/SKINNING.md +++ b/doc/SKINNING.md @@ -1,4 +1,4 @@ -# Skinning +# Replacing javascript files Any source file can be replaced at build time by mapping the path in a JSON file passed in to the build command, e.g. `yarn build --override-imports customizations.json`. The file should be written like so: @@ -10,3 +10,13 @@ Any source file can be replaced at build time by mapping the path in a JSON file The paths are relative to the location of the mapping file, but the mapping file should be in a parent directory of the files you want to replace. You should see a "replacing x with y" line (twice actually, for the normal and legacy build). + +# Injecting CSS + +You can override the location of the main css file with the `--override-css ` option to the build script. The default is `src/platform/web/ui/css/main.css`, which you probably want to import from your custom css file like so: + +```css +@import url('src/platform/web/ui/css/main.css'); + +/* additions */ +``` diff --git a/scripts/build.mjs b/scripts/build.mjs index 1b931f37..44d58fe6 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -51,9 +51,10 @@ const parameters = new commander.Command(); parameters .option("--modern-only", "don't make a legacy build") .option("--override-imports ", "pass in a file to override import paths, see doc/SKINNING.md") + .option("--override-css
", "pass in an alternative main css file") parameters.parse(process.argv); -async function build({modernOnly, overrideImports}) { +async function build({modernOnly, overrideImports, overrideCss}) { // get version number const version = JSON.parse(await fs.readFile(path.join(projectDir, "package.json"), "utf8")).version; let importOverridesMap; @@ -90,7 +91,7 @@ async function build({modernOnly, overrideImports}) { // creates the directories where the theme css bundles are placed in, // and writes to assets, so the build bundles can translate them, so do it first await copyThemeAssets(themes, assets); - await buildCssBundles(buildCssLegacy, themes, assets); + await buildCssBundles(buildCssLegacy, themes, assets, overrideCss); await buildManifest(assets); // all assets have been added, create a hash from all assets name to cache unhashed files like index.html assets.addToHashForAll("index.html", devHtml); @@ -311,8 +312,11 @@ async function buildServiceWorker(swSource, version, globalHash, assets) { await assets.writeUnhashed("sw.js", swSource); } -async function buildCssBundles(buildFn, themes, assets) { - const bundleCss = await buildFn(path.join(cssSrcDir, "main.css")); +async function buildCssBundles(buildFn, themes, assets, mainCssFile = null) { + if (!mainCssFile) { + mainCssFile = path.join(cssSrcDir, "main.css"); + } + const bundleCss = await buildFn(mainCssFile); await assets.write(`hydrogen.css`, bundleCss); for (const theme of themes) { const themeRelPath = `themes/${theme}/`;