Explorar el Código

setup emotion

Abhinav hace 3 años
padre
commit
a027ea721c
Se han modificado 6 ficheros con 243 adiciones y 103 borrados
  1. 2 0
      package.json
  2. 7 0
      src/createEmotionCache.js
  3. 81 66
      src/pages/_app.tsx
  4. 69 27
      src/pages/_document.tsx
  5. 0 7
      src/types/theme/styled.d.ts
  6. 84 3
      yarn.lock

+ 2 - 0
package.json

@@ -13,7 +13,9 @@
     "prepare": "husky install"
     "prepare": "husky install"
   },
   },
   "dependencies": {
   "dependencies": {
+    "@emotion/cache": "^11.9.3",
     "@emotion/react": "^11.9.3",
     "@emotion/react": "^11.9.3",
+    "@emotion/server": "^11.4.0",
     "@emotion/styled": "^11.9.3",
     "@emotion/styled": "^11.9.3",
     "@ente-io/next-with-workbox": "^1.0.3",
     "@ente-io/next-with-workbox": "^1.0.3",
     "@mui/icons-material": "^5.6.2",
     "@mui/icons-material": "^5.6.2",

+ 7 - 0
src/createEmotionCache.js

@@ -0,0 +1,7 @@
+import createCache from '@emotion/cache';
+
+// prepend: true moves MUI styles to the top of the <head> so they're loaded first.
+// It allows developers to easily override MUI styles with other styling solutions, like CSS modules.
+export default function createEmotionCache() {
+    return createCache({ key: 'css', prepend: true });
+}

+ 81 - 66
src/pages/_app.tsx

@@ -1,5 +1,4 @@
 import React, { createContext, useEffect, useRef, useState } from 'react';
 import React, { createContext, useEffect, useRef, useState } from 'react';
-import styled, { ThemeProvider as SThemeProvider } from 'styled-components';
 import AppNavbar from 'components/Navbar/app';
 import AppNavbar from 'components/Navbar/app';
 import constants from 'utils/strings/constants';
 import constants from 'utils/strings/constants';
 import { useRouter } from 'next/router';
 import { useRouter } from 'next/router';
@@ -17,19 +16,21 @@ import Head from 'next/head';
 import { logUploadInfo } from 'utils/upload';
 import { logUploadInfo } from 'utils/upload';
 import LoadingBar from 'react-top-loading-bar';
 import LoadingBar from 'react-top-loading-bar';
 import DialogBox from 'components/DialogBox';
 import DialogBox from 'components/DialogBox';
-import { ThemeProvider as MThemeProvider } from '@mui/material/styles';
+import { styled, ThemeProvider } from '@mui/material/styles';
+import { CacheProvider, EmotionCache } from '@emotion/react';
+import createEmotionCache from '../createEmotionCache';
 import darkThemeOptions from 'themes/darkThemeOptions';
 import darkThemeOptions from 'themes/darkThemeOptions';
 import { CssBaseline } from '@mui/material';
 import { CssBaseline } from '@mui/material';
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-import * as types from 'styled-components/cssprop'; // need to css prop on styled component
 import { SetDialogBoxAttributes, DialogBoxAttributes } from 'types/dialogBox';
 import { SetDialogBoxAttributes, DialogBoxAttributes } from 'types/dialogBox';
 import {
 import {
     getFamilyPortalRedirectURL,
     getFamilyPortalRedirectURL,
     getRoadmapRedirectURL,
     getRoadmapRedirectURL,
 } from 'services/userService';
 } from 'services/userService';
 import { CustomError } from 'utils/error';
 import { CustomError } from 'utils/error';
+import PropTypes from 'prop-types';
+import { AppProps } from 'next/app';
 
 
-export const MessageContainer = styled.div`
+export const MessageContainer = styled('div')`
     background-color: #111;
     background-color: #111;
     padding: 0;
     padding: 0;
     font-size: 14px;
     font-size: 14px;
@@ -72,7 +73,19 @@ const redirectMap = new Map([
     ['families', getFamilyPortalRedirectURL],
     ['families', getFamilyPortalRedirectURL],
 ]);
 ]);
 
 
