diff --git a/.env.example b/.env.example new file mode 100644 index 0000000000..52f2a023a2 --- /dev/null +++ b/.env.example @@ -0,0 +1,13 @@ +# If you want to have proper hot-reload css experience, define one and set this on. +CSS_HOT_RELOAD=1 +# Define which one theme you want to load for hot-reload purposes. +# You can load multiple themes at once, but switching between is quite buggy with the hot-reload turned on. +# To use a single theme just uncomment a line with the theme you want to use. +MATRIX_THEMES='light' +#MATRIX_THEMES='dark' +#MATRIX_THEMES='light-legacy' +#MATRIX_THEMES='dark-legacy' +#MATRIX_THEMES='light-custom' +#MATRIX_THEMES='dark-custom' +# If you want to use multiple themes, define the combinations manually like below: +#MATRIX_THEMES='light,dark' diff --git a/.gitignore b/.gitignore index bc6255165b..52152e1a11 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ electron/pub /webpack-stats.json .vscode .vscode/ +.env diff --git a/README.md b/README.md index 8bf6ecd8cf..76acfcaf85 100644 --- a/README.md +++ b/README.md @@ -30,14 +30,14 @@ and [element-ios](https://github.com/vector-im/element-ios). Getting Started =============== -The easiest way to test Element is to just use the hosted copy at https://app.element.io. -The `develop` branch is continuously deployed to https://develop.element.io +The easiest way to test Element is to just use the hosted copy at . +The `develop` branch is continuously deployed to for those who like living dangerously. To host your own copy of Element, the quickest bet is to use a pre-built released version of Element: -1. Download the latest version from https://github.com/vector-im/element-web/releases +1. Download the latest version from 1. Untar the tarball on your web server 1. Move (or symlink) the `element-x.x.x` directory to an appropriate name 1. Configure the correct caching headers in your webserver (see below) @@ -46,7 +46,7 @@ released version of Element: 1. Enter the URL into your browser and log into Element! Releases are signed using gpg and the OpenPGP standard, and can be checked against the public key located -at https://packages.riot.im/element-release-key.asc. +at . Note that for the security of your chats will need to serve Element over HTTPS. Major browsers also do not allow you to use VoIP/video @@ -72,7 +72,7 @@ access to Element (or other apps) due to sharing the same domain. We have put some coarse mitigations into place to try to protect against this situation, but it's still not good practice to do it in the first place. See -https://github.com/vector-im/element-web/issues/1977 for more details. + for more details. Configuration best practices ---------------------------- @@ -80,15 +80,15 @@ Configuration best practices Unless you have special requirements, you will want to add the following to your web server configuration when hosting Element Web: -- The `X-Frame-Options: SAMEORIGIN` header, to prevent Element Web from being +* The `X-Frame-Options: SAMEORIGIN` header, to prevent Element Web from being framed and protect from [clickjacking][owasp-clickjacking]. -- The `frame-ancestors 'none'` directive to your `Content-Security-Policy` +* The `frame-ancestors 'none'` directive to your `Content-Security-Policy` header, as the modern replacement for `X-Frame-Options` (though both should be included since not all browsers support it yet, see [this][owasp-clickjacking-csp]). -- The `X-Content-Type-Options: nosniff` header, to [disable MIME +* The `X-Content-Type-Options: nosniff` header, to [disable MIME sniffing][mime-sniffing]. -- The `X-XSS-Protection: 1; mode=block;` header, for basic XSS protection in +* The `X-XSS-Protection: 1; mode=block;` header, for basic XSS protection in legacy browsers. [mime-sniffing]: @@ -127,10 +127,10 @@ guide](https://classic.yarnpkg.com/en/docs/install) if you do not have it alread 1. Clone the repo: `git clone https://github.com/vector-im/element-web.git`. 1. Switch to the element-web directory: `cd element-web`. 1. Install the prerequisites: `yarn install`. - * If you're using the `develop` branch, then it is recommended to set up a + * If you're using the `develop` branch, then it is recommended to set up a proper development environment (see [Setting up a dev environment](#setting-up-a-dev-environment) below). Alternatively, you - can use https://develop.element.io - the continuous integration release of + can use - the continuous integration release of the develop branch. 1. Configure the app by copying `config.sample.json` to `config.json` and modifying it. See the [configuration docs](docs/config.md) for details. @@ -148,15 +148,16 @@ Running as a Desktop app ======================== Element can also be run as a desktop app, wrapped in Electron. You can download a -pre-built version from https://element.io/get-started or, if you prefer, +pre-built version from or, if you prefer, build it yourself. -To build it yourself, follow the instructions at https://github.com/vector-im/element-desktop. +To build it yourself, follow the instructions at . Many thanks to @aviraldg for the initial work on the Electron integration. Other options for running as a desktop app: - * @asdf:matrix.org points out that you can use nativefier and it just works(tm) + +* @asdf:matrix.org points out that you can use nativefier and it just works(tm) ```bash yarn global add nativefier @@ -171,6 +172,7 @@ Running from Docker The Docker image can be used to serve element-web as a web server. The easiest way to use it is to use the prebuilt image: + ```bash docker run -p 80:80 vectorim/element-web ``` @@ -178,11 +180,13 @@ docker run -p 80:80 vectorim/element-web To supply your own custom `config.json`, map a volume to `/app/config.json`. For example, if your custom config was located at `/etc/element-web/config.json` then your Docker command would be: + ```bash docker run -p 80:80 -v /etc/element-web/config.json:/app/config.json vectorim/element-web ``` To build the image yourself: + ```bash git clone https://github.com/vector-im/element-web.git element-web cd element-web @@ -192,6 +196,7 @@ docker build . If you're building a custom branch, or want to use the develop branch, check out the appropriate element-web branch and then run: + ```bash docker build -t \ --build-arg USE_CUSTOM_SDKS=true \ @@ -224,6 +229,7 @@ Caching requirements ==================== Element requires the following URLs not to be cached, when/if you are serving Element from your own webserver: + ``` /config.*.json /i18n @@ -261,6 +267,10 @@ internet. So please don't depend on resources (JS libs, CSS, images, fonts) hosted by external CDNs or servers but instead please package all dependencies into Element itself. +CSS hot-reload is currently an opt-in development feature, and if you want to have +it working properly on your environment, create a `.env` file in this repository +with proper environmental, see `.env.example` for documentation and example. + Setting up a dev environment ============================ @@ -302,14 +312,15 @@ yarn reskindex yarn start ``` - Wait a few seconds for the initial build to finish; you should see something like: + ``` [element-js] [webpack.Progress] 100% [element-js] [element-js] ℹ 「wdm」: 1840 modules [element-js] ℹ 「wdm」: Compiled successfully. ``` + Remember, the command will not terminate since it runs the web server and rebuilds source files when they change. This development server also disables caching, so do NOT use it in production. @@ -317,7 +328,7 @@ Wait a few seconds for the initial build to finish; you should see something lik Configure the app by copying `config.sample.json` to `config.json` and modifying it. See the [configuration docs](docs/config.md) for details. -Open http://127.0.0.1:8080/ in your browser to see your newly built Element. +Open in your browser to see your newly built Element. **Note**: The build script uses inotify by default on Linux to monitor directories for changes. If the inotify limits are too low your build will fail silently or with @@ -393,14 +404,14 @@ Triaging issues We strive to completely cover all applicable issues with these core labels: 1. __Type__ — Every issue is assigned a type: - - __[T-Defect](https://github.com/vector-im/element-web/labels/T-Defect):__ + * __[T-Defect](https://github.com/vector-im/element-web/labels/T-Defect):__ Bugs, crashes, hangs, vulnerabilities, or other reported problems - - __[T-Enhancement](https://github.com/vector-im/element-web/labels/T-Enhancement):__ + * __[T-Enhancement](https://github.com/vector-im/element-web/labels/T-Enhancement):__ New features, changes in functionality, performance boosts, user-facing improvements - - __[T-Task](https://github.com/vector-im/element-web/labels/T-Task):__ + * __[T-Task](https://github.com/vector-im/element-web/labels/T-Task):__ Refactoring, enabling or disabling functionality, other engineering tasks - - __[T-Other](https://github.com/vector-im/element-web/labels/T-Other):__ + * __[T-Other](https://github.com/vector-im/element-web/labels/T-Other):__ Questions, user support, anything else 2. __Severity__ — All issues labeled `T-Defect` are also assigned a severity: diff --git a/package.json b/package.json index fcf2b1fa53..1b2c87f331 100644 --- a/package.json +++ b/package.json @@ -104,6 +104,7 @@ "concurrently": "^5.3.0", "cpx": "^1.5.0", "css-loader": "^3.6.0", + "dotenv": "^10.0.0", "eslint": "7.18.0", "eslint-config-google": "^0.14.0", "eslint-plugin-matrix-org": "github:matrix-org/eslint-plugin-matrix-org#main", diff --git a/webpack.config.js b/webpack.config.js index 03ac4a8eff..035cfdb977 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,5 +1,6 @@ /* eslint-disable quote-props */ +const dotenv = require('dotenv'); const path = require('path'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); @@ -21,24 +22,29 @@ const cssThemes = { "theme-dark-custom": "./node_modules/matrix-react-sdk/res/themes/dark-custom/css/dark-custom.scss", }; -function getActiveThemes() { - const theme = process.env.MATRIX_THEMES ?? 'light,dark'; - const themes = theme.split(',').filter(x => x).map(x => x.trim()).filter(x => x); - return themes; +let dotenvConfig = { parsed: {} }; +try { + dotenvConfig = dotenv.config(); +} catch (err) { + dotenvConfig = { + parsed: { + CSS_HOT_RELOAD: 0, + MATRIX_THEMES: 'light', + }, + }; } -const ACTIVE_THEMES = getActiveThemes(); -function getThemesImports() { - const imports = ACTIVE_THEMES.map((t, index) => { - const themeImportPath = cssThemes[`theme-${t}`].replace('./node_modules/', ''); - return themeImportPath; - }); - const s = JSON.stringify(ACTIVE_THEMES); - return ` - window.MX_insertedThemeStylesCounter = 0 - window.MX_DEV_ACTIVE_THEMES = (${s}); - ${imports.map(i => `import("${i}")`).join('\n')}; - `; +const CSS_HOT_RELOAD = process.env.CSS_HOT_RELOAD ?? dotenvConfig.CSS_HOT_RELOAD; +const MATRIX_THEMES = process.env.MATRIX_THEMES ?? dotenvConfig.MATRIX_THEMES; + +function getActiveThemes() { + // We want to use `light` theme by default if it's not defined. + const theme = MATRIX_THEMES; + const themes = theme.split(',').filter(x => x).map(x => x.trim()).filter(x => x); + if (themes.length > 1) { + throw new Error('Please see `.env.example` for proper hotreload&themes configuation.'); + } + return themes; } module.exports = (env, argv) => { @@ -57,6 +63,7 @@ module.exports = (env, argv) => { nodeEnv = "production"; } const devMode = nodeEnv !== 'production'; + const useCssHotReload = CSS_HOT_RELOAD === '1' && devMode; const development = {}; if (argv.mode === "production") { @@ -73,16 +80,22 @@ module.exports = (env, argv) => { const reactSdkSrcDir = path.resolve(require.resolve("matrix-react-sdk/package.json"), '..', 'src'); const jsSdkSrcDir = path.resolve(require.resolve("matrix-js-sdk/package.json"), '..', 'src'); + const ACTIVE_THEMES = getActiveThemes(); + function getThemesImports() { + const imports = ACTIVE_THEMES.map((t, index) => { + const themeImportPath = cssThemes[`theme-${ t }`].replace('./node_modules/', ''); + return themeImportPath; + }); + const s = JSON.stringify(ACTIVE_THEMES); + return ` + window.MX_insertedThemeStylesCounter = 0 + window.MX_DEV_ACTIVE_THEMES = (${ s }); + ${ imports.map(i => `import("${ i }")`).join('\n') }; + `; + } + return { ...development, - - watch: true, - watchOptions: { - aggregateTimeout: 200, - poll: 1000, - ignored: [/node_modules([\\]+|\/)+(?!matrix-react-sdk|matrix-js-sdk)/], - }, - node: { // Mock out the NodeFS module: The opus decoder imports this wrongly. fs: 'empty', @@ -94,7 +107,7 @@ module.exports = (env, argv) => { "jitsi": "./src/vector/jitsi/index.ts", "usercontent": "./node_modules/matrix-react-sdk/src/usercontent/index.js", "recorder-worklet": "./node_modules/matrix-react-sdk/src/audio/RecorderWorklet.ts", - ...(devMode ? {} : cssThemes), + ...(useCssHotReload ? {} : cssThemes), }, optimization: { @@ -178,7 +191,7 @@ module.exports = (env, argv) => { /olm[\\/](javascript[\\/])?olm\.js$/, ], rules: [ - devMode && { + useCssHotReload && { test: /devcss\.ts$/, loader: 'string-replace-loader', options: { @@ -217,7 +230,7 @@ module.exports = (env, argv) => { { test: /\.css$/, use: [ - devMode ? 'style-loader' : MiniCssExtractPlugin.loader, + MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { @@ -271,8 +284,14 @@ module.exports = (env, argv) => { * of the JS/TS files. * Should be MUCH better with webpack 5, but we're stuck to this solution for now. */ - devMode ? { + useCssHotReload ? { loader: 'style-loader', options: { + /** + * If we refactor the `theme.js` in `matrix-react-sdk` a little bit, + * we could try using `lazyStyleTag` here to add and remove styles on demand, + * that would nicely resolve issues of race conditions for themes, + * at least for development purposes. + */ attributes: { 'data-mx-theme': 'replace_me', }, @@ -430,7 +449,7 @@ module.exports = (env, argv) => { }, ], }, - ], + ].filter(Boolean), }, plugins: [ diff --git a/yarn.lock b/yarn.lock index 74e40d7f90..495862952c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4024,6 +4024,11 @@ dot-prop@^5.2.0: dependencies: is-obj "^2.0.0" +dotenv@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== + duplexer@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"