From afb7827f4021fbe4516d29e87087cd242301a62b Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 3 Mar 2022 23:05:37 -0600 Subject: [PATCH 1/3] Allow features overrides, document `custom/` directory --- app/soapbox/utils/features.js | 17 ++++++++++++-- docs/development/build-config.md | 40 ++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/app/soapbox/utils/features.js b/app/soapbox/utils/features.js index 0516ef02d..917653a3a 100644 --- a/app/soapbox/utils/features.js +++ b/app/soapbox/utils/features.js @@ -4,6 +4,19 @@ import { createSelector } from 'reselect'; import gte from 'semver/functions/gte'; import lt from 'semver/functions/lt'; +// FIXME: We have to use a dynamic import to trick Webpack into treating it as +// optional, but this causes custom locales to become part of the main chunk. +const importCustom = path => { + try { + return require(`custom/${path}.json`); + } catch(e) { + return {}; + } +}; + +// Import custom overrides, if exists +const overrides = importCustom('features'); + const any = arr => arr.some(Boolean); // For uglification @@ -16,7 +29,7 @@ export const getFeatures = createSelector([instance => instance], instance => { const features = instance.getIn(['pleroma', 'metadata', 'features'], ImmutableList()); const federation = instance.getIn(['pleroma', 'metadata', 'federation'], ImmutableMap()); - return { + return Object.assign({ bookmarks: any([ v.software === MASTODON && gte(v.compatVersion, '3.1.0'), v.software === PLEROMA && gte(v.version, '0.9.9'), @@ -93,7 +106,7 @@ export const getFeatures = createSelector([instance => instance], instance => { v.software === MASTODON && gte(v.compatVersion, '3.2.0'), v.software === PLEROMA && gte(v.version, '2.4.50'), ]), - }; + }, overrides); }); export const parseVersion = version => { diff --git a/docs/development/build-config.md b/docs/development/build-config.md index e5083b8a0..a5f9a741b 100644 --- a/docs/development/build-config.md +++ b/docs/development/build-config.md @@ -1,5 +1,45 @@ # Build Configuration +Soapbox supports compile-time customizations in the form of environment variables and a gitignored `custom/` directory. + +## `custom/` directory + +You can place files into the `custom/` directory to customize the Soapbox build. + +### Custom locales (`custom/locales/*.json`) + +It is possible to override locale messages by creating a file for each language, eg `custom/locales/en.json`. +In this file, add only the messages you want to be overridden. +For example: + +```json +{ + "account.posts": "Poasts", + "account.posts_with_replies": "Poasts & Replies", + "compose.submit_success": "Your poast was sent!", + "compose_form.publish": "Poast" +} +``` + +These messages will be merged into the language file shipped with Soapbox. + +### Feature overrides (`custom/features.json`) + +You can create a file called `custom/features.json` to disable version-checking and force some features on or off. +For example: + +```json +{ + "bookmarks": false, + "lists": false, + "quotePosts": true +} +``` + +See `app/soapbox/utils/features.js` for the full list of features. + +## Environment variables + When compiling Soapbox FE, environment variables may be passed to change the build itself. For example: From 8d64bf26970d209f6132a538f950c27ffcae96bc Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 3 Mar 2022 23:38:59 -0600 Subject: [PATCH 2/3] custom: fix import leak --- app/soapbox/custom.js | 11 +++++++++++ app/soapbox/utils/features.js | 13 +++---------- 2 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 app/soapbox/custom.js diff --git a/app/soapbox/custom.js b/app/soapbox/custom.js new file mode 100644 index 000000000..31f565ed7 --- /dev/null +++ b/app/soapbox/custom.js @@ -0,0 +1,11 @@ +/** + * Functions for dealing with custom build configuration. + */ + +/** Require a custom JSON file if it exists */ +export const custom = (filename, fallback = {}) => { + const context = require.context('custom', false, /\.json$/); + const path = `./${filename}.json`; + + return context.keys().includes(path) ? context(path) : fallback; +}; diff --git a/app/soapbox/utils/features.js b/app/soapbox/utils/features.js index 917653a3a..44621a322 100644 --- a/app/soapbox/utils/features.js +++ b/app/soapbox/utils/features.js @@ -4,19 +4,12 @@ import { createSelector } from 'reselect'; import gte from 'semver/functions/gte'; import lt from 'semver/functions/lt'; -// FIXME: We have to use a dynamic import to trick Webpack into treating it as -// optional, but this causes custom locales to become part of the main chunk. -const importCustom = path => { - try { - return require(`custom/${path}.json`); - } catch(e) { - return {}; - } -}; +import { custom } from 'soapbox/custom'; // Import custom overrides, if exists -const overrides = importCustom('features'); +const overrides = custom('features'); +// Truthy array convenience function const any = arr => arr.some(Boolean); // For uglification From e8e1ab74edc6afa1b5b0ce2f94a4423936dbd15a Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 4 Mar 2022 11:33:22 -0600 Subject: [PATCH 3/3] Polyfill require.context in tests only --- babel.config.js | 3 +++ package.json | 1 + yarn.lock | 25 ++++++++++++++++--------- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/babel.config.js b/babel.config.js index b9f7954d1..0791d27f4 100644 --- a/babel.config.js +++ b/babel.config.js @@ -57,6 +57,9 @@ module.exports = (api) => { ]); break; case 'test': + config.plugins.push(...[ + 'transform-require-context', + ]); envOptions.modules = 'commonjs'; break; } diff --git a/package.json b/package.json index 5b9b1d9ac..dcdca8734 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "babel-plugin-preval": "^5.0.0", "babel-plugin-react-intl": "^7.5.20", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", + "babel-plugin-transform-require-context": "^0.1.1", "blurhash": "^1.0.0", "bootstrap-icons": "^1.5.0", "bowser": "^2.11.0", diff --git a/yarn.lock b/yarn.lock index 3623eb0ff..36ed26b5d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1141,6 +1141,15 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/template@7", "@babel/template@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + "@babel/template@^7.15.4", "@babel/template@^7.3.3": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194" @@ -1150,15 +1159,6 @@ "@babel/parser" "^7.15.4" "@babel/types" "^7.15.4" -"@babel/template@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" - integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/parser" "^7.16.7" - "@babel/types" "^7.16.7" - "@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.4.tgz#ff8510367a144bfbff552d9e18e28f3e2889c22d" @@ -2579,6 +2579,13 @@ babel-plugin-transform-react-remove-prop-types@^0.4.24: resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a" integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA== +babel-plugin-transform-require-context@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-require-context/-/babel-plugin-transform-require-context-0.1.1.tgz#319b545ca83080b5062776b46cc9b8b346fea9a6" + integrity sha512-4ceqYOtzgmq4/QsB8dP7pUrUOCjY/jrRYdt7YkIOWHxtGDQbcf6YZDyLCiPQf6KsEIcIbSQiTRXOsbLiuJfgNQ== + dependencies: + "@babel/template" "7" + babel-preset-current-node-syntax@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b"