diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2018-05-29 17:00:54 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2018-05-29 20:20:47 +0200 |
commit | 95220229b1d52f0acd4f1c0d4358e9fed610c3ee (patch) | |
tree | 37ce44f787c6a22aca324047efbe8bcb41b38689 | |
parent | 9c10956d8a65e1e3a851691d69cee367ac4e0869 (diff) | |
download | sonarqube-95220229b1d52f0acd4f1c0d4358e9fed610c3ee.tar.gz sonarqube-95220229b1d52f0acd4f1c0d4358e9fed610c3ee.zip |
SONAR-10675 Decrease JavaScript boot-up time (#283)
29 files changed, 504 insertions, 349 deletions
diff --git a/server/sonar-bitbucketcloud/.babelrc b/server/sonar-bitbucketcloud/.babelrc index 2962b9304d5..a14ae9bb095 100644 --- a/server/sonar-bitbucketcloud/.babelrc +++ b/server/sonar-bitbucketcloud/.babelrc @@ -1,40 +1,35 @@ { "presets": [ - ["env", { - "modules": false, - "targets": { - "browsers": [ - "last 3 Chrome versions", - "last 3 Firefox versions", - "last 3 Safari versions", - "last 3 Edge versions", - "IE 11" - ] - }, - "useBuiltIns": true - }], + [ + "env", + { + "modules": false, + "targets": { + "browsers": [ + "last 3 Chrome versions", + "last 3 Firefox versions", + "last 3 Safari versions", + "last 3 Edge versions", + "IE 11" + ] + }, + "useBuiltIns": true + } + ], "react" ], "plugins": [ "transform-class-properties", - ["transform-object-rest-spread", { - // use built-in `Object.assign` - "useBuiltIns": true - }] + // use built-in `Object.assign` + ["transform-object-rest-spread", { "useBuiltIns": true }], + "lodash" ], "env": { "production": { - "plugins": [ - "syntax-dynamic-import", - "transform-react-constant-elements" - ] + "plugins": ["syntax-dynamic-import", "transform-react-constant-elements"] }, "development": { - "plugins": [ - "syntax-dynamic-import", - "transform-react-jsx-source", - "transform-react-jsx-self" - ] + "plugins": ["syntax-dynamic-import", "transform-react-jsx-source", "transform-react-jsx-self"] }, "test": { "plugins": [ @@ -45,7 +40,5 @@ ] } }, - "ignore": [ - "**/libs/**" - ] + "ignore": ["**/libs/**"] } diff --git a/server/sonar-bitbucketcloud/package.json b/server/sonar-bitbucketcloud/package.json index a703523cb44..a73c2d1c77c 100644 --- a/server/sonar-bitbucketcloud/package.json +++ b/server/sonar-bitbucketcloud/package.json @@ -36,6 +36,7 @@ "babel-jest": "22.4.3", "babel-loader": "7.1.4", "babel-plugin-dynamic-import-node": "1.2.0", + "babel-plugin-lodash": "3.3.2", "babel-plugin-syntax-dynamic-import": "6.18.0", "babel-plugin-transform-class-properties": "6.24.1", "babel-plugin-transform-object-rest-spread": "6.26.0", diff --git a/server/sonar-bitbucketcloud/yarn.lock b/server/sonar-bitbucketcloud/yarn.lock index 2ba27285585..4064a564d36 100644 --- a/server/sonar-bitbucketcloud/yarn.lock +++ b/server/sonar-bitbucketcloud/yarn.lock @@ -751,6 +751,13 @@ babel-helper-hoist-variables@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" +babel-helper-module-imports@^7.0.0-beta.3: + version "7.0.0-beta.3" + resolved "https://registry.yarnpkg.com/babel-helper-module-imports/-/babel-helper-module-imports-7.0.0-beta.3.tgz#e15764e3af9c8e11810c09f78f498a2bdc71585a" + dependencies: + babel-types "7.0.0-beta.3" + lodash "^4.2.0" + babel-helper-optimise-call-expression@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" @@ -848,6 +855,16 @@ babel-plugin-jest-hoist@^22.4.3: version "22.4.3" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.3.tgz#7d8bcccadc2667f96a0dcc6afe1891875ee6c14a" +babel-plugin-lodash@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.3.2.tgz#da3a5b49ba27447f54463f6c4fa81396ccdd463f" + dependencies: + babel-helper-module-imports "^7.0.0-beta.3" + babel-types "^6.26.0" + glob "^7.1.1" + lodash "^4.17.4" + require-package-name "^2.0.1" + babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" @@ -1263,6 +1280,14 @@ babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: invariant "^2.2.2" lodash "^4.17.4" +babel-types@7.0.0-beta.3: + version "7.0.0-beta.3" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-7.0.0-beta.3.tgz#cd927ca70e0ae8ab05f4aab83778cfb3e6eb20b4" + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" + babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" @@ -4786,7 +4811,7 @@ lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -lodash@4.17.10, lodash@^4.17.10, lodash@^4.17.5: +lodash@4.17.10, lodash@^4.17.10, lodash@^4.17.5, lodash@^4.2.0: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -6610,6 +6635,10 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" +require-package-name@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9" + require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -7390,6 +7419,10 @@ to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" diff --git a/server/sonar-vsts/.babelrc b/server/sonar-vsts/.babelrc index 2962b9304d5..a14ae9bb095 100644 --- a/server/sonar-vsts/.babelrc +++ b/server/sonar-vsts/.babelrc @@ -1,40 +1,35 @@ { "presets": [ - ["env", { - "modules": false, - "targets": { - "browsers": [ - "last 3 Chrome versions", - "last 3 Firefox versions", - "last 3 Safari versions", - "last 3 Edge versions", - "IE 11" - ] - }, - "useBuiltIns": true - }], + [ + "env", + { + "modules": false, + "targets": { + "browsers": [ + "last 3 Chrome versions", + "last 3 Firefox versions", + "last 3 Safari versions", + "last 3 Edge versions", + "IE 11" + ] + }, + "useBuiltIns": true + } + ], "react" ], "plugins": [ "transform-class-properties", - ["transform-object-rest-spread", { - // use built-in `Object.assign` - "useBuiltIns": true - }] + // use built-in `Object.assign` + ["transform-object-rest-spread", { "useBuiltIns": true }], + "lodash" ], "env": { "production": { - "plugins": [ - "syntax-dynamic-import", - "transform-react-constant-elements" - ] + "plugins": ["syntax-dynamic-import", "transform-react-constant-elements"] }, "development": { - "plugins": [ - "syntax-dynamic-import", - "transform-react-jsx-source", - "transform-react-jsx-self" - ] + "plugins": ["syntax-dynamic-import", "transform-react-jsx-source", "transform-react-jsx-self"] }, "test": { "plugins": [ @@ -45,7 +40,5 @@ ] } }, - "ignore": [ - "**/libs/**" - ] + "ignore": ["**/libs/**"] } diff --git a/server/sonar-vsts/package.json b/server/sonar-vsts/package.json index 89d6479ef8e..0a03b0fed1f 100644 --- a/server/sonar-vsts/package.json +++ b/server/sonar-vsts/package.json @@ -25,6 +25,7 @@ "babel-jest": "22.0.6", "babel-loader": "7.1.4", "babel-plugin-dynamic-import-node": "1.1.0", + "babel-plugin-lodash": "3.3.2", "babel-plugin-syntax-dynamic-import": "6.18.0", "babel-plugin-transform-class-properties": "6.22.0", "babel-plugin-transform-object-rest-spread": "6.26.0", diff --git a/server/sonar-vsts/yarn.lock b/server/sonar-vsts/yarn.lock index 8b3d6df8060..093fd074912 100644 --- a/server/sonar-vsts/yarn.lock +++ b/server/sonar-vsts/yarn.lock @@ -536,6 +536,13 @@ babel-helper-hoist-variables@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" +babel-helper-module-imports@^7.0.0-beta.3: + version "7.0.0-beta.3" + resolved "https://registry.yarnpkg.com/babel-helper-module-imports/-/babel-helper-module-imports-7.0.0-beta.3.tgz#e15764e3af9c8e11810c09f78f498a2bdc71585a" + dependencies: + babel-types "7.0.0-beta.3" + lodash "^4.2.0" + babel-helper-optimise-call-expression@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" @@ -633,6 +640,16 @@ babel-plugin-jest-hoist@^22.4.1: version "22.4.1" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.1.tgz#d712fe5da8b6965f3191dacddbefdbdf4fb66d63" +babel-plugin-lodash@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.3.2.tgz#da3a5b49ba27447f54463f6c4fa81396ccdd463f" + dependencies: + babel-helper-module-imports "^7.0.0-beta.3" + babel-types "^6.26.0" + glob "^7.1.1" + lodash "^4.17.4" + require-package-name "^2.0.1" + babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" @@ -1031,6 +1048,14 @@ babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: invariant "^2.2.2" lodash "^4.17.4" +babel-types@7.0.0-beta.3: + version "7.0.0-beta.3" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-7.0.0-beta.3.tgz#cd927ca70e0ae8ab05f4aab83778cfb3e6eb20b4" + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" + babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" @@ -4471,6 +4496,10 @@ lodash@4.17.4, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.2, l version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" +lodash@^4.2.0: + version "4.17.10" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + log-symbols@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" @@ -6221,6 +6250,10 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" +require-package-name@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9" + require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -6969,6 +7002,10 @@ to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" diff --git a/server/sonar-web/.babelrc b/server/sonar-web/.babelrc index 2962b9304d5..a14ae9bb095 100644 --- a/server/sonar-web/.babelrc +++ b/server/sonar-web/.babelrc @@ -1,40 +1,35 @@ { "presets": [ - ["env", { - "modules": false, - "targets": { - "browsers": [ - "last 3 Chrome versions", - "last 3 Firefox versions", - "last 3 Safari versions", - "last 3 Edge versions", - "IE 11" - ] - }, - "useBuiltIns": true - }], + [ + "env", + { + "modules": false, + "targets": { + "browsers": [ + "last 3 Chrome versions", + "last 3 Firefox versions", + "last 3 Safari versions", + "last 3 Edge versions", + "IE 11" + ] + }, + "useBuiltIns": true + } + ], "react" ], "plugins": [ "transform-class-properties", - ["transform-object-rest-spread", { - // use built-in `Object.assign` - "useBuiltIns": true - }] + // use built-in `Object.assign` + ["transform-object-rest-spread", { "useBuiltIns": true }], + "lodash" ], "env": { "production": { - "plugins": [ - "syntax-dynamic-import", - "transform-react-constant-elements" - ] + "plugins": ["syntax-dynamic-import", "transform-react-constant-elements"] }, "development": { - "plugins": [ - "syntax-dynamic-import", - "transform-react-jsx-source", - "transform-react-jsx-self" - ] + "plugins": ["syntax-dynamic-import", "transform-react-jsx-source", "transform-react-jsx-self"] }, "test": { "plugins": [ @@ -45,7 +40,5 @@ ] } }, - "ignore": [ - "**/libs/**" - ] + "ignore": ["**/libs/**"] } diff --git a/server/sonar-web/config/webpack.config.js b/server/sonar-web/config/webpack.config.js index c5439551c5c..30cccdbd7ae 100644 --- a/server/sonar-web/config/webpack.config.js +++ b/server/sonar-web/config/webpack.config.js @@ -23,6 +23,7 @@ const CleanWebpackPlugin = require('clean-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); +const LodashPlugin = require('lodash-webpack-plugin'); const webpack = require('webpack'); const InterpolateHtmlPlugin = require('./InterpolateHtmlPlugin'); const paths = require('./paths'); @@ -77,7 +78,6 @@ module.exports = ({ production = true }) => ({ test: /\.md$/, use: 'raw-loader' }, - { test: require.resolve('lodash'), loader: 'expose-loader?_' }, { test: require.resolve('react'), loader: 'expose-loader?React' }, { test: require.resolve('react-dom'), loader: 'expose-loader?ReactDOM' }, { @@ -113,6 +113,15 @@ module.exports = ({ production = true }) => ({ chunkFilename: 'css/[name].[chunkhash:8].chunk.css' }), + new LodashPlugin({ + // keep these features + // https://github.com/lodash/lodash-webpack-plugin#feature-sets + shorthands: true, + collections: true, + memoizing: true, + flattening: true + }), + new HtmlWebpackPlugin({ inject: false, template: paths.appHtml, @@ -126,5 +135,12 @@ module.exports = ({ production = true }) => ({ ].filter(Boolean), optimization: { splitChunks: { chunks: 'all' } - } + }, + performance: production + ? { + hints: 'error', + maxEntrypointSize: 700000, // ~700kb, recommended: 250kb + maxAssetSize: 400000 // ~400kb, recommended: 250kb + } + : undefined }); diff --git a/server/sonar-web/package.json b/server/sonar-web/package.json index fbf2659e4b7..b199b8a9565 100644 --- a/server/sonar-web/package.json +++ b/server/sonar-web/package.json @@ -63,6 +63,7 @@ "babel-jest": "22.4.3", "babel-loader": "7.1.4", "babel-plugin-dynamic-import-node": "1.2.0", + "babel-plugin-lodash": "3.3.2", "babel-plugin-syntax-dynamic-import": "6.18.0", "babel-plugin-transform-class-properties": "^6.22.0", "babel-plugin-transform-object-rest-spread": "6.26.0", @@ -93,6 +94,7 @@ "html-webpack-plugin": "3.2.0", "jest": "22.4.3", "lint-staged": "4.3.0", + "lodash-webpack-plugin": "0.11.5", "mini-css-extract-plugin": "0.4.0", "postcss-calc": "6.0.1", "postcss-custom-properties": "6.2.0", diff --git a/server/sonar-web/src/main/js/app/components/AdminContainer.tsx b/server/sonar-web/src/main/js/app/components/AdminContainer.tsx index 20284555423..c81e450022d 100644 --- a/server/sonar-web/src/main/js/app/components/AdminContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/AdminContainer.tsx @@ -41,23 +41,29 @@ import { Extension } from '../types'; import { PluginPendingResult } from '../../api/plugins'; import handleRequiredAuthorization from '../utils/handleRequiredAuthorization'; -interface Props { +interface StateProps { appState: { adminPages: Extension[]; organizationsEnabled: boolean; version: string; }; - editionsUrl: string; editionStatus?: EditionStatus; + editionsUrl: string; + pendingPlugins: PluginPendingResult; +} + +interface DispatchProps { fetchEditions: (url: string, version: string) => void; fetchPendingPlugins: () => void; - location: {}; - pendingPlugins: PluginPendingResult; setAdminPages: (adminPages: Extension[]) => void; setEditionStatus: (editionStatus: EditionStatus) => void; } -class AdminContainer extends React.PureComponent<Props> { +interface OwnProps { + location: {}; +} + +class AdminContainer extends React.PureComponent<StateProps & DispatchProps & OwnProps> { static contextTypes = { canAdmin: PropTypes.bool.isRequired }; @@ -105,13 +111,18 @@ class AdminContainer extends React.PureComponent<Props> { } } -const mapStateToProps = (state: any) => ({ +const mapStateToProps = (state: any): StateProps => ({ appState: getAppState(state), editionStatus: getMarketplaceEditionStatus(state), editionsUrl: (getGlobalSettingValue(state, 'sonar.editions.jsonUrl') || {}).value, pendingPlugins: getMarketplacePendingPlugins(state) }); -const mapDispatchToProps = { setAdminPages, setEditionStatus, fetchEditions, fetchPendingPlugins }; +const mapDispatchToProps: DispatchProps = { + setAdminPages, + setEditionStatus, + fetchEditions, + fetchPendingPlugins +}; -export default connect(mapStateToProps, mapDispatchToProps)(AdminContainer as any); +export default connect(mapStateToProps, mapDispatchToProps)(AdminContainer); diff --git a/server/sonar-web/src/main/js/app/components/GlobalFooterSonarCloud.tsx b/server/sonar-web/src/main/js/app/components/GlobalFooterSonarCloud.tsx index 6dd0208f57a..ad0c7d3b84d 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalFooterSonarCloud.tsx +++ b/server/sonar-web/src/main/js/app/components/GlobalFooterSonarCloud.tsx @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { getYear } from 'date-fns'; +import * as getYear from 'date-fns/get_year'; import { translate } from '../../helpers/l10n'; export default function GlobalFooterSonarCloud() { diff --git a/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooterSonarCloud-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooterSonarCloud-test.tsx index 27ba87d8e89..1583bd701c1 100644 --- a/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooterSonarCloud-test.tsx +++ b/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooterSonarCloud-test.tsx @@ -21,9 +21,7 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import GlobalFooterSonarCloud from '../GlobalFooterSonarCloud'; -jest.mock('date-fns', () => ({ - getYear: jest.fn(() => 2018) -})); +jest.mock('date-fns/get_year', () => jest.fn(() => 2018)); it('should render correctly', () => { expect(shallow(<GlobalFooterSonarCloud />)).toMatchSnapshot(); diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx index 9e1eabf9be6..d7525d24054 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNav.tsx @@ -23,7 +23,6 @@ import GlobalNavBranding from './GlobalNavBranding'; import GlobalNavMenu from './GlobalNavMenu'; import GlobalNavExplore from './GlobalNavExplore'; import GlobalNavUserContainer from './GlobalNavUserContainer'; -import GlobalNavPlus from './GlobalNavPlus'; import Search from '../../search/Search'; import EmbedDocsPopupHelper from '../../embed-docs-modal/EmbedDocsPopupHelper'; import * as theme from '../../../theme'; @@ -31,12 +30,15 @@ import { isLoggedIn, CurrentUser, AppState } from '../../../types'; import OnboardingModal from '../../../../apps/tutorials/onboarding/OnboardingModal'; import NavBar from '../../../../components/nav/NavBar'; import Tooltip from '../../../../components/controls/Tooltip'; +import { lazyLoad } from '../../../../components/lazyLoad'; import { translate } from '../../../../helpers/l10n'; import { getCurrentUser, getAppState, getGlobalSettingValue } from '../../../../store/rootReducer'; import { skipOnboarding } from '../../../../store/users/actions'; import { SuggestionLink } from '../../embed-docs-modal/SuggestionsProvider'; import './GlobalNav.css'; +const GlobalNavPlus = lazyLoad(() => import('./GlobalNavPlus')); + interface StateProps { appState: AppState; currentUser: CurrentUser; diff --git a/server/sonar-web/src/main/js/app/utils/startReactApp.js b/server/sonar-web/src/main/js/app/utils/startReactApp.js index a013773e344..6d143225d4a 100644 --- a/server/sonar-web/src/main/js/app/utils/startReactApp.js +++ b/server/sonar-web/src/main/js/app/utils/startReactApp.js @@ -24,24 +24,10 @@ import { Router, Route, IndexRoute, Redirect } from 'react-router'; import { Provider } from 'react-redux'; import getStore from './getStore'; import getHistory from './getHistory'; -import AppContextContainer from '../components/AppContextContainer'; import LocalizationContainer from '../components/LocalizationContainer'; import MigrationContainer from '../components/MigrationContainer'; import App from '../components/App'; import GlobalContainer from '../components/GlobalContainer'; -import SimpleContainer from '../components/SimpleContainer'; -import SimpleSessionsContainer from '../components/SimpleSessionsContainer'; -import Landing from '../components/Landing'; -import ProjectAdminContainer from '../components/ProjectAdminContainer'; -import ProjectPageExtension from '../components/extensions/ProjectPageExtension'; -import ProjectAdminPageExtension from '../components/extensions/ProjectAdminPageExtension'; -import PortfoliosPage from '../components/extensions/PortfoliosPage'; -import AdminContainer from '../components/AdminContainer'; -import GlobalPageExtension from '../components/extensions/GlobalPageExtension'; -import GlobalAdminPageExtension from '../components/extensions/GlobalAdminPageExtension'; -import MarkdownHelp from '../components/MarkdownHelp'; -import NotFound from '../components/NotFound'; -import OnboardingPage from '../../apps/tutorials/onboarding/OnboardingPage'; import aboutRoutes from '../../apps/about/routes'; import accountRoutes from '../../apps/account/routes'; import backgroundTasksRoutes from '../../apps/background-tasks/routes'; @@ -63,7 +49,6 @@ import organizationsRoutes from '../../apps/organizations/routes'; import permissionTemplatesRoutes from '../../apps/permission-templates/routes'; import portfolioRoutes from '../../apps/portfolio/routes'; import projectActivityRoutes from '../../apps/projectActivity/routes'; -import projectAdminRoutes from '../../apps/project-admin/routes'; import projectBranchesRoutes from '../../apps/projectBranches/routes'; import projectQualityGateRoutes from '../../apps/projectQualityGate/routes'; import projectQualityProfilesRoutes from '../../apps/projectQualityProfiles/routes'; @@ -150,23 +135,26 @@ const startReactApp = () => { <Redirect from="/view" to="/portfolio" /> <Redirect from="/users" to="/admin/users" /> - <Route path="markdown/help" component={MarkdownHelp} /> + <Route + path="markdown/help" + component={lazyLoad(() => import('../components/MarkdownHelp'))} + /> <Route component={LocalizationContainer}> - <Route component={SimpleContainer}> + <Route component={lazyLoad(() => import('../components/SimpleContainer'))}> <Route path="maintenance">{maintenanceRoutes}</Route> <Route path="setup">{setupRoutes}</Route> </Route> <Route component={MigrationContainer}> - <Route component={AppContextContainer}> - <Route component={SimpleSessionsContainer}> + <Route component={lazyLoad(() => import('../components/AppContextContainer'))}> + <Route component={lazyLoad(() => import('../components/SimpleSessionsContainer'))}> <Route path="/sessions" childRoutes={sessionsRoutes} /> </Route> </Route> <Route path="/" component={App}> - <IndexRoute component={Landing} /> + <IndexRoute component={lazyLoad(() => import('../components/Landing'))} /> <Route component={GlobalContainer}> <Route path="about" childRoutes={aboutRoutes} /> @@ -178,13 +166,24 @@ const startReactApp = () => { <Route path="issues" component={ExploreIssues} /> <Route path="projects" component={ExploreProjects} /> </Route> - <Route path="extension/:pluginKey/:extensionKey" component={GlobalPageExtension} /> + <Route + path="extension/:pluginKey/:extensionKey" + component={lazyLoad(() => import('../components/extensions/GlobalPageExtension'))} + /> <Route path="issues" component={IssuesPageSelector} /> - <Route path="onboarding" component={OnboardingPage} /> + <Route + path="onboarding" + component={lazyLoad(() => + import('../../apps/tutorials/onboarding/OnboardingPage') + )} + /> <Route path="organizations" childRoutes={organizationsRoutes} /> <Route path="projects" childRoutes={projectsRoutes} /> <Route path="quality_gates" childRoutes={qualityGatesRoutes} /> - <Route path="portfolios" component={PortfoliosPage} /> + <Route + path="portfolios" + component={lazyLoad(() => import('../components/extensions/PortfoliosPage'))} + /> <Route path="profiles" childRoutes={qualityProfilesRoutes} /> <Route path="web_api" childRoutes={webAPIRoutes} /> @@ -196,7 +195,9 @@ const startReactApp = () => { <Route path="project/activity" childRoutes={projectActivityRoutes} /> <Route path="project/extension/:pluginKey/:extensionKey" - component={ProjectPageExtension} + component={lazyLoad(() => + import('../components/extensions/ProjectPageExtension') + )} /> <Route path="project/issues" component={Issues} /> <Route path="project/quality_gate" childRoutes={projectQualityGateRoutes} /> @@ -204,25 +205,44 @@ const startReactApp = () => { path="project/quality_profiles" childRoutes={projectQualityProfilesRoutes} /> - <Route component={ProjectAdminContainer}> + <Route component={lazyLoad(() => import('../components/ProjectAdminContainer'))}> <Route path="custom_measures" childRoutes={customMeasuresRoutes} /> <Route path="project/admin/extension/:pluginKey/:extensionKey" - component={ProjectAdminPageExtension} + component={lazyLoad(() => + import('../components/extensions/ProjectAdminPageExtension') + )} /> <Route path="project/background_tasks" childRoutes={backgroundTasksRoutes} /> <Route path="project/branches" childRoutes={projectBranchesRoutes} /> <Route path="project/settings" childRoutes={settingsRoutes} /> <Route path="project_roles" childRoutes={projectPermissionsRoutes} /> <Route path="project/webhooks" childRoutes={webhooksRoutes} /> + <Route + path="project/deletion" + component={lazyLoad(() => + import('../../apps/project-admin/deletion/Deletion') + )} + /> + <Route + path="project/links" + component={lazyLoad(() => import('../../apps/project-admin/links/Links'))} + /> + <Route + path="project/key" + component={lazyLoad(() => import('../../apps/project-admin/key/Key'))} + /> </Route> - {projectAdminRoutes} </Route> - <Route component={AdminContainer} path="admin"> + <Route + component={lazyLoad(() => import('../components/AdminContainer'))} + path="admin"> <Route path="extension/:pluginKey/:extensionKey" - component={GlobalAdminPageExtension} + component={lazyLoad(() => + import('../components/extensions/GlobalAdminPageExtension') + )} /> <Route path="background_tasks" childRoutes={backgroundTasksRoutes} /> <Route path="custom_metrics" childRoutes={customMetricsRoutes} /> @@ -238,8 +258,11 @@ const startReactApp = () => { <Route path="webhooks" childRoutes={webhooksRoutes} /> </Route> </Route> - <Route path="not_found" component={NotFound} /> - <Route path="*" component={NotFound} /> + <Route + path="not_found" + component={lazyLoad(() => import('../components/NotFound'))} + /> + <Route path="*" component={lazyLoad(() => import('../components/NotFound'))} /> </Route> </Route> </Route> diff --git a/server/sonar-web/src/main/js/apps/organizations/routes.ts b/server/sonar-web/src/main/js/apps/organizations/routes.ts index e267926dce1..02c2bdaec00 100644 --- a/server/sonar-web/src/main/js/apps/organizations/routes.ts +++ b/server/sonar-web/src/main/js/apps/organizations/routes.ts @@ -18,28 +18,18 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { RouterState, RedirectFunction } from 'react-router'; -import OrganizationPageContainer from './components/OrganizationPage'; -import OrganizationContainer from './components/OrganizationContainer'; -import OrganizationProjects from './components/OrganizationProjects'; -import OrganizationAdminContainer from './components/OrganizationAdminContainer'; -import OrganizationEdit from './components/OrganizationEdit'; -import OrganizationMembersContainer from './components/OrganizationMembersContainer'; -import OrganizationDelete from './components/OrganizationDelete'; -import GlobalPermissionsApp from '../permissions/global/components/App'; -import PermissionTemplateApp from '../permission-templates/components/AppContainer'; -import ProjectManagementApp from '../projectsManagement/AppContainer'; import codingRulesRoutes from '../coding-rules/routes'; import qualityGatesRoutes from '../quality-gates/routes'; import qualityProfilesRoutes from '../quality-profiles/routes'; import webhooksRoutes from '../webhooks/routes'; -import Issues from '../issues/components/AppContainer'; -import GroupsApp from '../groups/components/App'; -import OrganizationPageExtension from '../../app/components/extensions/OrganizationPageExtension'; +import { lazyLoad } from '../../components/lazyLoad'; + +const OrganizationContainer = lazyLoad(() => import('./components/OrganizationContainer')); const routes = [ { path: ':organizationKey', - component: OrganizationPageContainer, + component: lazyLoad(() => import('./components/OrganizationPage')), childRoutes: [ { indexRoute: { @@ -52,19 +42,23 @@ const routes = [ { path: 'projects', component: OrganizationContainer, - childRoutes: [{ indexRoute: { component: OrganizationProjects } }] + childRoutes: [ + { indexRoute: { component: lazyLoad(() => import('./components/OrganizationProjects')) } } + ] }, { path: 'issues', component: OrganizationContainer, - childRoutes: [{ indexRoute: { component: Issues } }] + childRoutes: [ + { indexRoute: { component: lazyLoad(() => import('../issues/components/AppContainer')) } } + ] }, { path: 'members', - component: OrganizationMembersContainer + component: lazyLoad(() => import('./components/OrganizationMembersContainer')) }, { - path: 'rules', + path: 'rules', component: OrganizationContainer, childRoutes: codingRulesRoutes }, @@ -78,18 +72,29 @@ const routes = [ childRoutes: qualityGatesRoutes }, { - component: OrganizationAdminContainer, + component: lazyLoad(() => import('./components/OrganizationAdminContainer')), childRoutes: [ - { path: 'delete', component: OrganizationDelete }, - { path: 'edit', component: OrganizationEdit }, - { path: 'groups', component: GroupsApp }, - { path: 'permissions', component: GlobalPermissionsApp }, - { path: 'permission_templates', component: PermissionTemplateApp }, - { path: 'projects_management', component: ProjectManagementApp }, + { path: 'delete', component: lazyLoad(() => import('./components/OrganizationDelete')) }, + { path: 'edit', component: lazyLoad(() => import('./components/OrganizationEdit')) }, + { path: 'groups', component: lazyLoad(() => import('../groups/components/App')) }, + { + path: 'permissions', + component: lazyLoad(() => import('../permissions/global/components/App')) + }, + { + path: 'permission_templates', + component: lazyLoad(() => import('../permission-templates/components/AppContainer')) + }, + { + path: 'projects_management', + component: lazyLoad(() => import('../projectsManagement/AppContainer')) + }, { path: 'webhooks', childRoutes: webhooksRoutes }, { path: 'extension/:pluginKey/:extensionKey', - component: OrganizationPageExtension + component: lazyLoad(() => + import('../../app/components/extensions/OrganizationPageExtension') + ) } ] } diff --git a/server/sonar-web/src/main/js/apps/project-admin/routes.js b/server/sonar-web/src/main/js/apps/project-admin/routes.js deleted file mode 100644 index 78c051e7f89..00000000000 --- a/server/sonar-web/src/main/js/apps/project-admin/routes.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import React from 'react'; -import { Route } from 'react-router'; -import Deletion from './deletion/Deletion'; -import Links from './links/Links'; -import Key from './key/Key'; - -export default [ - <Route key="deletion" path="project/deletion" component={Deletion} />, - <Route key="links" path="project/links" component={Links} />, - <Route key="key" path="project/key" component={Key} /> -]; diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.tsx index 054f9777d03..2c9ab530964 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.tsx @@ -20,7 +20,8 @@ import * as React from 'react'; import { Link } from 'react-router'; import { sortBy } from 'lodash'; -import { isSameMinute, startOfMinute } from 'date-fns'; +import * as isSameMinute from 'date-fns/is_same_minute'; +import * as startOfMinute from 'date-fns/start_of_minute'; import ChangesList from './ChangesList'; import DateTimeFormatter from '../../../components/intl/DateTimeFormatter'; import { translate } from '../../../helpers/l10n'; diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/OrganizationStep-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/OrganizationStep-test.js.snap index 3f1d39e377e..4ff55018414 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/OrganizationStep-test.js.snap +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/OrganizationStep-test.js.snap @@ -80,40 +80,11 @@ exports[`works with existing organization 1`] = ` ] } > - <Select - arrowRenderer={[Function]} - autosize={true} - backspaceRemoves={true} - backspaceToRemoveMessage="Press backspace to remove {label}" + <LazyLoader className="input-super-large" - clearAllText="Clear all" clearRenderer={[Function]} - clearValueText="Clear value" clearable={false} - closeOnSelect={true} - deleteRemoves={true} - delimiter="," - disabled={false} - escapeClearsValue={true} - filterOptions={[Function]} - ignoreAccents={true} - ignoreCase={true} - inputProps={Object {}} - isLoading={false} - joinValues={false} - labelKey="label" - matchPos="any" - matchProp="any" - menuBuffer={0} - menuRenderer={[Function]} - multi={false} - noResultsText="No results found" - onBlurResetsInput={true} onChange={[Function]} - onCloseResetsInput={true} - onSelectResetsInput={true} - openOnClick={true} - optionComponent={[Function]} options={ Array [ Object { @@ -126,108 +97,156 @@ exports[`works with existing organization 1`] = ` }, ] } - pageSize={5} - placeholder="Select..." - removeSelected={true} - required={false} - rtl={false} - scrollMenuIntoView={true} - searchable={true} - simpleValue={false} - tabSelectsValue={true} - trimFilter={true} - valueComponent={[Function]} - valueKey="value" > - <div - className="Select input-super-large is-searchable Select--single" + <Select + arrowRenderer={[Function]} + autosize={true} + backspaceRemoves={true} + backspaceToRemoveMessage="Press backspace to remove {label}" + className="input-super-large" + clearAllText="Clear all" + clearRenderer={[Function]} + clearValueText="Clear value" + clearable={false} + closeOnSelect={true} + deleteRemoves={true} + delimiter="," + disabled={false} + escapeClearsValue={true} + filterOptions={[Function]} + ignoreAccents={true} + ignoreCase={true} + inputProps={Object {}} + isLoading={false} + joinValues={false} + labelKey="label" + matchPos="any" + matchProp="any" + menuBuffer={0} + menuRenderer={[Function]} + multi={false} + noResultsText="No results found" + onBlurResetsInput={true} + onChange={[Function]} + onCloseResetsInput={true} + onSelectResetsInput={true} + openOnClick={true} + optionComponent={[Function]} + options={ + Array [ + Object { + "label": "another", + "value": "another", + }, + Object { + "label": "user", + "value": "user", + }, + ] + } + pageSize={5} + placeholder="Select..." + removeSelected={true} + required={false} + rtl={false} + scrollMenuIntoView={true} + searchable={true} + simpleValue={false} + tabSelectsValue={true} + trimFilter={true} + valueComponent={[Function]} + valueKey="value" > <div - className="Select-control" - onKeyDown={[Function]} - onMouseDown={[Function]} - onTouchEnd={[Function]} - onTouchMove={[Function]} - onTouchStart={[Function]} + className="Select input-super-large is-searchable Select--single" > - <span - className="Select-multi-value-wrapper" - id="react-select-2--value" + <div + className="Select-control" + onKeyDown={[Function]} + onMouseDown={[Function]} + onTouchEnd={[Function]} + onTouchMove={[Function]} + onTouchStart={[Function]} > - <div - className="Select-placeholder" - > - Select... - </div> - <AutosizeInput - aria-activedescendant="react-select-2--value" - aria-expanded="false" - aria-haspopup="false" - aria-owns="" - className="Select-input" - injectStyles={true} - minWidth="5" - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - required={false} - role="combobox" - value="" + <span + className="Select-multi-value-wrapper" + id="react-select-2--value" > <div + className="Select-placeholder" + > + Select... + </div> + <AutosizeInput + aria-activedescendant="react-select-2--value" + aria-expanded="false" + aria-haspopup="false" + aria-owns="" className="Select-input" - style={ - Object { - "display": "inline-block", - } - } + injectStyles={true} + minWidth="5" + onBlur={[Function]} + onChange={[Function]} + onFocus={[Function]} + required={false} + role="combobox" + value="" > - <input - aria-activedescendant="react-select-2--value" - aria-expanded="false" - aria-haspopup="false" - aria-owns="" - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - required={false} - role="combobox" - style={ - Object { - "boxSizing": "content-box", - "width": "5px", - } - } - value="" - /> <div + className="Select-input" style={ Object { - "height": 0, - "left": 0, - "overflow": "scroll", - "position": "absolute", - "top": 0, - "visibility": "hidden", - "whiteSpace": "pre", + "display": "inline-block", } } - /> - </div> - </AutosizeInput> - </span> - <span - className="Select-arrow-zone" - onMouseDown={[Function]} - > + > + <input + aria-activedescendant="react-select-2--value" + aria-expanded="false" + aria-haspopup="false" + aria-owns="" + onBlur={[Function]} + onChange={[Function]} + onFocus={[Function]} + required={false} + role="combobox" + style={ + Object { + "boxSizing": "content-box", + "width": "5px", + } + } + value="" + /> + <div + style={ + Object { + "height": 0, + "left": 0, + "overflow": "scroll", + "position": "absolute", + "top": 0, + "visibility": "hidden", + "whiteSpace": "pre", + } + } + /> + </div> + </AutosizeInput> + </span> <span - className="Select-arrow" + className="Select-arrow-zone" onMouseDown={[Function]} - /> - </span> + > + <span + className="Select-arrow" + onMouseDown={[Function]} + /> + </span> + </div> </div> - </div> - </Select> + </Select> + </LazyLoader> </Select> </div> </div> diff --git a/server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx b/server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx index 188369030f9..fc8b7686a80 100644 --- a/server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx +++ b/server/sonar-web/src/main/js/components/SourceViewer/components/Line.tsx @@ -149,7 +149,7 @@ export default class Line extends React.PureComponent<Props> { <LineDuplications line={line} onClick={this.props.loadDuplications} /> )} - {times(duplicationsCount).map(index => ( + {times(duplicationsCount, index => ( <LineDuplicationBlock duplicated={duplications.includes(index)} index={index} diff --git a/server/sonar-web/src/main/js/components/controls/DateInput.tsx b/server/sonar-web/src/main/js/components/controls/DateInput.tsx index 886a43211e4..4da2144f9ac 100644 --- a/server/sonar-web/src/main/js/components/controls/DateInput.tsx +++ b/server/sonar-web/src/main/js/components/controls/DateInput.tsx @@ -19,12 +19,16 @@ */ import * as React from 'react'; import * as classNames from 'classnames'; -import DayPicker, { DayModifiers, Modifier, Modifiers } from 'react-day-picker'; +import { DayModifiers, Modifier, Modifiers } from 'react-day-picker'; import { intlShape, InjectedIntlProps } from 'react-intl'; import { range } from 'lodash'; -import { addMonths, subMonths, setYear, setMonth } from 'date-fns'; +import * as addMonths from 'date-fns/add_months'; +import * as setMonth from 'date-fns/set_month'; +import * as setYear from 'date-fns/set_year'; +import * as subMonths from 'date-fns/sub_months'; import OutsideClickHandler from './OutsideClickHandler'; import Select from './Select'; +import { lazyLoad } from '../lazyLoad'; import * as theme from '../../app/theme'; import CalendarIcon from '../icons-components/CalendarIcon'; import ChevronLeftIcon from '../icons-components/ChevronLeftIcon'; @@ -35,6 +39,8 @@ import { getShortMonthName, getWeekDayName, getShortWeekDayName } from '../../he import './DayPicker.css'; import './styles.css'; +const DayPicker = lazyLoad(() => import('react-day-picker')); + export interface Props { className?: string; currentMonth?: Date; diff --git a/server/sonar-web/src/main/js/components/controls/Select.tsx b/server/sonar-web/src/main/js/components/controls/Select.tsx index 8aa569de29b..aca10d86b70 100644 --- a/server/sonar-web/src/main/js/components/controls/Select.tsx +++ b/server/sonar-web/src/main/js/components/controls/Select.tsx @@ -18,18 +18,18 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import ReactSelect, { - Creatable as ReactCreatable, - Async, - ReactSelectProps, - ReactCreatableSelectProps, - ReactAsyncSelectProps -} from 'react-select'; +import { ReactSelectProps, ReactCreatableSelectProps, ReactAsyncSelectProps } from 'react-select'; import * as theme from '../../app/theme'; import ClearIcon from '../icons-components/ClearIcon'; import { ButtonIcon } from '../ui/buttons'; +import { lazyLoad } from '../lazyLoad'; import './react-select.css'; +const ReactSelectLib = import('react-select'); +const ReactSelect = lazyLoad(() => ReactSelectLib); +const ReactCreatable = lazyLoad(() => ReactSelectLib.then(lib => ({ default: lib.Creatable }))); +const ReactAsync = lazyLoad(() => ReactSelectLib.then(lib => ({ default: lib.Async }))); + function renderInput() { return ( <ButtonIcon className="button-tiny spacer-left text-middle" color={theme.gray60}> @@ -39,7 +39,7 @@ function renderInput() { } interface WithInnerRef { - innerRef?: (element: ReactSelect) => void; + innerRef?: (element: React.Component) => void; } export default function Select({ innerRef, ...props }: WithInnerRef & ReactSelectProps) { @@ -61,5 +61,5 @@ export function Creatable(props: ReactCreatableSelectProps) { // TODO figure out why `ref` prop is incompatible export function AsyncSelect(props: ReactAsyncSelectProps & { ref?: any }) { - return <Async {...props} />; + return <ReactAsync {...props} />; } diff --git a/server/sonar-web/src/main/js/components/controls/__tests__/DateInput-test.tsx b/server/sonar-web/src/main/js/components/controls/__tests__/DateInput-test.tsx index 564f884d920..82a5894856e 100644 --- a/server/sonar-web/src/main/js/components/controls/__tests__/DateInput-test.tsx +++ b/server/sonar-web/src/main/js/components/controls/__tests__/DateInput-test.tsx @@ -18,16 +18,20 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { subMonths, setMonth, setYear, addDays, subDays } from 'date-fns'; +import * as addDays from 'date-fns/add_days'; +import * as setMonth from 'date-fns/set_month'; +import * as setYear from 'date-fns/set_year'; +import * as subDays from 'date-fns/sub_days'; +import * as subMonths from 'date-fns/sub_months'; import DateInput, { Props } from '../DateInput'; import { shallowWithIntl } from '../../../helpers/testUtils'; import { parseDate } from '../../../helpers/dates'; -// need to mock, because react-day-picker uses `new Date()` as a default prop for `initialMonth` -jest.mock('react-day-picker', () => ({ - // eslint-disable-next-line func-name-matching - default: function DayPicker() { - return null; +jest.mock('../../lazyLoad', () => ({ + lazyLoad: () => { + return function DayPicker() { + return null; + }; } })); diff --git a/server/sonar-web/src/main/js/components/docs/DocInclude.tsx b/server/sonar-web/src/main/js/components/docs/DocInclude.tsx index 85298633439..d499b27c22c 100644 --- a/server/sonar-web/src/main/js/components/docs/DocInclude.tsx +++ b/server/sonar-web/src/main/js/components/docs/DocInclude.tsx @@ -18,7 +18,9 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import DocMarkdownBlock from './DocMarkdownBlock'; +import { lazyLoad } from '../lazyLoad'; + +const DocMarkdownBlock = lazyLoad(() => import('./DocMarkdownBlock')); interface Props { className?: string; diff --git a/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx b/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx index e064f15d2ee..c456c9ecd21 100644 --- a/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx +++ b/server/sonar-web/src/main/js/components/docs/DocTooltip.tsx @@ -18,8 +18,10 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import DocMarkdownBlock from './DocMarkdownBlock'; import HelpTooltip from '../controls/HelpTooltip'; +import { lazyLoad } from '../lazyLoad'; + +const DocMarkdownBlock = lazyLoad(() => import('./DocMarkdownBlock')); interface Props { className?: string; @@ -75,15 +77,15 @@ export default class DocTooltip extends React.PureComponent<Props, State> { }; renderOverlay() { - if (this.state.loading) { - return ( - <div className="abs-width-300"> + return ( + <div className="abs-width-300"> + {this.state.loading ? ( <i className="spinner" /> - </div> - ); - } - - return <DocMarkdownBlock className="cut-margins abs-width-300" content={this.state.content} />; + ) : ( + <DocMarkdownBlock className="cut-margins" content={this.state.content} /> + )} + </div> + ); } render() { diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap index cbdf355d855..cc1d24b0783 100644 --- a/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap +++ b/server/sonar-web/src/main/js/components/docs/__tests__/__snapshots__/DocTooltip-test.tsx.snap @@ -19,10 +19,14 @@ exports[`should render 2`] = ` <HelpTooltip onShow={[Function]} overlay={ - <DocMarkdownBlock - className="cut-margins abs-width-300" - content="this is *bold* text" - /> + <div + className="abs-width-300" + > + <LazyLoader + className="cut-margins" + content="this is *bold* text" + /> + </div> } /> `; diff --git a/server/sonar-web/src/main/js/components/ui/CoverageRating.tsx b/server/sonar-web/src/main/js/components/ui/CoverageRating.tsx index 10ffc9e849b..6814eea2f1d 100644 --- a/server/sonar-web/src/main/js/components/ui/CoverageRating.tsx +++ b/server/sonar-web/src/main/js/components/ui/CoverageRating.tsx @@ -18,9 +18,11 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import DonutChart from '../charts/DonutChart'; +import { lazyLoad } from '../lazyLoad'; import * as theme from '../../app/theme'; +const DonutChart = lazyLoad(() => import('../charts/DonutChart')); + const SIZE_TO_WIDTH_MAPPING = { small: 16, normal: 24, big: 40, huge: 60 }; const SIZE_TO_THICKNESS_MAPPING = { small: 2, normal: 3, big: 3, huge: 4 }; diff --git a/server/sonar-web/src/main/js/helpers/dates.ts b/server/sonar-web/src/main/js/helpers/dates.ts index f6f9167435d..b86e3685446 100644 --- a/server/sonar-web/src/main/js/helpers/dates.ts +++ b/server/sonar-web/src/main/js/helpers/dates.ts @@ -17,14 +17,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { - differenceInDays as _differenceInDays, - differenceInSeconds as _differenceInSeconds, - differenceInYears as _differenceInYears, - isSameDay as _isSameDay, - parse, - startOfDay as _startOfDay -} from 'date-fns'; +import * as _differenceInDays from 'date-fns/difference_in_days'; +import * as _differenceInSeconds from 'date-fns/difference_in_seconds'; +import * as _differenceInYears from 'date-fns/difference_in_years'; +import * as _isSameDay from 'date-fns/is_same_day'; +import * as _startOfDay from 'date-fns/start_of_day'; +import * as parse from 'date-fns/parse'; function pad(number: number) { if (number < 10) { diff --git a/server/sonar-web/yarn.lock b/server/sonar-web/yarn.lock index 3fa52d493cc..45c78e2cf5c 100644 --- a/server/sonar-web/yarn.lock +++ b/server/sonar-web/yarn.lock @@ -760,6 +760,13 @@ babel-helper-hoist-variables@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" +babel-helper-module-imports@^7.0.0-beta.3: + version "7.0.0-beta.3" + resolved "https://registry.yarnpkg.com/babel-helper-module-imports/-/babel-helper-module-imports-7.0.0-beta.3.tgz#e15764e3af9c8e11810c09f78f498a2bdc71585a" + dependencies: + babel-types "7.0.0-beta.3" + lodash "^4.2.0" + babel-helper-optimise-call-expression@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" @@ -849,6 +856,16 @@ babel-plugin-jest-hoist@^22.4.3: version "22.4.3" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.3.tgz#7d8bcccadc2667f96a0dcc6afe1891875ee6c14a" +babel-plugin-lodash@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.3.2.tgz#da3a5b49ba27447f54463f6c4fa81396ccdd463f" + dependencies: + babel-helper-module-imports "^7.0.0-beta.3" + babel-types "^6.26.0" + glob "^7.1.1" + lodash "^4.17.4" + require-package-name "^2.0.1" + babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" @@ -1252,6 +1269,14 @@ babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: invariant "^2.2.2" lodash "^4.17.4" +babel-types@7.0.0-beta.3: + version "7.0.0-beta.3" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-7.0.0-beta.3.tgz#cd927ca70e0ae8ab05f4aab83778cfb3e6eb20b4" + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" + babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" @@ -5093,6 +5118,12 @@ lodash-es@^4.17.5, lodash-es@^4.2.1: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.10.tgz#62cd7104cdf5dd87f235a837f0ede0e8e5117e05" +lodash-webpack-plugin@0.11.5: + version "0.11.5" + resolved "https://registry.yarnpkg.com/lodash-webpack-plugin/-/lodash-webpack-plugin-0.11.5.tgz#c4bd064b4f561c3f823fa5982bdeb12c475390b9" + dependencies: + lodash "^4.17.4" + lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" @@ -5129,7 +5160,7 @@ lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -lodash@4.17.10, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0: +lodash@4.17.10, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -7169,6 +7200,10 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" +require-package-name@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9" + require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -7965,6 +8000,10 @@ to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectKeyUpdatePageTest.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectKeyUpdatePageTest.java index a6789d3c74d..50d4849035c 100644 --- a/tests/src/test/java/org/sonarqube/tests/project/ProjectKeyUpdatePageTest.java +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectKeyUpdatePageTest.java @@ -102,7 +102,7 @@ public class ProjectKeyUpdatePageTest { $(".modal").shouldNotBe(visible); - tester.openBrowser().openProjectKey("another"); + openPage("another"); assertThat(url()).endsWith("/project/key?id=another"); } |