support overriding imports for customizations

This commit is contained in:
Bruno Windels 2021-03-25 18:08:47 +01:00
parent c06b9cd886
commit cd615265f8
2 changed files with 66 additions and 8 deletions

12
doc/SKINNING.md Normal file
View file

@ -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).

View file

@ -50,12 +50,16 @@ const cssSrcDir = path.join(projectDir, "src/platform/web/ui/css/");
const parameters = new commander.Command(); const parameters = new commander.Command();
parameters parameters
.option("--modern-only", "don't make a legacy build") .option("--modern-only", "don't make a legacy build")
.option("--override-imports <json file>", "pass in a file to override import paths, see doc/SKINNING.md")
parameters.parse(process.argv); parameters.parse(process.argv);
async function build({modernOnly}) { async function build({modernOnly, overrideImports}) {
// get version number // get version number
const version = JSON.parse(await fs.readFile(path.join(projectDir, "package.json"), "utf8")).version; 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 devHtml = await fs.readFile(path.join(projectDir, "index.html"), "utf8");
const doc = cheerio.load(devHtml); const doc = cheerio.load(devHtml);
const themes = []; const themes = [];
@ -70,12 +74,12 @@ async function build({modernOnly}) {
// copy olm assets // copy olm assets
const olmAssets = await copyFolder(path.join(projectDir, "lib/olm/"), assets.directory); const olmAssets = await copyFolder(path.join(projectDir, "lib/olm/"), assets.directory);
assets.addSubMap(olmAssets); 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) { if (!modernOnly) {
await assets.write(`hydrogen-legacy.js`, await buildJsLegacy("src/main.js", [ await assets.write(`hydrogen-legacy.js`, await buildJsLegacy("src/main.js", [
'src/platform/web/legacy-polyfill.js', 'src/platform/web/legacy-polyfill.js',
'src/platform/web/LegacyPlatform.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'])); await assets.write(`worker.js`, await buildJsLegacy("src/platform/web/worker/main.js", ['src/platform/web/worker/polyfill.js']));
} }
// copy over non-theme assets // 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()); await assets.writeUnhashed("index.html", doc.html());
} }
async function buildJs(mainFile, extraFiles = []) { async function buildJs(mainFile, extraFiles, importOverrides) {
// create js bundle // create js bundle
const plugins = [multi(), removeJsComments({comments: "none"})];
if (importOverrides) {
plugins.push(overridesAsRollupPlugin(importOverrides));
}
const bundle = await rollup({ const bundle = await rollup({
input: extraFiles.concat(mainFile), input: extraFiles.concat(mainFile),
plugins: [multi(), removeJsComments({comments: "none"})] plugins
}); });
const {output} = await bundle.generate({ const {output} = await bundle.generate({
format: 'es', format: 'es',
@ -192,7 +200,7 @@ async function buildJs(mainFile, extraFiles = []) {
return code; return code;
} }
async function buildJsLegacy(mainFile, extraFiles = []) { async function buildJsLegacy(mainFile, extraFiles, importOverrides) {
// compile down to whatever IE 11 needs // compile down to whatever IE 11 needs
const babelPlugin = babel.babel({ const babelPlugin = babel.babel({
babelHelpers: 'bundled', 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 // create js bundle
const rollupConfig = { const rollupConfig = {
// important the extraFiles come first, // important the extraFiles come first,
// so polyfills are available in the global scope // so polyfills are available in the global scope
// if needed for the mainfile // if needed for the mainfile
input: extraFiles.concat(mainFile), input: extraFiles.concat(mainFile),
plugins: [multi(), commonjs(), nodeResolve(), babelPlugin] plugins
}; };
const bundle = await rollup(rollupConfig); const bundle = await rollup(rollupConfig);
const {output} = await bundle.generate({ 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)); build(parameters).catch(err => console.error(err));