diff --git a/benchmark/README.md b/benchmark/README.md new file mode 100644 index 00000000000000..3e42ce1960a376 --- /dev/null +++ b/benchmark/README.md @@ -0,0 +1,11 @@ +# Browser benchmark + +This project is used when running the following command: + +```sh +yarn benchmark +``` + +It is suppose to give developers comparable values between running different scenarios inside the browser, that can be find the `./scenarios` folder. + +You should use these numbers exclusively for comparing performance between different scenarios, not as absolute values. There is also a `./noop` scenario, that renders nothing, to give you the idea of the initial setup time before the actual code is being run. diff --git a/benchmark/index.html b/benchmark/index.html new file mode 100644 index 00000000000000..0136af6ac6e532 --- /dev/null +++ b/benchmark/index.html @@ -0,0 +1,13 @@ + + + + Perf scenario + + + + + +
+ + + diff --git a/benchmark/index.js b/benchmark/index.js new file mode 100644 index 00000000000000..e30c8718f0fb78 --- /dev/null +++ b/benchmark/index.js @@ -0,0 +1,42 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import PropTypes from 'prop-types'; + +// Get all the scenarios +const requirePerfScenarios = require.context('./scenarios', true, /(js|ts|tsx)$/); + +const rootEl = document.getElementById('root'); + +const scenarioSuitePath = window.location.search.replace('?', ''); + +const Component = requirePerfScenarios(scenarioSuitePath).default; + +const start = performance.now(); +let end; + +function TestCase(props) { + const ref = React.useRef(null); + + React.useLayoutEffect(() => { + // Force layout + ref.current.getBoundingClientRect(); + + end = performance.now(); + window.timing = { + render: end - start, + }; + }); + + return
{props.children}
; +} + +TestCase.propTypes = { + children: PropTypes.node, +}; + +ReactDOM.render( + + + , + rootEl, +); diff --git a/benchmark/scenarios/box-emotion/index.js b/benchmark/scenarios/box-emotion/index.js new file mode 100644 index 00000000000000..817cee62d43e2a --- /dev/null +++ b/benchmark/scenarios/box-emotion/index.js @@ -0,0 +1,29 @@ +import * as React from 'react'; +import { createMuiTheme } from '@material-ui/core/styles'; +import styledEmotion from '@emotion/styled'; +import { ThemeProvider as EmotionTheme } from 'emotion-theming'; +import { styleFunction } from '@material-ui/core/Box'; +import { logReactMetrics } from '../utils'; + +const materialSystemTheme = createMuiTheme(); +const Box = styledEmotion('div')(styleFunction); + +export default function BoxEmotion() { + return ( + + {new Array(1000).fill().map(() => ( + + + emotion + + + ))} + + ); +} diff --git a/benchmark/scenarios/box-material-ui-styles/index.js b/benchmark/scenarios/box-material-ui-styles/index.js new file mode 100644 index 00000000000000..23065b9c1ab0fd --- /dev/null +++ b/benchmark/scenarios/box-material-ui-styles/index.js @@ -0,0 +1,27 @@ +import * as React from 'react'; +import { createMuiTheme } from '@material-ui/core/styles'; +import { ThemeProvider as StylesThemeProvider } from '@material-ui/styles'; +import BoxStyles from '@material-ui/core/Box'; +import { logReactMetrics } from '../utils'; + +const materialSystemTheme = createMuiTheme(); + +export default function BoxMaterialUIStyles() { + return ( + + {new Array(1000).fill().map(() => ( + + + @material-ui/styles + + + ))} + + ); +} diff --git a/benchmark/scenarios/box-styled-components/index.js b/benchmark/scenarios/box-styled-components/index.js new file mode 100644 index 00000000000000..66efc41169c8e1 --- /dev/null +++ b/benchmark/scenarios/box-styled-components/index.js @@ -0,0 +1,30 @@ +import * as React from 'react'; +import { createMuiTheme } from '@material-ui/core/styles'; +import { styleFunction } from '@material-ui/core/Box'; +import styledComponents, { + ThemeProvider as StyledComponentsThemeProvider, +} from 'styled-components'; +import { logReactMetrics } from '../utils'; + +const materialSystemTheme = createMuiTheme(); +const BoxStyleComponents = styledComponents('div')(styleFunction); + +export default function BoxStyledComponents() { + return ( + + {new Array(1000).fill().map(() => ( + + + styled-components + + + ))} + + ); +} diff --git a/benchmark/scenarios/material-ui-system-all-inclusive/index.js b/benchmark/scenarios/material-ui-system-all-inclusive/index.js new file mode 100644 index 00000000000000..1e028b882391c9 --- /dev/null +++ b/benchmark/scenarios/material-ui-system-all-inclusive/index.js @@ -0,0 +1,17 @@ +import { createMuiTheme } from '@material-ui/core/styles'; +import { styleFunction } from '@material-ui/core/Box'; + +const materialSystemTheme = createMuiTheme(); + +export default function MaterialUISystemAllInclusive() { + styleFunction({ + theme: materialSystemTheme, + color: 'primary.main', + bgcolor: 'background.paper', + fontFamily: 'h6.fontFamily', + fontSize: ['h6.fontSize', 'h4.fontSize', 'h3.fontSize'], + p: [2, 3, 4], + }); + + return null; +} diff --git a/benchmark/scenarios/material-ui-system-colors/index.js b/benchmark/scenarios/material-ui-system-colors/index.js new file mode 100644 index 00000000000000..1dd175a4377e16 --- /dev/null +++ b/benchmark/scenarios/material-ui-system-colors/index.js @@ -0,0 +1,10 @@ +import { palette } from '@material-ui/system'; + +export default function MaterialUISystemColors() { + palette({ + theme: {}, + bgcolor: ['red', 'blue'], + }); + + return null; +} diff --git a/benchmark/scenarios/material-ui-system-compose/index.js b/benchmark/scenarios/material-ui-system-compose/index.js new file mode 100644 index 00000000000000..0e85b395b597db --- /dev/null +++ b/benchmark/scenarios/material-ui-system-compose/index.js @@ -0,0 +1,18 @@ +import { createMuiTheme } from '@material-ui/core/styles'; +import { spacing, palette, typography, compose } from '@material-ui/system'; + +const materialSystem = compose(palette, spacing, typography); +const materialSystemTheme = createMuiTheme(); + +export default function MaterialUISystemCompose() { + materialSystem({ + theme: materialSystemTheme, + color: 'primary.main', + bgcolor: 'background.paper', + fontFamily: 'h6.fontFamily', + fontSize: ['h6.fontSize', 'h4.fontSize', 'h3.fontSize'], + p: [2, 3, 4], + }); + + return null; +} diff --git a/benchmark/scenarios/material-ui-system-spaces/index.js b/benchmark/scenarios/material-ui-system-spaces/index.js new file mode 100644 index 00000000000000..ec9677f1957803 --- /dev/null +++ b/benchmark/scenarios/material-ui-system-spaces/index.js @@ -0,0 +1,10 @@ +import { spacing } from '@material-ui/system'; + +export default function MaterialUISystemSpaces() { + spacing({ + theme: {}, + p: [1, 2, 3], + }); + + return null; +} diff --git a/benchmark/scenarios/naked-styled-components/index.js b/benchmark/scenarios/naked-styled-components/index.js new file mode 100644 index 00000000000000..059054f8780231 --- /dev/null +++ b/benchmark/scenarios/naked-styled-components/index.js @@ -0,0 +1,30 @@ +import * as React from 'react'; +import { createMuiTheme } from '@material-ui/core/styles'; +import { spacing } from '@material-ui/system'; +import styledComponents, { + ThemeProvider as StyledComponentsThemeProvider, +} from 'styled-components'; +import { logReactMetrics } from '../utils'; + +const materialSystemTheme = createMuiTheme(); +const NakedStyleComponents = styledComponents('div')(spacing); + +export default function NakedStyledComponents() { + return ( + + {new Array(1000).fill().map(() => ( + + + styled-components + + + ))} + + ); +} diff --git a/benchmark/scenarios/noop/index.js b/benchmark/scenarios/noop/index.js new file mode 100644 index 00000000000000..feeed026e3f1ab --- /dev/null +++ b/benchmark/scenarios/noop/index.js @@ -0,0 +1,3 @@ +export default function Noop() { + return null; +} diff --git a/benchmark/scenarios/styled-components-box-material-ui-system/index.js b/benchmark/scenarios/styled-components-box-material-ui-system/index.js new file mode 100644 index 00000000000000..fd865f4c6eefde --- /dev/null +++ b/benchmark/scenarios/styled-components-box-material-ui-system/index.js @@ -0,0 +1,31 @@ +import * as React from 'react'; +import { createMuiTheme } from '@material-ui/core/styles'; +import styledComponents, { + ThemeProvider as StyledComponentsThemeProvider, +} from 'styled-components'; +import { spacing, palette, typography, compose } from '@material-ui/system'; +import { logReactMetrics } from '../utils'; + +const materialSystem = compose(palette, spacing, typography); +const materialSystemTheme = createMuiTheme(); +const BoxMaterialSystem = styledComponents('div')(materialSystem); + +export default function StyledComponentsBoxMaterialUISystem() { + return ( + + {new Array(1000).fill().map(() => ( + + + @material-ui/system + + + ))} + + ); +} diff --git a/benchmark/scenarios/styled-components-box-styled-system/index.js b/benchmark/scenarios/styled-components-box-styled-system/index.js new file mode 100644 index 00000000000000..3d618afb296476 --- /dev/null +++ b/benchmark/scenarios/styled-components-box-styled-system/index.js @@ -0,0 +1,36 @@ +import * as React from 'react'; +import { createMuiTheme } from '@material-ui/core/styles'; +import styledComponents, { + ThemeProvider as StyledComponentsThemeProvider, +} from 'styled-components'; +import { space, color, fontFamily, fontSize, compose } from 'styled-system'; +import { logReactMetrics } from '../utils'; + +const styledSystem = compose(color, space, fontFamily, fontSize); +const BoxStyledSystem = styledComponents('div')(styledSystem); + +const styledSystemTheme = createMuiTheme(); +styledSystemTheme.breakpoints = ['40em', '52em', '64em']; +styledSystemTheme.colors = styledSystemTheme.palette; +styledSystemTheme.fontSizes = styledSystemTheme.typography; +styledSystemTheme.fonts = styledSystemTheme.typography; + +export default function StyledComponentsBoxStyledSystem() { + return ( + + {new Array(1000).fill().map(() => ( + + + styled-system + + + ))} + + ); +} diff --git a/benchmark/scenarios/styled-system-colors/index.js b/benchmark/scenarios/styled-system-colors/index.js new file mode 100644 index 00000000000000..e3265ba3f95516 --- /dev/null +++ b/benchmark/scenarios/styled-system-colors/index.js @@ -0,0 +1,10 @@ +import { color } from 'styled-system'; + +export default function StyledSystemColors() { + color({ + theme: {}, + bg: ['red', 'blue'], + }); + + return null; +} diff --git a/benchmark/scenarios/styled-system-compose/index.js b/benchmark/scenarios/styled-system-compose/index.js new file mode 100644 index 00000000000000..be8f1305cda567 --- /dev/null +++ b/benchmark/scenarios/styled-system-compose/index.js @@ -0,0 +1,22 @@ +import { createMuiTheme } from '@material-ui/core/styles'; +import { space, color, fontFamily, fontSize, compose } from 'styled-system'; + +const styledSystem = compose(color, space, fontFamily, fontSize); +const styledSystemTheme = createMuiTheme(); +styledSystemTheme.breakpoints = ['40em', '52em', '64em']; +styledSystemTheme.colors = styledSystemTheme.palette; +styledSystemTheme.fontSizes = styledSystemTheme.typography; +styledSystemTheme.fonts = styledSystemTheme.typography; + +export default function StyledSystemCompose() { + styledSystem({ + theme: styledSystemTheme, + color: 'primary.main', + bg: 'background.paper', + fontFamily: 'h6.fontFamily', + fontSize: ['h6.fontSize', 'h4.fontSize', 'h3.fontSize'], + p: [2, 3, 4], + }); + + return null; +} diff --git a/benchmark/scenarios/styled-system-spaces/index.js b/benchmark/scenarios/styled-system-spaces/index.js new file mode 100644 index 00000000000000..41c78350b5c97e --- /dev/null +++ b/benchmark/scenarios/styled-system-spaces/index.js @@ -0,0 +1,10 @@ +import { space } from 'styled-system'; + +export default function StyledSystemSpaces() { + space({ + theme: {}, + p: [1, 2, 3], + }); + + return null; +} diff --git a/benchmark/scenarios/utils/index.js b/benchmark/scenarios/utils/index.js new file mode 100644 index 00000000000000..425fa78c72c2ff --- /dev/null +++ b/benchmark/scenarios/utils/index.js @@ -0,0 +1,22 @@ +/* eslint-disable import/prefer-default-export */ + +export const logReactMetrics = ( + id, // the "id" prop of the Profiler tree that has just committed + phase, // either "mount" (if the tree just mounted) or "update" (if it re-rendered) + actualDuration, // time spent rendering the committed update + baseDuration, // estimated time to render the entire subtree without memoization + startTime, // when React began rendering this update + commitTime, // when React committed this update + interactions, // the Set of interactions belonging to this update +) => { + // eslint-disable-next-line no-console + console.info({ + id, + phase, + actualDuration, + baseDuration, + startTime, + commitTime, + interactions, + }); +}; diff --git a/benchmark/scripts/benchmark.js b/benchmark/scripts/benchmark.js new file mode 100644 index 00000000000000..efce8715cb8eba --- /dev/null +++ b/benchmark/scripts/benchmark.js @@ -0,0 +1,147 @@ +/* eslint-disable no-console */ +/* eslint-disable no-await-in-loop */ +const puppeteer = require('puppeteer'); +const handler = require('serve-handler'); +const http = require('http'); + +const PORT = 1122; +const APP = 'benchmark'; + +function createServer(options) { + const { port } = options; + const server = http.createServer((request, response) => { + return handler(request, response); + }); + + function close() { + return new Promise((resolve, reject) => { + server.close((error) => { + if (error !== undefined) { + reject(error); + } else { + resolve(); + } + }); + }); + } + + return new Promise((resolve) => { + server.listen(port, () => { + resolve({ close }); + }); + }); +} + +async function createBrowser() { + const browser = await puppeteer.launch(); + + return { + openPage: async (url) => { + const page = await browser.newPage(); + await page.goto(url); + + return page; + }, + close: () => browser.close(), + }; +} + +const getMedian = (measures) => { + const length = measures.length; + measures.sort(); + if (length % 2 === 0) { + return (measures[length / 2] + measures[length / 2 - 1]) / 2; + } + return measures[parseInt(length / 2, 10)]; +}; + +const printMeasure = (name, measures) => { + console.log(`\n${name}:\n`); + + let sum = 0; + const totalNum = measures.length; + + measures.forEach((measure) => { + sum += measure; + console.log(`${measure.toFixed(2)}ms`); + }); + + console.log('-------------'); + console.log(`Avg: ${Number(sum / totalNum).toFixed(2)}ms`); + console.log(`Median: ${Number(getMedian(measures)).toFixed(2)}ms`); +}; + +async function runMeasures(browser, testCaseName, testCase, times) { + const measures = []; + + for (let i = 0; i < times; i += 1) { + const url = `http://localhost:${PORT}/${APP}?${testCase}`; + const page = await browser.openPage(url); + + const benchmark = await page.evaluate(() => { + return window.timing.render; + }); + + measures.push(benchmark); + await page.close(); + } + + printMeasure(testCaseName, measures); + + return measures; +} + +async function run() { + const [server, browser] = await Promise.all([createServer({ port: PORT }), createBrowser()]); + + try { + await runMeasures(browser, 'noop (baseline)', './noop/index.js', 10); + await runMeasures( + browser, + '@material-ui/system colors', + './material-ui-system-colors/index.js', + 10, + ); + await runMeasures(browser, 'styled-system colors', './styled-system-colors/index.js', 10); + await runMeasures( + browser, + '@material-ui/system spaces', + './material-ui-system-spaces/index.js', + 10, + ); + await runMeasures(browser, 'styled-system spaces', './styled-system-spaces/index.js', 10); + await runMeasures( + browser, + '@material-ui/system compose', + './material-ui-system-compose/index.js', + 10, + ); + await runMeasures(browser, 'styled-system compose', './styled-system-compose/index.js', 10); + await runMeasures( + browser, + '@material-ui/core all-inclusive', + './material-ui-system-all-inclusive/index.js', + 10, + ); + await runMeasures( + browser, + 'styled-components Box + @material-ui/system', + './styled-components-box-material-ui-system/index.js', + 10, + ); + await runMeasures( + browser, + 'styled-components Box + styled-system', + './styled-components-box-styled-system/index.js', + 10, + ); + await runMeasures(browser, 'Box emotion', './box-emotion/index.js', 10); + await runMeasures(browser, 'Box @material-ui/styles', './box-material-ui-styles/index.js', 10); + await runMeasures(browser, 'Box styled-components', './box-styled-components/index.js', 10); + await runMeasures(browser, 'Naked styled-components', './naked-styled-components/index.js', 10); + } finally { + await Promise.all([browser.close(), server.close()]); + } +} + +run(); diff --git a/benchmark/webpack.config.js b/benchmark/webpack.config.js new file mode 100644 index 00000000000000..fc8ca0b6e73d2a --- /dev/null +++ b/benchmark/webpack.config.js @@ -0,0 +1,29 @@ +const path = require('path'); +const webpackBaseConfig = require('../webpackBaseConfig'); + +module.exports = { + ...webpackBaseConfig, + entry: path.resolve(__dirname, 'index.js'), + mode: 'production', + output: { + path: path.resolve(__dirname, '../tmp'), + filename: 'benchmark.js', + }, + module: { + ...webpackBaseConfig.module, + rules: webpackBaseConfig.module.rules.concat([ + { + test: /\.(jpg|gif|png)$/, + loader: 'url-loader', + }, + ]), + }, + resolve: { + ...webpackBaseConfig.resolve, + alias: { + ...webpackBaseConfig.resolve.alias, + 'react-dom$': 'react-dom/profiling', + 'scheduler/tracing': 'scheduler/tracing-profiling', + }, + }, +}; diff --git a/package.json b/package.json index 8b16500fc2a151..26ccdcf2680055 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "proptypes": "cross-env BABEL_ENV=test babel-node --extensions \".tsx,.ts,.js\" ./scripts/generateProptypes.ts", "deduplicate": "node scripts/deduplicate.js", "argos": "argos upload test/regressions/screenshots/chrome --token $ARGOS_TOKEN", + "benchmark": "yarn webpack --config benchmark/webpack.config.js && node benchmark/scripts/benchmark.js", "build:codesandbox": "lerna run --parallel --scope \"@material-ui/*\" build", "docs:api": "rimraf ./docs/pages/api-docs && yarn docs:api:build", "docs:api:build": "cross-env BABEL_ENV=test __NEXT_EXPORT_TRAILING_SLASH=true babel-node --extensions \".tsx,.ts,.js\" ./docs/scripts/buildApi.ts ./docs/pages/api-docs ./packages/material-ui/src ./packages/material-ui-lab/src", @@ -142,6 +143,7 @@ "rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-size-snapshot": "^0.12.0", "rollup-plugin-terser": "^7.0.0", + "serve-handler": "^6.1.3", "sinon": "^9.0.0", "tslint": "5.14.0", "typescript": "^4.0.2", @@ -149,8 +151,8 @@ "url-loader": "^4.1.0", "vrtest-mui": "^0.3.4", "webpack": "^4.41.0", - "webpack-cli": "^3.3.9", "webpack-bundle-analyzer": "^3.9.0", + "webpack-cli": "^3.3.9", "yargs": "^16.0.3", "yarn-deduplicate": "^3.0.0" }, diff --git a/yarn.lock b/yarn.lock index ab209da6e71e9b..e06b3a798ea814 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4529,6 +4529,11 @@ byte-size@^5.0.1: resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-5.0.1.tgz#4b651039a5ecd96767e71a3d7ed380e48bed4191" integrity sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw== +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + bytes@3.1.0, bytes@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" @@ -5287,6 +5292,11 @@ contains-path@^0.1.0: resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= + content-disposition@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" @@ -7421,6 +7431,13 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fast-url-parser@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" + integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0= + dependencies: + punycode "^1.3.2" + fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -10699,6 +10716,18 @@ mime-db@1.44.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== + +mime-types@2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== + dependencies: + mime-db "~1.33.0" + mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.19, mime-types@~2.1.24: version "2.1.27" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" @@ -12137,6 +12166,11 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= +path-is-inside@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" @@ -12157,6 +12191,11 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-to-regexp@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" + integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ== + path-to-regexp@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" @@ -12653,7 +12692,7 @@ punycode@1.3.2: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= -punycode@^1.2.4: +punycode@^1.2.4, punycode@^1.3.2: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= @@ -12776,6 +12815,11 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" +range-parser@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= + range-parser@^1.2.1, range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" @@ -13867,9 +13911,9 @@ run-queue@^1.0.0, run-queue@^1.0.3: aproba "^1.1.1" rxjs@^6.4.0: - version "6.5.4" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" - integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== + version "6.6.3" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" + integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ== dependencies: tslib "^1.9.0" @@ -14038,6 +14082,20 @@ serialize-javascript@^5.0.1: dependencies: randombytes "^2.1.0" +serve-handler@^6.1.3: + version "6.1.3" + resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.3.tgz#1bf8c5ae138712af55c758477533b9117f6435e8" + integrity sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w== + dependencies: + bytes "3.0.0" + content-disposition "0.5.2" + fast-url-parser "1.1.3" + mime-types "2.1.18" + minimatch "3.0.4" + path-is-inside "1.0.2" + path-to-regexp "2.2.1" + range-parser "1.2.0" + serve-static@1.14.1: version "1.14.1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"