-export default function App({ Component, err }) {
+// Client-side cache, shared for the whole session of the user in the browser.
+const clientSideEmotionCache = createEmotionCache();
+
+interface MyAppProps extends AppProps {
+    emotionCache?: EmotionCache;
+}
+
+export default function MyApp(props: MyAppProps) {
+    const {
+        Component,
+        emotionCache = clientSideEmotionCache,
+        pageProps,
+    } = props;
     const router = useRouter();
     const router = useRouter();
     const [loading, setLoading] = useState(false);
     const [loading, setLoading] = useState(false);
     const [offline, setOffline] = useState(
     const [offline, setOffline] = useState(
@@ -223,7 +236,7 @@ export default function App({ Component, err }) {
     const closeMessageDialog = () => setMessageDialogView(false);
     const closeMessageDialog = () => setMessageDialogView(false);
 
 
     return (
     return (
-        <>
+        <CacheProvider value={emotionCache}>
             <Head>
             <Head>
                 <title>{constants.TITLE}</title>
                 <title>{constants.TITLE}</title>
                 <meta
                 <meta
@@ -232,66 +245,68 @@ export default function App({ Component, err }) {
                 />
                 />
             </Head>
             </Head>
 
 
-            <MThemeProvider theme={darkThemeOptions}>
-                <SThemeProvider theme={darkThemeOptions}>
-                    <CssBaseline />
-                    {showNavbar && <AppNavbar />}
-                    <MessageContainer>
-                        {offline && constants.OFFLINE_MSG}
-                    </MessageContainer>
-                    {sharedFiles &&
-                        (router.pathname === '/gallery' ? (
-                            <MessageContainer>
-                                {constants.FILES_TO_BE_UPLOADED(
-                                    sharedFiles.length
-                                )}
-                            </MessageContainer>
-                        ) : (
-                            <MessageContainer>
-                                {constants.LOGIN_TO_UPLOAD_FILES(
-                                    sharedFiles.length
-                                )}
-                            </MessageContainer>
-                        ))}
-                    {flashMessage && (
-                        <FlashMessageBar
-                            flashMessage={flashMessage}
-                            onClose={() => setFlashMessage(null)}
-                        />
-                    )}
-                    <LoadingBar color="#51cd7c" ref={loadingBar} />
-
-                    <DialogBox
-                        open={messageDialogView}
-                        onClose={closeMessageDialog}
-                        attributes={dialogMessage}
+            <ThemeProvider theme={darkThemeOptions}>
+                <CssBaseline />
+                {showNavbar && <AppNavbar />}
+                <MessageContainer>
+                    {offline && constants.OFFLINE_MSG}
+                </MessageContainer>
+                {sharedFiles &&
+                    (router.pathname === '/gallery' ? (
+                        <MessageContainer>
+                            {constants.FILES_TO_BE_UPLOADED(sharedFiles.length)}
+                        </MessageContainer>
+                    ) : (
+                        <MessageContainer>
+                            {constants.LOGIN_TO_UPLOAD_FILES(
+                                sharedFiles.length
+                            )}
+                        </MessageContainer>
+                    ))}
+                {flashMessage && (
+                    <FlashMessageBar
+                        flashMessage={flashMessage}
+                        onClose={() => setFlashMessage(null)}
                     />
                     />
+                )}
+                <LoadingBar color="#51cd7c" ref={loadingBar} />
 
 
-                    <AppContext.Provider
-                        value={{
-                            showNavBar,
-                            sharedFiles,
-                            resetSharedFiles,
-                            setDisappearingFlashMessage,
-                            redirectURL,
-                            setRedirectURL,
-                            startLoading,
-                            finishLoading,
-                            closeMessageDialog,
-                            setDialogMessage,
-                        }}>
-                        {loading ? (
-                            <VerticallyCentered>
-                                <EnteSpinner>
-                                    <span className="sr-only">Loading...</span>
-                                </EnteSpinner>
-                            </VerticallyCentered>
-                        ) : (
-                            <Component err={err} setLoading={setLoading} />
-                        )}
-                    </AppContext.Provider>
-                </SThemeProvider>
-            </MThemeProvider>
-        </>
+                <DialogBox
+                    open={messageDialogView}
+                    onClose={closeMessageDialog}
+                    attributes={dialogMessage}
+                />
+
+                <AppContext.Provider
+                    value={{
+                        showNavBar,
+                        sharedFiles,
+                        resetSharedFiles,
+                        setDisappearingFlashMessage,
+                        redirectURL,
+                        setRedirectURL,
+                        startLoading,
+                        finishLoading,
+                        closeMessageDialog,
+                        setDialogMessage,
+                    }}>
+                    {loading ? (
+                        <VerticallyCentered>
+                            <EnteSpinner>
+                                <span className="sr-only">Loading...</span>
+                            </EnteSpinner>
+                        </VerticallyCentered>
+                    ) : (
+                        <Component {...pageProps} />
+                    )}
+                </AppContext.Provider>
+            </ThemeProvider>
+        </CacheProvider>
     );
     );
 }
 }
+
+MyApp.propTypes = {
+    Component: PropTypes.elementType.isRequired,
+    emotionCache: PropTypes.object,
+    pageProps: PropTypes.object.isRequired,
+};

+ 69 - 27
src/pages/_document.tsx

@@ -1,38 +1,19 @@
 import React from 'react';
 import React from 'react';
 import Document, { Html, Head, Main, NextScript } from 'next/document';
 import Document, { Html, Head, Main, NextScript } from 'next/document';
-import { ServerStyleSheet } from 'styled-components';
 
 
-export default class MyDocument extends Document {
-    static async getInitialProps(ctx) {
-        const sheet = new ServerStyleSheet();
-        const originalRenderPage = ctx.renderPage;
-
-        try {
-            ctx.renderPage = () =>
-                originalRenderPage({
-                    enhanceApp: (App) => (props) =>
-                        sheet.collectStyles(<App {...props} />),
-                });
-
-            const initialProps = await Document.getInitialProps(ctx);
-            return {
-                ...initialProps,
-                styles: (
-                    <>
-                        {initialProps.styles}
-                        {sheet.getStyleElement()}
-                    </>
-                ),
-            };
-        } finally {
-            sheet.seal();
-        }
-    }
+import createEmotionServer from '@emotion/server/create-instance';
+import theme from '../themes/darkThemeOptions';
+import createEmotionCache from '../createEmotionCache';
 
 
+export default class MyDocument extends Document {
     render() {
     render() {
         return (
         return (
             <Html lang="en">
             <Html lang="en">
                 <Head>
                 <Head>
+                    <meta
+                        name="theme-color"
+                        content={theme.palette.primary.main}
+                    />
                     <meta
                     <meta
                         name="description"
                         name="description"
                         content="ente is a privacy focussed photo storage service that offers end-to-end encryption."
                         content="ente is a privacy focussed photo storage service that offers end-to-end encryption."
@@ -55,6 +36,8 @@ export default class MyDocument extends Document {
                         name="apple-mobile-web-app-status-bar-style"
                         name="apple-mobile-web-app-status-bar-style"
                         content="black"
                         content="black"
                     />
                     />
+                    {/* Inject MUI styles first to match with the prepend: true configuration. */}
+                    {(this.props as any).emotionStyleTags}
                 </Head>
                 </Head>
                 <body>
                 <body>
                     <Main />
                     <Main />
@@ -64,3 +47,62 @@ export default class MyDocument extends Document {
         );
         );
     }
     }
 }
 }
+
+// `getInitialProps` belongs to `_document` (instead of `_app`),
+// it's compatible with static-site generation (SSG).
+MyDocument.getInitialProps = async (ctx) => {
+    // Resolution order
+    //
+    // On the server:
+    // 1. app.getInitialProps
+    // 2. page.getInitialProps
+    // 3. document.getInitialProps
+    // 4. app.render
+    // 5. page.render
+    // 6. document.render
+    //
+    // On the server with error:
+    // 1. document.getInitialProps
+    // 2. app.render
+    // 3. page.render
+    // 4. document.render
+    //
+    // On the client
+    // 1. app.getInitialProps
+    // 2. page.getInitialProps
+    // 3. app.render
+    // 4. page.render
+
+    const originalRenderPage = ctx.renderPage;
+
+    // You can consider sharing the same Emotion cache between all the SSR requests to speed up performance.
+    // However, be aware that it can have global side effects.
+    const cache = createEmotionCache();
+    const { extractCriticalToChunks } = createEmotionServer(cache);
+
+    ctx.renderPage = () =>
+        originalRenderPage({
+            enhanceApp: (App: any) =>
+                function EnhanceApp(props) {
+                    return <App emotionCache={cache} {...props} />;
+                },
+        });
+
+    const initialProps = await Document.getInitialProps(ctx);
+    // This is important. It prevents Emotion to render invalid HTML.
+    // See https://github.com/mui/material-ui/issues/26561#issuecomment-855286153
+    const emotionStyles = extractCriticalToChunks(initialProps.html);
+    const emotionStyleTags = emotionStyles.styles.map((style) => (
+        <style
+            data-emotion={`${style.key} ${style.ids.join(' ')}`}
+            key={style.key}
+            // eslint-disable-next-line react/no-danger
+            dangerouslySetInnerHTML={{ __html: style.css }}
+        />
+    ));
+
+    return {
+        ...initialProps,
+        emotionStyleTags,
+    };
+};

+ 0 - 7
src/types/theme/styled.d.ts

@@ -1,7 +0,0 @@
-// styled.d.ts
-import 'styled-components';
-import { Theme } from '@mui/material';
-
-declare module 'styled-components' {
-    export interface DefaultTheme extends Theme {}
-}

+ 84 - 3
yarn.lock

@@ -1035,6 +1035,16 @@
     "@emotion/utils" "^1.0.0"
     "@emotion/utils" "^1.0.0"
     csstype "^3.0.2"
     csstype "^3.0.2"
 
 
+"@emotion/server@^11.4.0":
+  version "11.4.0"
+  resolved "https://registry.yarnpkg.com/@emotion/server/-/server-11.4.0.tgz#3ae1d74cb31c7d013c3c76e88c0c4439076e9f66"
+  integrity sha512-IHovdWA3V0DokzxLtUNDx4+hQI82zUXqQFcVz/om2t44O0YSc+NHB+qifnyAOoQwt3SXcBTgaSntobwUI9gnfA==
+  dependencies:
+    "@emotion/utils" "^1.0.0"
+    html-tokenize "^2.0.0"
+    multipipe "^1.0.2"
+    through "^2.3.8"
+
 "@emotion/sheet@^1.0.0", "@emotion/sheet@^1.0.2":
 "@emotion/sheet@^1.0.0", "@emotion/sheet@^1.0.2":
   version "1.0.2"
   version "1.0.2"
   resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.0.2.tgz"
   resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.0.2.tgz"
@@ -2232,6 +2242,11 @@ buffer-from@^1.0.0:
   resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz"
   resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz"
   integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
   integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
 
 
+buffer-from@~0.1.1:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-0.1.2.tgz#15f4b9bcef012044df31142c14333caf6e0260d0"
+  integrity sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==
+
 builtin-modules@^3.1.0:
 builtin-modules@^3.1.0:
   version "3.2.0"
   version "3.2.0"
   resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz"
   resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz"
@@ -2655,6 +2670,13 @@ dom-helpers@^5.0.1, dom-helpers@^5.2.0, dom-helpers@^5.2.1:
     "@babel/runtime" "^7.8.7"
     "@babel/runtime" "^7.8.7"
     csstype "^3.0.2"
     csstype "^3.0.2"
 
 
+duplexer2@^0.1.2:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
+  integrity sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==
+  dependencies:
+    readable-stream "^2.0.2"
+
 duplexer@^0.1.1:
 duplexer@^0.1.1:
   version "0.1.2"
   version "0.1.2"
   resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz"
   resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz"
@@ -3439,6 +3461,17 @@ hosted-git-info@^2.1.4:
   resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz"
   resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz"
   integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
   integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
 
 
+html-tokenize@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/html-tokenize/-/html-tokenize-2.0.1.tgz#c3b2ea6e2837d4f8c06693393e9d2a12c960be5f"
+  integrity sha512-QY6S+hZ0f5m1WT8WffYN+Hg+xm/w5I8XeUcAq/ZYP5wVC8xbKi4Whhru3FtrAebD5EhBW8rmFzkDI6eCAuFe2w==
+  dependencies:
+    buffer-from "~0.1.1"
+    inherits "~2.0.1"
+    minimist "~1.2.5"
+    readable-stream "~1.0.27-1"
+    through2 "~0.4.1"
+
 http-errors@1.7.2:
 http-errors@1.7.2:
   version "1.7.2"
   version "1.7.2"
   resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz"
   resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz"
@@ -3557,7 +3590,7 @@ inflight@^1.0.4:
     once "^1.3.0"
     once "^1.3.0"
     wrappy "1"
     wrappy "1"
 
 
-inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
   version "2.0.4"
   version "2.0.4"
   resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
   resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
   integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
   integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -3780,6 +3813,11 @@ is-weakref@^1.0.1:
   dependencies:
   dependencies:
     call-bind "^1.0.2"
     call-bind "^1.0.2"
 
 
+isarray@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+  integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==
+
 isarray@~1.0.0:
 isarray@~1.0.0:
   version "1.0.0"
   version "1.0.0"
   resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
   resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
@@ -4174,7 +4212,7 @@ minimatch@^3.0.4:
   dependencies:
   dependencies:
     brace-expansion "^1.1.7"
     brace-expansion "^1.1.7"
 
 
-minimist@^1.2.0, minimist@^1.2.5:
+minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2.5:
   version "1.2.6"
   version "1.2.6"
   resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
   resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
   integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
   integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
@@ -4201,6 +4239,14 @@ ms@2.1.2, ms@^2.1.1:
   resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
   resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
   integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
   integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
 
 
+multipipe@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-1.0.2.tgz#cc13efd833c9cda99f224f868461b8e1a3fd939d"
+  integrity sha512-6uiC9OvY71vzSGX8lZvSqscE7ft9nPupJ8fMjrCNRAUy2LREUW42UL+V/NTrogr6rFgRydUrCX4ZitfpSNkSCQ==
+  dependencies:
+    duplexer2 "^0.1.2"
+    object-assign "^4.1.0"
+
 nanoid@^3.1.30:
 nanoid@^3.1.30:
   version "3.3.1"
   version "3.3.1"
   resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz"
   resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz"
@@ -4316,6 +4362,11 @@ object-keys@^1.0.12, object-keys@^1.1.1:
   resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz"
   resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz"
   integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
   integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
 
 
+object-keys@~0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336"
+  integrity sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==
+
 object.assign@^4.1.0, object.assign@^4.1.2:
 object.assign@^4.1.0, object.assign@^4.1.2:
   version "4.1.2"
   version "4.1.2"
   resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz"
   resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz"
@@ -4900,7 +4951,7 @@ read-pkg@^3.0.0:
     normalize-package-data "^2.3.2"
     normalize-package-data "^2.3.2"
     path-type "^3.0.0"
     path-type "^3.0.0"
 
 
-readable-stream@^2.0.6, readable-stream@~2.3.6:
+readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@~2.3.6:
   version "2.3.7"
   version "2.3.7"
   resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz"
   resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz"
   integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
   integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
@@ -4922,6 +4973,16 @@ readable-stream@^3.6.0:
     string_decoder "^1.1.1"
     string_decoder "^1.1.1"
     util-deprecate "^1.0.1"
     util-deprecate "^1.0.1"
 
 
+readable-stream@~1.0.17, readable-stream@~1.0.27-1:
+  version "1.0.34"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
+  integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.1"
+    isarray "0.0.1"
+    string_decoder "~0.10.x"
+
 readable-web-to-node-stream@^3.0.0:
 readable-web-to-node-stream@^3.0.0:
   version "3.0.2"
   version "3.0.2"
   resolved "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz"
   resolved "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz"
@@ -5434,6 +5495,11 @@ string_decoder@^1.1.1:
   dependencies:
   dependencies:
     safe-buffer "~5.2.0"
     safe-buffer "~5.2.0"
 
 
+string_decoder@~0.10.x:
+  version "0.10.31"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+  integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==
+
 string_decoder@~1.1.1:
 string_decoder@~1.1.1:
   version "1.1.1"
   version "1.1.1"
   resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz"
   resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz"
@@ -5593,6 +5659,14 @@ text-table@^0.2.0:
   resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
   resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
   integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
   integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
 
 
+through2@~0.4.1:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-0.4.2.tgz#dbf5866031151ec8352bb6c4db64a2292a840b9b"
+  integrity sha512-45Llu+EwHKtAZYTPPVn3XZHBgakWMN3rokhEv5hu596XP+cNgplMg+Gj+1nmAvj+L0K7+N49zBKx5rah5u0QIQ==
+  dependencies:
+    readable-stream "~1.0.17"
+    xtend "~2.1.1"
+
 through@^2.3.8:
 through@^2.3.8:
   version "2.3.8"
   version "2.3.8"
   resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
   resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
@@ -6142,6 +6216,13 @@ xml-js@^1.6.11:
   dependencies:
   dependencies:
     sax "^1.2.4"
     sax "^1.2.4"
 
 
+xtend@~2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b"
+  integrity sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==
+  dependencies:
+    object-keys "~0.4.0"
+
 yallist@^4.0.0:
 yallist@^4.0.0:
   version "4.0.0"
   version "4.0.0"
   resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
   resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"