mirror of https://github.com/vector-im/riot-web
				
				
				
			Add a .env config and explanation how to use HMR
							parent
							
								
									b677edbc58
								
							
						
					
					
						commit
						a9f3f873a5
					
				| 
						 | 
				
			
			@ -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'
 | 
			
		||||
| 
						 | 
				
			
			@ -21,3 +21,4 @@ electron/pub
 | 
			
		|||
/webpack-stats.json
 | 
			
		||||
.vscode
 | 
			
		||||
.vscode/
 | 
			
		||||
.env
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										51
									
								
								README.md
								
								
								
								
							
							
						
						
									
										51
									
								
								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 <https://app.element.io>.
 | 
			
		||||
The `develop` branch is continuously deployed to <https://develop.element.io>
 | 
			
		||||
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 <https://github.com/vector-im/element-web/releases>
 | 
			
		||||
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 <https://packages.riot.im/element-release-key.asc>.
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
<https://github.com/vector-im/element-web/issues/1977> 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 <https://develop.element.io> - 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 <https://element.io/get-started> 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 <https://github.com/vector-im/element-desktop>.
 | 
			
		||||
 | 
			
		||||
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] <s> [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 <http://127.0.0.1:8080/> 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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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: [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue