Build: Upgrade Webpack 5 (#36444)

* build(webpack): bump to v5 and successful yarn start compilation

* build(webpack): update postcss dependencies

* build(webpack): silence warnings about hash renamed to fullhash

* build(webpack): enable persistent cache to store generated webpack modules / chunks

* build(webpack): prefer eslintWebpackPlugin over tschecker so eslint doesn't block typechecking

* chore(yarn): run yarn-deduplicate to clean up dependencies

* chore(yarn): refresh lock file after clean install

* build(webpack): prefer output.clean over CleanWebpackPlugin

* build(webpack): prefer esbuild over babel-loader for dev config

* build(babel): turn off cache compression to improve build performance

* build(webpack): get production builds working

* build(webpack): remove phantomJS (removed from grafana in v7) specific loader

* build(webpack): put back babel for dev builds no performance gain in using esbuild in webpack

* build(webpack): prefer terser and optimise css plugins for prod. slower but smaller bundles

* build(webpack): clean up redundant code. inform postcss about node_modules

* build(webpack): remove deprecation warnings flag

* build(webpack): bump packages, dev performance optimisations, attempt to get hot working

* chore(storybook): use webpack 5 for dev and production builds

* build(storybook): speed up dev build

* chore(yarn): refresh lock file

* chore(webpack): bump webpack and related deps to latest

* refactor(webpack): put back inline-source-map, move start scripts out of grafana toolkit

* feat(webpack): prefer react-refresh over react-hot-loader

* build(webpack): update webpack.hot to use react-refresh

* chore: remove react-hot-loader from codebase

* refactor(queryeditorrow): fix circular dependency causing react-fast-refresh errors

* revert(webpack): remove stats.errorDetails from common config

* build(webpack): bump to v5 and successful yarn start compilation

* build(webpack): update postcss dependencies

* build(webpack): silence warnings about hash renamed to fullhash

* build(webpack): enable persistent cache to store generated webpack modules / chunks

* build(webpack): prefer eslintWebpackPlugin over tschecker so eslint doesn't block typechecking

* chore(yarn): run yarn-deduplicate to clean up dependencies

* chore(yarn): refresh lock file after clean install

* build(webpack): prefer output.clean over CleanWebpackPlugin

* build(webpack): prefer esbuild over babel-loader for dev config

* build(babel): turn off cache compression to improve build performance

* build(webpack): get production builds working

* build(webpack): remove phantomJS (removed from grafana in v7) specific loader

* build(webpack): put back babel for dev builds no performance gain in using esbuild in webpack

* build(webpack): prefer terser and optimise css plugins for prod. slower but smaller bundles

* build(webpack): clean up redundant code. inform postcss about node_modules

* build(webpack): remove deprecation warnings flag

* build(webpack): bump packages, dev performance optimisations, attempt to get hot working

* chore(storybook): use webpack 5 for dev and production builds

* build(storybook): speed up dev build

* chore(yarn): refresh lock file

* chore(webpack): bump webpack and related deps to latest

* refactor(webpack): put back inline-source-map, move start scripts out of grafana toolkit

* feat(webpack): prefer react-refresh over react-hot-loader

* build(webpack): update webpack.hot to use react-refresh

* chore: remove react-hot-loader from codebase

* refactor(queryeditorrow): fix circular dependency causing react-fast-refresh errors

* revert(webpack): remove stats.errorDetails from common config

* revert(webpack): remove include from babel-loader so symlinks (enterprise) work as before

* refactor(webpack): fix deprecation warnings in prod builds

* fix(storybook): fix failing builds due to replacing css-optimise webpack plugin

* fix(storybook): use raw-loader for svg icons

* build(webpack): fix dev script colors error

* chore(webpack): bump css-loader and react-refresh-webpack-plugin to latest versions

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
pull/38762/head
Jack Westbrook 4 years ago committed by GitHub
parent b40d48258d
commit 8d3b31ff23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 21
      contribute/style-guides/frontend.md
  2. 64
      package.json
  3. 4
      packages/grafana-toolkit/src/cli/tasks/core.start.ts
  4. 110
      packages/grafana-ui/.storybook/main.ts
  5. 6
      packages/grafana-ui/package.json
  6. 4
      public/app/features/admin/AdminSettings.tsx
  7. 3
      public/app/features/admin/UpgradePage.tsx
  8. 3
      public/app/features/admin/UserAdminPage.tsx
  9. 3
      public/app/features/admin/UserCreatePage.tsx
  10. 3
      public/app/features/admin/UserListAdminPage.tsx
  11. 3
      public/app/features/admin/ldap/LdapPage.tsx
  12. 3
      public/app/features/alerting/AlertRuleList.tsx
  13. 3
      public/app/features/api-keys/ApiKeysPage.tsx
  14. 3
      public/app/features/dashboard/containers/DashboardPage.tsx
  15. 3
      public/app/features/dashboard/containers/SoloPanelPage.tsx
  16. 3
      public/app/features/datasources/DataSourcesListPage.tsx
  17. 3
      public/app/features/datasources/NewDataSourcePage.tsx
  18. 3
      public/app/features/explore/Explore.tsx
  19. 3
      public/app/features/explore/ExploreQueryInspector.tsx
  20. 3
      public/app/features/explore/ExploreToolbar.tsx
  21. 3
      public/app/features/explore/LogsContainer.tsx
  22. 3
      public/app/features/explore/QueryRow.tsx
  23. 3
      public/app/features/explore/RichHistory/RichHistoryCard.tsx
  24. 3
      public/app/features/explore/RichHistory/RichHistoryContainer.tsx
  25. 3
      public/app/features/explore/TableContainer.tsx
  26. 3
      public/app/features/org/NewOrgPage.tsx
  27. 3
      public/app/features/org/OrgDetailsPage.tsx
  28. 3
      public/app/features/org/UserInvitePage.tsx
  29. 3
      public/app/features/plugins/PluginListPage.tsx
  30. 5
      public/app/features/plugins/PluginsErrorsInfo.tsx
  31. 3
      public/app/features/profile/ChangePasswordPage.tsx
  32. 3
      public/app/features/profile/UserProfileEditPage.tsx
  33. 4
      public/app/features/query/components/QueryEditorRow.tsx
  34. 3
      public/app/features/teams/CreateTeam.tsx
  35. 3
      public/app/features/teams/TeamList.tsx
  36. 3
      public/app/features/users/UsersListPage.tsx
  37. 23
      public/views/error-template.html
  38. 17
      public/views/index-template.html
  39. 9
      scripts/webpack/babel.config.js
  40. 2
      scripts/webpack/loaders/compile.js
  41. 14
      scripts/webpack/postcss.config.js
  42. 6
      scripts/webpack/sass.rule.js
  43. 72
      scripts/webpack/webpack.common.js
  44. 56
      scripts/webpack/webpack.dev.js
  45. 111
      scripts/webpack/webpack.hot.js
  46. 10
      scripts/webpack/webpack.prod.js
  47. 2466
      yarn.lock

@ -5,6 +5,7 @@ Generally we follow the Airbnb [React Style Guide](https://github.com/airbnb/jav
## Table of Contents ## Table of Contents
- [Frontend Style Guide](#frontend-style-guide) - [Frontend Style Guide](#frontend-style-guide)
- [Table of Contents](#table-of-contents) - [Table of Contents](#table-of-contents)
- [Basic rules](#basic-rules) - [Basic rules](#basic-rules)
- [Naming conventions](#naming-conventions) - [Naming conventions](#naming-conventions)
@ -28,10 +29,10 @@ Generally we follow the Airbnb [React Style Guide](https://github.com/airbnb/jav
- [Linting](#linting) - [Linting](#linting)
- [React](#react) - [React](#react)
- [Props](#props) - [Props](#props)
- [Name callback props and handlers with an "on" prefix.](#name-callback-props-and-handlers-with-an-on-prefix) - [Name callback props and handlers with an "on" prefix.](#name-callback-props-and-handlers-with-an-on-prefix)
- [React Component definitions](#react-component-definitions) - [React Component definitions](#react-component-definitions)
- [React Component constructor](#react-component-constructor) - [React Component constructor](#react-component-constructor)
- [React Component defaultProps](#react-component-defaultprops) - [React Component defaultProps](#react-component-defaultprops)
- [State management](#state-management) - [State management](#state-management)
- [Proposal for removing or replacing Angular dependencies](https://github.com/grafana/grafana/pull/23048) - [Proposal for removing or replacing Angular dependencies](https://github.com/grafana/grafana/pull/23048)
@ -216,18 +217,18 @@ Specify function return types explicitly in new code. This improves readability
// bad // bad
function transform(value?: string) { function transform(value?: string) {
if (!value) { if (!value) {
return undefined return undefined;
} }
return applyTransform(value) return applyTransform(value);
}; }
// good // good
function transform(value?: string): TransformedValue | undefined { function transform(value?: string): TransformedValue | undefined {
if (!value) { if (!value) {
return undefined return undefined;
} }
return applyTransform(value) return applyTransform(value);
}; }
``` ```
### File and directory naming conventions ### File and directory naming conventions

@ -8,7 +8,7 @@
"scripts": { "scripts": {
"api-tests": "jest --notify --watch --config=devenv/e2e-api-tests/jest.js", "api-tests": "jest --notify --watch --config=devenv/e2e-api-tests/jest.js",
"build": "node ./node_modules/webpack/bin/webpack.js --config scripts/webpack/webpack.prod.js", "build": "node ./node_modules/webpack/bin/webpack.js --config scripts/webpack/webpack.prod.js",
"dev": "webpack --progress --colors --config scripts/webpack/webpack.dev.js", "dev": "webpack --progress --color --config scripts/webpack/webpack.dev.js",
"e2e": "./e2e/start-and-run-suite", "e2e": "./e2e/start-and-run-suite",
"e2e:debug": "./e2e/start-and-run-suite debug", "e2e:debug": "./e2e/start-and-run-suite debug",
"e2e:dev": "./e2e/start-and-run-suite dev", "e2e:dev": "./e2e/start-and-run-suite dev",
@ -33,10 +33,12 @@
"precommit": "yarn run lint-staged", "precommit": "yarn run lint-staged",
"prettier:check": "prettier --list-different \"**/*.{ts,tsx,scss}\"", "prettier:check": "prettier --list-different \"**/*.{ts,tsx,scss}\"",
"prettier:write": "prettier --list-different \"**/*.{ts,tsx,scss,js}\" --write", "prettier:write": "prettier --list-different \"**/*.{ts,tsx,scss,js}\" --write",
"start": "grafana-toolkit core:start --watchTheme", "prestart": "yarn themes:generate",
"start:hot": "grafana-toolkit core:start --hot --watchTheme", "prestart:hot": "yarn themes:generate",
"start:ignoreTheme": "grafana-toolkit core:start --hot", "prestart:noTsCheck": "yarn themes:generate",
"start:noTsCheck": "grafana-toolkit core:start --noTsCheck", "start": "webpack --progress --color --watch --env noTsCheck=0 --config scripts/webpack/webpack.dev.js",
"start:hot": "webpack serve --progress --color --config scripts/webpack/webpack.hot.js",
"start:noTsCheck": "webpack --progress --color --watch --env noTsCheck=1 --config scripts/webpack/webpack.dev.js",
"stats": "webpack --mode production --config scripts/webpack/webpack.prod.js --profile --json > compilation-stats.json", "stats": "webpack --mode production --config scripts/webpack/webpack.prod.js --profile --json > compilation-stats.json",
"storybook": "yarn workspace @grafana/ui storybook --ci", "storybook": "yarn workspace @grafana/ui storybook --ci",
"storybook:build": "yarn workspace @grafana/ui storybook:build", "storybook:build": "yarn workspace @grafana/ui storybook:build",
@ -82,6 +84,7 @@
"@grafana/api-extractor": "7.10.1", "@grafana/api-extractor": "7.10.1",
"@grafana/eslint-config": "2.5.0", "@grafana/eslint-config": "2.5.0",
"@kusto/monaco-kusto": "3.2.7", "@kusto/monaco-kusto": "3.2.7",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.0-rc.6",
"@rtsao/plugin-proposal-class-properties": "7.0.1-patch.1", "@rtsao/plugin-proposal-class-properties": "7.0.1-patch.1",
"@testing-library/jest-dom": "5.11.5", "@testing-library/jest-dom": "5.11.5",
"@testing-library/react": "11.1.2", "@testing-library/react": "11.1.2",
@ -139,14 +142,14 @@
"@typescript-eslint/parser": "4.28.0", "@typescript-eslint/parser": "4.28.0",
"@wojtekmaj/enzyme-adapter-react-17": "0.6.2", "@wojtekmaj/enzyme-adapter-react-17": "0.6.2",
"angular-mocks": "1.6.6", "angular-mocks": "1.6.6",
"autoprefixer": "9.7.4", "autoprefixer": "10.2.6",
"axios": "0.21.1", "axios": "0.21.1",
"babel-jest": "26.6.3", "babel-jest": "26.6.3",
"babel-loader": "8.2.2", "babel-loader": "8.2.2",
"babel-plugin-angularjs-annotate": "0.10.0", "babel-plugin-angularjs-annotate": "0.10.0",
"clean-webpack-plugin": "3.0.0", "copy-webpack-plugin": "9.0.1",
"copy-webpack-plugin": "6.4.1", "css-loader": "6.2.0",
"css-loader": "3.4.2", "css-minimizer-webpack-plugin": "^3.0.2",
"enzyme": "3.11.0", "enzyme": "3.11.0",
"enzyme-to-json": "3.4.4", "enzyme-to-json": "3.4.4",
"es-abstract": "1.18.0-next.1", "es-abstract": "1.18.0-next.1",
@ -160,16 +163,17 @@
"eslint-plugin-prettier": "3.3.1", "eslint-plugin-prettier": "3.3.1",
"eslint-plugin-react": "7.22.0", "eslint-plugin-react": "7.22.0",
"eslint-plugin-react-hooks": "4.2.0", "eslint-plugin-react-hooks": "4.2.0",
"eslint-webpack-plugin": "3.0.1",
"expect.js": "0.3.1", "expect.js": "0.3.1",
"expose-loader": "0.7.5", "expose-loader": "3.0.0",
"file-loader": "5.0.2", "file-loader": "6.2.0",
"fork-ts-checker-webpack-plugin": "6.3.1", "fork-ts-checker-webpack-plugin": "6.3.2",
"fs-extra": "9.1.0", "fs-extra": "9.1.0",
"gaze": "1.1.3", "gaze": "1.1.3",
"glob": "7.1.6", "glob": "7.1.6",
"html-loader": "0.5.5", "html-loader": "2.1.2",
"html-webpack-harddisk-plugin": "1.0.1", "html-webpack-harddisk-plugin": "2.0.0",
"html-webpack-plugin": "3.2.0", "html-webpack-plugin": "5.3.2",
"husky": "4.2.1", "husky": "4.2.1",
"iconscout-unicons-tarball": "https://github.com/grafana/icons/tarball/9728be621a4e7d891611149c9cd179e793f790a7", "iconscout-unicons-tarball": "https://github.com/grafana/icons/tarball/9728be621a4e7d891611149c9cd179e793f790a7",
"jest": "26.6.3", "jest": "26.6.3",
@ -178,44 +182,44 @@
"jest-matcher-utils": "26.0.0", "jest-matcher-utils": "26.0.0",
"lerna": "^3.22.1", "lerna": "^3.22.1",
"lint-staged": "10.0.7", "lint-staged": "10.0.7",
"mini-css-extract-plugin": "0.9.0", "mini-css-extract-plugin": "2.2.0",
"mocha": "7.0.1", "mocha": "7.0.1",
"module-alias": "2.2.2", "module-alias": "2.2.2",
"mutationobserver-shim": "0.3.3", "mutationobserver-shim": "0.3.3",
"ngtemplate-loader": "2.0.1", "ngtemplate-loader": "2.1.0",
"nodemon": "2.0.2", "nodemon": "2.0.2",
"optimize-css-assets-webpack-plugin": "5.0.5",
"pa11y-ci": "2.4.2", "pa11y-ci": "2.4.2",
"postcss": "8.3.6",
"postcss-browser-reporter": "0.6.0", "postcss-browser-reporter": "0.6.0",
"postcss-loader": "3.0.0", "postcss-loader": "6.1.1",
"postcss-reporter": "6.0.1", "postcss-reporter": "7.0.2",
"prettier": "2.2.1", "prettier": "2.2.1",
"raw-loader": "4.0.2", "raw-loader": "4.0.2",
"react-hot-loader": "4.8.0", "react-refresh": "^0.10.0",
"react-select-event": "^5.1.0", "react-select-event": "^5.1.0",
"react-test-renderer": "17.0.1", "react-test-renderer": "17.0.1",
"redux-mock-store": "1.5.4", "redux-mock-store": "1.5.4",
"regexp-replace-loader": "1.0.1", "regexp-replace-loader": "1.0.1",
"rimraf": "3.0.1", "rimraf": "3.0.1",
"rxjs-spy": "8.0.0", "rxjs-spy": "8.0.0",
"sass": "1.27.0", "sass": "1.32.13",
"sass-lint": "1.12.1", "sass-lint": "1.12.1",
"sass-loader": "8.0.2", "sass-loader": "12.1.0",
"sinon": "8.1.1", "sinon": "8.1.1",
"style-loader": "1.1.3", "style-loader": "3.2.1",
"terser-webpack-plugin": "2.3.7", "terser-webpack-plugin": "5.1.4",
"testing-library-selector": "^0.1.3", "testing-library-selector": "^0.1.3",
"ts-jest": "26.4.4", "ts-jest": "26.4.4",
"ts-node": "9.0.0", "ts-node": "9.0.0",
"tslib": "2.2.0", "tslib": "2.2.0",
"typescript": "4.3.4", "typescript": "4.3.4",
"wait-on": "6.0.0", "wait-on": "6.0.0",
"webpack": "4.41.5", "webpack": "5.51.1",
"webpack-bundle-analyzer": "3.6.0", "webpack-bundle-analyzer": "4.4.2",
"webpack-cleanup-plugin": "0.5.1", "webpack-cleanup-plugin": "0.5.1",
"webpack-cli": "3.3.10", "webpack-cli": "4.8.0",
"webpack-dev-server": "3.11.1", "webpack-dev-server": "4.0.0",
"webpack-merge": "4.2.2", "webpack-merge": "5.8.0",
"worker-loader": "^3.0.8", "worker-loader": "^3.0.8",
"zone.js": "0.7.8" "zone.js": "0.7.8"
}, },

@ -17,11 +17,11 @@ const startTaskRunner: TaskRunner<StartTaskOptions> = async ({ watchThemes, noTs
}, },
hot hot
? { ? {
command: 'webpack-dev-server --progress --colors --config scripts/webpack/webpack.hot.js', command: 'webpack serve --progress --color --config scripts/webpack/webpack.hot.js',
name: 'Dev server', name: 'Dev server',
} }
: { : {
command: `webpack --progress --colors --watch --env.noTsCheck=${noTsCheckArg} --config scripts/webpack/webpack.dev.js`, command: `webpack --progress --color --watch --env noTsCheck=${noTsCheckArg} --config scripts/webpack/webpack.dev.js`,
name: 'Webpack', name: 'Webpack',
}, },
]; ];

@ -1,7 +1,8 @@
const path = require('path'); const path = require('path');
const TerserPlugin = require('terser-webpack-plugin'); const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const FilterWarningsPlugin = require('webpack-filter-warnings-plugin'); const FilterWarningsPlugin = require('webpack-filter-warnings-plugin');
const getBabelConfig = require('../../../scripts/webpack/babel.config');
const stories = ['../src/**/*.story.{js,jsx,ts,tsx,mdx}']; const stories = ['../src/**/*.story.{js,jsx,ts,tsx,mdx}'];
@ -23,8 +24,12 @@ module.exports = {
'@storybook/addon-storysource', '@storybook/addon-storysource',
'storybook-dark-mode', 'storybook-dark-mode',
], ],
reactOptions: { // currently broken in webpack 5 builder support
fastRefresh: true, // reactOptions: {
// fastRefresh: true,
// },
core: {
builder: 'webpack5',
}, },
typescript: { typescript: {
check: true, check: true,
@ -39,6 +44,22 @@ module.exports = {
}, },
webpackFinal: async (config: any, { configType }: any) => { webpackFinal: async (config: any, { configType }: any) => {
const isProductionBuild = configType === 'PRODUCTION'; const isProductionBuild = configType === 'PRODUCTION';
// remove svg from default storybook webpack 5 config so we can use `raw-loader`
config.module.rules = config.module.rules.map((rule: any) => {
if (
String(rule.test) ===
String(/\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/)
) {
return {
...rule,
test: /\.(ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/,
};
}
return rule;
});
config.module.rules = [ config.module.rules = [
...(config.module.rules || []), ...(config.module.rules || []),
{ {
@ -52,6 +73,8 @@ module.exports = {
}, },
}, },
], ],
exclude: /node_modules/,
include: [path.resolve(__dirname, '../../../public/'), path.resolve(__dirname, '../../../packages/')],
}, },
{ {
test: /\.scss$/, test: /\.scss$/,
@ -63,6 +86,7 @@ module.exports = {
{ {
loader: 'css-loader', loader: 'css-loader',
options: { options: {
url: false,
importLoaders: 2, importLoaders: 2,
}, },
}, },
@ -70,7 +94,9 @@ module.exports = {
loader: 'postcss-loader', loader: 'postcss-loader',
options: { options: {
sourceMap: false, sourceMap: false,
config: { path: __dirname + '../../../../scripts/webpack/postcss.config.js' }, postcssOptions: {
config: path.resolve(__dirname + '../../../../scripts/webpack/postcss.config.js'),
},
}, },
}, },
{ {
@ -81,52 +107,50 @@ module.exports = {
}, },
], ],
}, },
// for pre-caching SVGs as part of the JS bundles
{
test: /\.svg$/,
use: 'raw-loader',
},
{ {
test: require.resolve('jquery'), test: require.resolve('jquery'),
use: [ loader: 'expose-loader',
{ options: {
loader: 'expose-loader', exposes: ['$', 'jQuery'],
query: 'jQuery', },
},
{
loader: 'expose-loader',
query: '$',
},
],
}, },
]; ];
config.optimization = { if (isProductionBuild) {
nodeEnv: 'production', config.optimization = {
moduleIds: 'hashed', nodeEnv: 'production',
runtimeChunk: 'single', moduleIds: 'deterministic',
splitChunks: { runtimeChunk: 'single',
chunks: 'all', splitChunks: {
minChunks: 1, chunks: 'all',
cacheGroups: { minChunks: 1,
vendors: { cacheGroups: {
test: /[\\/]node_modules[\\/].*[jt]sx?$/, vendors: {
chunks: 'initial', test: /[\\/]node_modules[\\/].*[jt]sx?$/,
priority: -10, chunks: 'initial',
reuseExistingChunk: true, priority: -10,
enforce: true, reuseExistingChunk: true,
}, enforce: true,
default: { },
priority: -20, default: {
chunks: 'all', priority: -20,
test: /.*[jt]sx?$/, chunks: 'all',
reuseExistingChunk: true, test: /.*[jt]sx?$/,
reuseExistingChunk: true,
},
}, },
}, },
}, minimize: isProductionBuild,
minimize: isProductionBuild, minimizer: isProductionBuild
minimizer: isProductionBuild ? [new TerserPlugin({ parallel: false, exclude: /monaco/ }), new CssMinimizerPlugin()]
? [ : [],
new TerserPlugin({ cache: false, parallel: false, sourceMap: false, exclude: /monaco/ }), };
new OptimizeCSSAssetsPlugin({}), }
]
: [],
};
config.resolve.alias['@grafana/ui'] = path.resolve(__dirname, '..'); config.resolve.alias['@grafana/ui'] = path.resolve(__dirname, '..');

@ -25,6 +25,10 @@
"storybook:build": "build-storybook -o ./dist/storybook -c .storybook -s ../../public/img:public/img,../../public/lib:public/lib", "storybook:build": "build-storybook -o ./dist/storybook -c .storybook -s ../../public/img:public/img,../../public/lib:public/lib",
"typecheck": "tsc --noEmit" "typecheck": "tsc --noEmit"
}, },
"browserslist": [
"defaults",
"not IE 11"
],
"dependencies": { "dependencies": {
"@emotion/css": "11.1.3", "@emotion/css": "11.1.3",
"@emotion/react": "11.1.5", "@emotion/react": "11.1.5",
@ -81,6 +85,8 @@
"@storybook/addon-storysource": "6.3.7", "@storybook/addon-storysource": "6.3.7",
"@storybook/react": "6.3.7", "@storybook/react": "6.3.7",
"@storybook/theming": "6.3.7", "@storybook/theming": "6.3.7",
"@storybook/builder-webpack5": "6.3.7",
"@storybook/manager-webpack5": "6.3.7",
"@testing-library/jest-dom": "5.11.9", "@testing-library/jest-dom": "5.11.9",
"@types/classnames": "2.2.7", "@types/classnames": "2.2.7",
"@types/common-tags": "^1.8.0", "@types/common-tags": "^1.8.0",

@ -1,7 +1,5 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { hot } from 'react-hot-loader';
import { getBackendSrv } from '@grafana/runtime'; import { getBackendSrv } from '@grafana/runtime';
import { NavModel } from '@grafana/data'; import { NavModel } from '@grafana/data';
@ -74,4 +72,4 @@ const mapStateToProps = (state: StoreState) => ({
navModel: getNavModel(state.navIndex, 'server-settings'), navModel: getNavModel(state.navIndex, 'server-settings'),
}); });
export default hot(module)(connect(mapStateToProps)(AdminSettings)); export default connect(mapStateToProps)(AdminSettings);

@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { hot } from 'react-hot-loader';
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import { LinkButton, useStyles2 } from '@grafana/ui'; import { LinkButton, useStyles2 } from '@grafana/ui';
import { GrafanaTheme2, NavModel } from '@grafana/data'; import { GrafanaTheme2, NavModel } from '@grafana/data';
@ -231,4 +230,4 @@ const mapStateToProps = (state: StoreState) => ({
navModel: getNavModel(state.navIndex, 'upgrading'), navModel: getNavModel(state.navIndex, 'upgrading'),
}); });
export default hot(module)(connect(mapStateToProps)(UpgradePage)); export default connect(mapStateToProps)(UpgradePage);

@ -1,5 +1,4 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { NavModel } from '@grafana/data'; import { NavModel } from '@grafana/data';
import { getNavModel } from 'app/core/selectors/navModel'; import { getNavModel } from 'app/core/selectors/navModel';
@ -177,4 +176,4 @@ const mapDispatchToProps = {
const connector = connect(mapStateToProps, mapDispatchToProps); const connector = connect(mapStateToProps, mapDispatchToProps);
type Props = OwnProps & ConnectedProps<typeof connector>; type Props = OwnProps & ConnectedProps<typeof connector>;
export default hot(module)(connector(UserAdminPage)); export default connector(UserAdminPage);

@ -1,5 +1,4 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Form, Button, Input, Field } from '@grafana/ui'; import { Form, Button, Input, Field } from '@grafana/ui';
import { NavModel } from '@grafana/data'; import { NavModel } from '@grafana/data';
@ -83,4 +82,4 @@ const mapStateToProps = (state: StoreState) => ({
navModel: getNavModel(state.navIndex, 'global-users'), navModel: getNavModel(state.navIndex, 'global-users'),
}); });
export default hot(module)(connect(mapStateToProps)(UserCreatePage)); export default connect(mapStateToProps)(UserCreatePage);

@ -1,6 +1,5 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { Pagination, Tooltip, stylesFactory, LinkButton, Icon } from '@grafana/ui'; import { Pagination, Tooltip, stylesFactory, LinkButton, Icon } from '@grafana/ui';
import { AccessControlAction, StoreState, UserDTO } from '../../types'; import { AccessControlAction, StoreState, UserDTO } from '../../types';
@ -142,4 +141,4 @@ const getStyles = stylesFactory(() => {
}; };
}); });
export default hot(module)(connector(UserListAdminPageUnConnected)); export default connector(UserListAdminPageUnConnected);

@ -1,5 +1,4 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { NavModel } from '@grafana/data'; import { NavModel } from '@grafana/data';
import { Alert, Button, LegacyForms } from '@grafana/ui'; import { Alert, Button, LegacyForms } from '@grafana/ui';
@ -160,4 +159,4 @@ const mapDispatchToProps = {
const connector = connect(mapStateToProps, mapDispatchToProps); const connector = connect(mapStateToProps, mapDispatchToProps);
type Props = OwnProps & ConnectedProps<typeof connector>; type Props = OwnProps & ConnectedProps<typeof connector>;
export default hot(module)(connector(LdapPage)); export default connector(LdapPage);

@ -1,5 +1,4 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import Page from 'app/core/components/Page/Page'; import Page from 'app/core/components/Page/Page';
import AlertRuleItem from './AlertRuleItem'; import AlertRuleItem from './AlertRuleItem';
@ -141,4 +140,4 @@ export class AlertRuleListUnconnected extends PureComponent<Props> {
} }
} }
export default hot(module)(connector(AlertRuleListUnconnected)); export default connector(AlertRuleListUnconnected);

@ -1,6 +1,5 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { hot } from 'react-hot-loader';
// Utils // Utils
import { ApiKey, NewApiKey, StoreState } from 'app/types'; import { ApiKey, NewApiKey, StoreState } from 'app/types';
import { getNavModel } from 'app/core/selectors/navModel'; import { getNavModel } from 'app/core/selectors/navModel';
@ -168,4 +167,4 @@ export class ApiKeysPageUnconnected extends PureComponent<Props, State> {
} }
const ApiKeysPage = connector(ApiKeysPageUnconnected); const ApiKeysPage = connector(ApiKeysPageUnconnected);
export default hot(module)(ApiKeysPage); export default ApiKeysPage;

@ -1,6 +1,5 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { css } from 'emotion'; import { css } from 'emotion';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { locationService } from '@grafana/runtime'; import { locationService } from '@grafana/runtime';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
@ -417,4 +416,4 @@ export const getStyles = stylesFactory((theme: GrafanaTheme2, kioskMode) => {
export const DashboardPage = withTheme2(UnthemedDashboardPage); export const DashboardPage = withTheme2(UnthemedDashboardPage);
DashboardPage.displayName = 'DashboardPage'; DashboardPage.displayName = 'DashboardPage';
export default hot(module)(connector(DashboardPage)); export default connector(DashboardPage);

@ -1,5 +1,4 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import AutoSizer from 'react-virtualized-auto-sizer'; import AutoSizer from 'react-virtualized-auto-sizer';
import { DashboardPanel } from '../dashgrid/DashboardPanel'; import { DashboardPanel } from '../dashgrid/DashboardPanel';
@ -111,4 +110,4 @@ export class SoloPanelPage extends Component<Props, State> {
} }
} }
export default hot(module)(connector(SoloPanelPage)); export default connector(SoloPanelPage);

@ -1,7 +1,6 @@
// Libraries // Libraries
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { hot } from 'react-hot-loader';
// Components // Components
import Page from 'app/core/components/Page/Page'; import Page from 'app/core/components/Page/Page';
import PageActionBar from 'app/core/components/PageActionBar/PageActionBar'; import PageActionBar from 'app/core/components/PageActionBar/PageActionBar';
@ -97,4 +96,4 @@ export class DataSourcesListPage extends PureComponent<Props> {
} }
} }
export default hot(module)(connector(DataSourcesListPage)); export default connector(DataSourcesListPage);

@ -1,6 +1,5 @@
import React, { FC, PureComponent } from 'react'; import React, { FC, PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { hot } from 'react-hot-loader';
import { DataSourcePluginMeta, NavModel } from '@grafana/data'; import { DataSourcePluginMeta, NavModel } from '@grafana/data';
import { Button, LinkButton, List, PluginSignatureBadge } from '@grafana/ui'; import { Button, LinkButton, List, PluginSignatureBadge } from '@grafana/ui';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
@ -179,4 +178,4 @@ export function getNavModel(): NavModel {
}; };
} }
export default hot(module)(connector(NewDataSourcePage)); export default connector(NewDataSourcePage);

@ -1,5 +1,4 @@
import React from 'react'; import React from 'react';
import { hot } from 'react-hot-loader';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { compose } from 'redux'; import { compose } from 'redux';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
@ -408,4 +407,4 @@ const mapDispatchToProps = {
const connector = connect(mapStateToProps, mapDispatchToProps); const connector = connect(mapStateToProps, mapDispatchToProps);
export default compose(hot(module), connector, withTheme2)(Explore) as React.ComponentType<{ exploreId: ExploreId }>; export default compose(connector, withTheme2)(Explore) as React.ComponentType<{ exploreId: ExploreId }>;

@ -3,7 +3,6 @@ import { TabbedContainer, TabConfig } from '@grafana/ui';
import { TimeZone } from '@grafana/data'; import { TimeZone } from '@grafana/data';
import { runQueries } from './state/query'; import { runQueries } from './state/query';
import { StoreState, ExploreItemState, ExploreId } from 'app/types'; import { StoreState, ExploreItemState, ExploreId } from 'app/types';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { ExploreDrawer } from 'app/features/explore/ExploreDrawer'; import { ExploreDrawer } from 'app/features/explore/ExploreDrawer';
import { InspectJSONTab } from 'app/features/inspector/InspectJSONTab'; import { InspectJSONTab } from 'app/features/inspector/InspectJSONTab';
@ -93,4 +92,4 @@ const mapDispatchToProps = {
const connector = connect(mapStateToProps, mapDispatchToProps); const connector = connect(mapStateToProps, mapDispatchToProps);
export default hot(module)(connector(ExploreQueryInspector)); export default connector(ExploreQueryInspector);

@ -1,6 +1,5 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { hot } from 'react-hot-loader';
import classNames from 'classnames'; import classNames from 'classnames';
import { css } from '@emotion/css'; import { css } from '@emotion/css';
@ -251,4 +250,4 @@ const mapDispatchToProps = {
const connector = connect(mapStateToProps, mapDispatchToProps); const connector = connect(mapStateToProps, mapDispatchToProps);
export const ExploreToolbar = hot(module)(connector(UnConnectedExploreToolbar)); export const ExploreToolbar = connector(UnConnectedExploreToolbar);

@ -1,5 +1,4 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { css } from 'emotion'; import { css } from 'emotion';
import { Collapse } from '@grafana/ui'; import { Collapse } from '@grafana/ui';
@ -192,4 +191,4 @@ const mapDispatchToProps = {
const connector = connect(mapStateToProps, mapDispatchToProps); const connector = connect(mapStateToProps, mapDispatchToProps);
type PropsFromRedux = ConnectedProps<typeof connector>; type PropsFromRedux = ConnectedProps<typeof connector>;
export default hot(module)(connector(LogsContainer)); export default connector(LogsContainer);

@ -1,7 +1,6 @@
// Libraries // Libraries
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { debounce, has } from 'lodash'; import { debounce, has } from 'lodash';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import AngularQueryEditor from './QueryEditor'; import AngularQueryEditor from './QueryEditor';
import { QueryRowActions } from './QueryRowActions'; import { QueryRowActions } from './QueryRowActions';
@ -201,4 +200,4 @@ const mapDispatchToProps = {
const connector = connect(mapStateToProps, mapDispatchToProps); const connector = connect(mapStateToProps, mapDispatchToProps);
export default hot(module)(connector(QueryRow)); export default connector(QueryRow);

@ -1,6 +1,5 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { hot } from 'react-hot-loader';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { stylesFactory, useTheme, TextArea, Button, IconButton } from '@grafana/ui'; import { stylesFactory, useTheme, TextArea, Button, IconButton } from '@grafana/ui';
import { getDataSourceSrv } from '@grafana/runtime'; import { getDataSourceSrv } from '@grafana/runtime';
@ -318,4 +317,4 @@ export function RichHistoryCard(props: Props) {
); );
} }
export default hot(module)(connector(RichHistoryCard)); export default connector(RichHistoryCard);

@ -1,7 +1,6 @@
// Libraries // Libraries
import React, { useState } from 'react'; import React, { useState } from 'react';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { hot } from 'react-hot-loader';
// Services & Utils // Services & Utils
import store from 'app/core/store'; import store from 'app/core/store';
@ -72,4 +71,4 @@ export function RichHistoryContainer(props: Props) {
); );
} }
export default hot(module)(connector(RichHistoryContainer)); export default connector(RichHistoryContainer);

@ -1,5 +1,4 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { ValueLinkConfig } from '@grafana/data'; import { ValueLinkConfig } from '@grafana/data';
import { Collapse, Table } from '@grafana/ui'; import { Collapse, Table } from '@grafana/ui';
@ -84,4 +83,4 @@ export class TableContainer extends PureComponent<Props> {
} }
} }
export default hot(module)(connector(TableContainer)); export default connector(TableContainer);

@ -4,7 +4,6 @@ import Page from 'app/core/components/Page/Page';
import { Button, Input, Field, Form } from '@grafana/ui'; import { Button, Input, Field, Form } from '@grafana/ui';
import { getConfig } from 'app/core/config'; import { getConfig } from 'app/core/config';
import { StoreState } from 'app/types'; import { StoreState } from 'app/types';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { NavModel } from '@grafana/data'; import { NavModel } from '@grafana/data';
import { getNavModel } from '../../core/selectors/navModel'; import { getNavModel } from '../../core/selectors/navModel';
@ -76,4 +75,4 @@ const mapStateToProps = (state: StoreState) => {
return { navModel: getNavModel(state.navIndex, 'global-orgs') }; return { navModel: getNavModel(state.navIndex, 'global-orgs') };
}; };
export default hot(module)(connect(mapStateToProps)(NewOrgPage)); export default connect(mapStateToProps)(NewOrgPage);

@ -1,5 +1,4 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { NavModel } from '@grafana/data'; import { NavModel } from '@grafana/data';
@ -62,4 +61,4 @@ const mapDispatchToProps = {
updateOrganization, updateOrganization,
}; };
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(OrgDetailsPage)); export default connect(mapStateToProps, mapDispatchToProps)(OrgDetailsPage);

@ -1,5 +1,4 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import UserInviteForm from './UserInviteForm'; import UserInviteForm from './UserInviteForm';
import { contextSrv, NavModel } from 'app/core/core'; import { contextSrv, NavModel } from 'app/core/core';
@ -30,4 +29,4 @@ const mapStateToProps = (state: StoreState) => ({
navModel: getNavModel(state.navIndex, 'users'), navModel: getNavModel(state.navIndex, 'users'),
}); });
export default hot(module)(connect(mapStateToProps)(UserInvitePage)); export default connect(mapStateToProps)(UserInvitePage);

@ -1,5 +1,4 @@
import React from 'react'; import React from 'react';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import Page from 'app/core/components/Page/Page'; import Page from 'app/core/components/Page/Page';
import PageActionBar from 'app/core/components/PageActionBar/PageActionBar'; import PageActionBar from 'app/core/components/PageActionBar/PageActionBar';
@ -65,4 +64,4 @@ export const PluginListPage: React.FC<Props> = ({
); );
}; };
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(PluginListPage)); export default connect(mapStateToProps, mapDispatchToProps)(PluginListPage);

@ -6,7 +6,6 @@ import { getAllPluginsErrors } from './state/selectors';
import { loadPlugins, loadPluginsErrors } from './state/actions'; import { loadPlugins, loadPluginsErrors } from './state/actions';
import useAsync from 'react-use/lib/useAsync'; import useAsync from 'react-use/lib/useAsync';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { hot } from 'react-hot-loader';
import { PluginErrorCode, PluginSignatureStatus } from '@grafana/data'; import { PluginErrorCode, PluginSignatureStatus } from '@grafana/data';
import { css } from '@emotion/css'; import { css } from '@emotion/css';
@ -80,9 +79,7 @@ export const PluginsErrorsInfoUnconnected: React.FC<PluginsErrorsInfoProps> = ({
); );
}; };
export const PluginsErrorsInfo = hot(module)( export const PluginsErrorsInfo = connect(mapStateToProps, mapDispatchToProps)(PluginsErrorsInfoUnconnected);
connect(mapStateToProps, mapDispatchToProps)(PluginsErrorsInfoUnconnected)
);
function mapPluginErrorCodeToSignatureStatus(code: PluginErrorCode) { function mapPluginErrorCodeToSignatureStatus(code: PluginErrorCode) {
switch (code) { switch (code) {

@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import { useMount } from 'react-use'; import { useMount } from 'react-use';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { NavModel } from '@grafana/data'; import { NavModel } from '@grafana/data';
@ -50,4 +49,4 @@ export function ChangePasswordPage({ navModel, loadUser, isUpdating, user, chang
); );
} }
export default hot(module)(connector(ChangePasswordPage)); export default connector(ChangePasswordPage);

@ -1,7 +1,6 @@
import React from 'react'; import React from 'react';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { useMount } from 'react-use'; import { useMount } from 'react-use';
import { hot } from 'react-hot-loader';
import { NavModel } from '@grafana/data'; import { NavModel } from '@grafana/data';
import { VerticalGroup } from '@grafana/ui'; import { VerticalGroup } from '@grafana/ui';
@ -78,4 +77,4 @@ export function UserProfileEditPage({
); );
} }
export default hot(module)(connector(UserProfileEditPage)); export default connector(UserProfileEditPage);

@ -25,9 +25,9 @@ import {
QueryOperationRowRenderProps, QueryOperationRowRenderProps,
} from 'app/core/components/QueryOperationRow/QueryOperationRow'; } from 'app/core/components/QueryOperationRow/QueryOperationRow';
import { QueryOperationAction } from 'app/core/components/QueryOperationRow/QueryOperationAction'; import { QueryOperationAction } from 'app/core/components/QueryOperationRow/QueryOperationAction';
import { DashboardModel } from '../../dashboard/state/DashboardModel';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
import { PanelModel } from 'app/features/dashboard/state'; import { PanelModel } from 'app/features/dashboard/state/PanelModel';
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
import { OperationRowHelp } from 'app/core/components/QueryOperationRow/OperationRowHelp'; import { OperationRowHelp } from 'app/core/components/QueryOperationRow/OperationRowHelp';
interface Props<TQuery extends DataQuery> { interface Props<TQuery extends DataQuery> {

@ -1,6 +1,5 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import Page from 'app/core/components/Page/Page'; import Page from 'app/core/components/Page/Page';
import { hot } from 'react-hot-loader';
import { Button, Form, Field, Input, FieldSet, Label, Tooltip, Icon } from '@grafana/ui'; import { Button, Form, Field, Input, FieldSet, Label, Tooltip, Icon } from '@grafana/ui';
import { NavModel } from '@grafana/data'; import { NavModel } from '@grafana/data';
import { getBackendSrv, locationService } from '@grafana/runtime'; import { getBackendSrv, locationService } from '@grafana/runtime';
@ -68,4 +67,4 @@ function mapStateToProps(state: StoreState) {
}; };
} }
export default hot(module)(connect(mapStateToProps)(CreateTeam)); export default connect(mapStateToProps)(CreateTeam);

@ -1,5 +1,4 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import Page from 'app/core/components/Page/Page'; import Page from 'app/core/components/Page/Page';
import { DeleteButton, LinkButton } from '@grafana/ui'; import { DeleteButton, LinkButton } from '@grafana/ui';
import { NavModel } from '@grafana/data'; import { NavModel } from '@grafana/data';
@ -167,4 +166,4 @@ const mapDispatchToProps = {
setSearchQuery, setSearchQuery,
}; };
export default hot(module)(connectWithCleanUp(mapStateToProps, mapDispatchToProps, (state) => state.teams)(TeamList)); export default connectWithCleanUp(mapStateToProps, mapDispatchToProps, (state) => state.teams)(TeamList);

@ -1,5 +1,4 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux'; import { connect, ConnectedProps } from 'react-redux';
import { renderMarkdown } from '@grafana/data'; import { renderMarkdown } from '@grafana/data';
import { HorizontalGroup, Pagination, VerticalGroup } from '@grafana/ui'; import { HorizontalGroup, Pagination, VerticalGroup } from '@grafana/ui';
@ -138,4 +137,4 @@ export class UsersListPage extends PureComponent<Props, State> {
} }
} }
export default hot(module)(connector(UsersListPage)); export default connector(UsersListPage);

@ -1,20 +1,19 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width" />
<meta name="theme-color" content="#000"> <meta name="theme-color" content="#000" />
<title>Grafana - Error</title> <title>Grafana - Error</title>
<base href="[[.AppSubUrl]]/" /> <base href="[[.AppSubUrl]]/" />
<link rel="stylesheet" href="public/build/grafana.[[ .Theme ]].<%= webpack.hash %>.css"> <link rel="stylesheet" href="public/build/grafana.[[ .Theme ]].<%= compilation.hash %>.css" />
<link rel="icon" type="image/png" href="public/img/fav32.png">
<link rel="mask-icon" href="public/img/grafana_mask_icon.svg" color="#F05A28">
<link rel="icon" type="image/png" href="public/img/fav32.png" />
<link rel="mask-icon" href="public/img/grafana_mask_icon.svg" color="#F05A28" />
</head> </head>
<body class="theme-[[ .Theme ]]"> <body class="theme-[[ .Theme ]]">
@ -43,10 +42,10 @@
</div> </div>
<br /> <br />
[[if .ErrorMsg]] [[if .ErrorMsg]]
<h4 class="page-heading">Error details</h4> <h4 class="page-heading">Error details</h4>
<div class="alert-text"> <div class="alert-text">
<pre>[[.ErrorMsg]]</pre> <pre>[[.ErrorMsg]]</pre>
</div> </div>
[[end]] [[end]]
<div style="padding: 2rem 0 0"> <div style="padding: 2rem 0 0">
<p>Check the Grafana server logs for the detailed error message.</p> <p>Check the Grafana server logs for the detailed error message.</p>

@ -20,7 +20,10 @@
<link rel="icon" type="image/png" href="[[.FavIcon]]" /> <link rel="icon" type="image/png" href="[[.FavIcon]]" />
<link rel="apple-touch-icon" sizes="180x180" href="[[.AppleTouchIcon]]" /> <link rel="apple-touch-icon" sizes="180x180" href="[[.AppleTouchIcon]]" />
<link rel="mask-icon" href="[[.ContentDeliveryURL]]public/img/grafana_mask_icon.svg" color="#F05A28" /> <link rel="mask-icon" href="[[.ContentDeliveryURL]]public/img/grafana_mask_icon.svg" color="#F05A28" />
<link rel="stylesheet" href="[[.ContentDeliveryURL]]public/build/grafana.[[ .Theme ]].<%= webpack.hash %>.css" /> <link
rel="stylesheet"
href="[[.ContentDeliveryURL]]public/build/grafana.[[ .Theme ]].<%= compilation.hash %>.css"
/>
<script nonce="[[.Nonce]]"> <script nonce="[[.Nonce]]">
performance.mark('frontend_boot_css_time_seconds'); performance.mark('frontend_boot_css_time_seconds');
@ -248,8 +251,8 @@
settings: [[.Settings]], settings: [[.Settings]],
navTree: [[.NavTree]], navTree: [[.NavTree]],
themePaths: { themePaths: {
light: '[[.ContentDeliveryURL]]public/build/grafana.light.<%= webpack.hash %>.css', light: '[[.ContentDeliveryURL]]public/build/grafana.light.<%= compilation.hash %>.css',
dark: '[[.ContentDeliveryURL]]public/build/grafana.dark.<%= webpack.hash %>.css' dark: '[[.ContentDeliveryURL]]public/build/grafana.dark.<%= compilation.hash %>.css'
} }
}; };
@ -303,18 +306,18 @@
})(window, document, 'script', 'dataLayer', '[[.GoogleTagManagerId]]'); })(window, document, 'script', 'dataLayer', '[[.GoogleTagManagerId]]');
</script> </script>
<!-- End Google Tag Manager --> <!-- End Google Tag Manager -->
[[end]] <% for (key in htmlWebpackPlugin.files.chunks) { %> <% if (htmlWebpackPlugin.files.jsIntegrity) { %> [[end]] <% for (index in htmlWebpackPlugin.files.js) { %> <% if (htmlWebpackPlugin.files.jsIntegrity) { %>
<script <script
nonce="[[.Nonce]]" nonce="[[.Nonce]]"
src="[[.ContentDeliveryURL]]<%= htmlWebpackPlugin.files.chunks[key].entry %>" src="[[.ContentDeliveryURL]]<%= htmlWebpackPlugin.files.js[index] %>"
type="text/javascript" type="text/javascript"
integrity="<%= htmlWebpackPlugin.files.jsIntegrity[htmlWebpackPlugin.files.js.indexOf(htmlWebpackPlugin.files.chunks[key].entry)] %>" integrity="<%= htmlWebpackPlugin.files.jsIntegrity[index] %>"
crossorigin="<%= webpackConfig.output.crossOriginLoading %>" crossorigin="<%= webpackConfig.output.crossOriginLoading %>"
></script> ></script>
<% } else { %> <% } else { %>
<script <script
nonce="[[.Nonce]]" nonce="[[.Nonce]]"
src="[[.ContentDeliveryURL]]<%= htmlWebpackPlugin.files.chunks[key].entry %>" src="[[.ContentDeliveryURL]]<%= htmlWebpackPlugin.files.js[index] %>"
type="text/javascript" type="text/javascript"
></script> ></script>
<% } %> <% } %> <% } %> <% } %>

@ -1,6 +1,7 @@
module.exports = function getBabelConfig(options = {}) { module.exports = function getBabelConfig(options = {}) {
return { const babelOptions = {
cacheDirectory: true, cacheDirectory: true,
cacheCompression: false,
babelrc: false, babelrc: false,
// Note: order is bottom-to-top and/or right-to-left // Note: order is bottom-to-top and/or right-to-left
presets: [ presets: [
@ -43,4 +44,10 @@ module.exports = function getBabelConfig(options = {}) {
'angularjs-annotate', 'angularjs-annotate',
], ],
}; };
if (options.REACT_REFRESH) {
babelOptions.plugins.push('react-refresh/babel');
}
return babelOptions;
}; };

@ -83,7 +83,7 @@ module.exports.pitch = function pitch(remainingRequest) {
function getOutputFilename(options, { target }) { function getOutputFilename(options, { target }) {
if (!options) { if (!options) {
return { filename: `[hash].${target}.js`, options: undefined }; return { filename: `[fullhash].${target}.js`, options: undefined };
} }
if (typeof options === 'string') { if (typeof options === 'string') {
return { filename: options, options: undefined }; return { filename: options, options: undefined };

@ -1,9 +1,7 @@
module.exports = () => { module.exports = {
return { plugins: {
plugins: { autoprefixer: {},
autoprefixer: {}, 'postcss-reporter': {},
'postcss-reporter': {}, 'postcss-browser-reporter': {},
'postcss-browser-reporter': {}, },
},
};
}; };

@ -1,10 +1,12 @@
'use strict'; 'use strict';
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = function (options) { module.exports = function (options) {
return { return {
test: /\.scss$/, test: /\.scss$/,
exclude: /node_modules/,
use: [ use: [
MiniCssExtractPlugin.loader, MiniCssExtractPlugin.loader,
{ {
@ -19,7 +21,9 @@ module.exports = function (options) {
loader: 'postcss-loader', loader: 'postcss-loader',
options: { options: {
sourceMap: options.sourceMap, sourceMap: options.sourceMap,
config: { path: __dirname }, postcssOptions: {
config: path.resolve(__dirname),
},
}, },
}, },
{ {

@ -2,7 +2,6 @@ const fs = require('fs-extra');
const path = require('path'); const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin');
const getBabelConfig = require('./babel.config');
class CopyUniconsPlugin { class CopyUniconsPlugin {
apply(compiler) { apply(compiler) {
@ -17,31 +16,15 @@ class CopyUniconsPlugin {
} }
} }
// https://github.com/visionmedia/debug/issues/701#issuecomment-505487361
function shouldExclude(filename) {
// There is external js code inside this which needs to be processed by babel.
if (filename.indexOf(`jaeger-ui-components`) > 0) {
return false;
}
const packagesToProcessbyBabel = ['debug', 'lru-cache', 'yallist', 'react-hook-form', 'rc-trigger'];
for (const package of packagesToProcessbyBabel) {
if (filename.indexOf(`node_modules/${package}`) > 0) {
return false;
}
}
return true;
}
console.log(path.resolve());
module.exports = { module.exports = {
target: 'web', target: 'web',
entry: { entry: {
app: './public/app/index.ts', app: './public/app/index.ts',
}, },
output: { output: {
clean: true,
path: path.resolve(__dirname, '../../public/build'), path: path.resolve(__dirname, '../../public/build'),
filename: '[name].[hash].js', filename: '[name].[fullhash].js',
// Keep publicPath relative for host.com/grafana/ deployments // Keep publicPath relative for host.com/grafana/ deployments
publicPath: 'public/build/', publicPath: 'public/build/',
}, },
@ -64,15 +47,16 @@ module.exports = {
// we need full path to root node_modules for grafana-enterprise symlink to work // we need full path to root node_modules for grafana-enterprise symlink to work
path.resolve('node_modules'), path.resolve('node_modules'),
], ],
fallback: {
fs: false,
stream: false,
},
}, },
ignoreWarnings: [/export .* was not found in/],
stats: { stats: {
children: false, children: false,
warningsFilter: /export .* was not found in/,
source: false, source: false,
}, },
node: {
fs: 'empty',
},
plugins: [ plugins: [
new CopyUniconsPlugin(), new CopyUniconsPlugin(),
new CopyWebpackPlugin({ new CopyWebpackPlugin({
@ -97,33 +81,12 @@ module.exports = {
], ],
module: { module: {
rules: [ rules: [
/**
* Some npm packages are bundled with es2015 syntax, ie. debug
* To make them work with PhantomJS we need to transpile them
* to get rid of unsupported syntax.
*/
{
test: /\.js$/,
exclude: shouldExclude,
use: [
{
loader: 'babel-loader',
options: getBabelConfig(),
},
],
},
{ {
test: require.resolve('jquery'), test: require.resolve('jquery'),
use: [ loader: 'expose-loader',
{ options: {
loader: 'expose-loader', exposes: ['$', 'jQuery'],
query: 'jQuery', },
},
{
loader: 'expose-loader',
query: '$',
},
],
}, },
{ {
test: /\.html$/, test: /\.html$/,
@ -135,10 +98,11 @@ module.exports = {
{ {
loader: 'html-loader', loader: 'html-loader',
options: { options: {
attrs: [], sources: false,
minimize: true, minimize: {
removeComments: false, removeComments: false,
collapseWhitespace: false, collapseWhitespace: false,
},
}, },
}, },
], ],
@ -170,7 +134,7 @@ module.exports = {
}, },
// https://webpack.js.org/plugins/split-chunks-plugin/#split-chunks-example-3 // https://webpack.js.org/plugins/split-chunks-plugin/#split-chunks-example-3
optimization: { optimization: {
moduleIds: 'hashed', moduleIds: 'named',
runtimeChunk: 'single', runtimeChunk: 'single',
splitChunks: { splitChunks: {
chunks: 'all', chunks: 'all',
@ -194,7 +158,7 @@ module.exports = {
priority: 50, priority: 50,
enforce: true, enforce: true,
}, },
vendors: { defaultVendors: {
test: /[\\/]node_modules[\\/].*[jt]sx?$/, test: /[\\/]node_modules[\\/].*[jt]sx?$/,
chunks: 'initial', chunks: 'initial',
priority: -10, priority: -10,

@ -1,11 +1,11 @@
'use strict'; 'use strict';
const merge = require('webpack-merge'); const { merge } = require('webpack-merge');
const common = require('./webpack.common.js'); const common = require('./webpack.common.js');
const path = require('path'); const path = require('path');
const webpack = require('webpack'); const { DefinePlugin } = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const ESLintPlugin = require('eslint-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const getBabelConfig = require('./babel.config'); const getBabelConfig = require('./babel.config');
@ -32,13 +32,11 @@ module.exports = (env = {}) =>
rules: [ rules: [
{ {
test: /\.tsx?$/, test: /\.tsx?$/,
use: {
loader: 'babel-loader',
options: getBabelConfig({ BABEL_ENV: 'dev' }),
},
exclude: /node_modules/, exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: getBabelConfig({ BABEL_ENV: 'dev' }),
},
],
}, },
require('./sass.rule.js')({ require('./sass.rule.js')({
sourceMap: false, sourceMap: false,
@ -47,19 +45,25 @@ module.exports = (env = {}) =>
], ],
}, },
// https://webpack.js.org/guides/build-performance/#output-without-path-info
output: {
pathinfo: false,
filename: '[name].js',
},
// https://webpack.js.org/guides/build-performance/#avoid-extra-optimization-steps
optimization: {
runtimeChunk: true,
removeAvailableModules: false,
removeEmptyChunks: false,
splitChunks: false,
},
plugins: [ plugins: [
new CleanWebpackPlugin(), parseInt(env.noTsCheck, 10)
env.noTsCheck ? new DefinePlugin({}) // bogus plugin to satisfy webpack API
? new webpack.DefinePlugin({}) // bogus plugin to satisfy webpack API
: new ForkTsCheckerWebpackPlugin({ : new ForkTsCheckerWebpackPlugin({
eslint: { async: true, // don't block webpack emit
enabled: true,
files: ['public/app/**/*.{ts,tsx}', 'packages/*/src/**/*.{ts,tsx}'],
options: {
cache: true,
},
memoryLimit: 4096,
},
typescript: { typescript: {
mode: 'write-references', mode: 'write-references',
memoryLimit: 4096, memoryLimit: 4096,
@ -69,8 +73,13 @@ module.exports = (env = {}) =>
}, },
}, },
}), }),
// next major version of ForkTsChecker is dropping support for ESLint
new ESLintPlugin({
lintDirtyModulesOnly: true, // don't lint on start, only lint changed files
extensions: ['.ts', '.tsx'],
}),
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
filename: 'grafana.[name].[hash].css', filename: 'grafana.[name].[fullhash].css',
}), }),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
filename: path.resolve(__dirname, '../../public/views/error.html'), filename: path.resolve(__dirname, '../../public/views/error.html'),
@ -82,13 +91,12 @@ module.exports = (env = {}) =>
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
filename: path.resolve(__dirname, '../../public/views/index.html'), filename: path.resolve(__dirname, '../../public/views/index.html'),
template: path.resolve(__dirname, '../../public/views/index-template.html'), template: path.resolve(__dirname, '../../public/views/index-template.html'),
hash: true,
inject: false, inject: false,
chunksSortMode: 'none', chunksSortMode: 'none',
excludeChunks: ['dark', 'light'], excludeChunks: ['dark', 'light'],
}), }),
new webpack.NamedModulesPlugin(), new DefinePlugin({
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
'process.env': { 'process.env': {
NODE_ENV: JSON.stringify('development'), NODE_ENV: JSON.stringify('development'),
}, },

@ -1,104 +1,91 @@
'use strict'; 'use strict';
const merge = require('webpack-merge'); const { merge } = require('webpack-merge');
const common = require('./webpack.common.js'); const common = require('./webpack.common.js');
const path = require('path'); const path = require('path');
const webpack = require('webpack'); const { DefinePlugin } = require('webpack');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const getBabelConfig = require('./babel.config'); const getBabelConfig = require('./babel.config');
module.exports = merge(common, { module.exports = merge(common, {
devtool: 'inline-source-map',
mode: 'development', mode: 'development',
entry: {
app: ['webpack-dev-server/client?http://localhost:3333', './public/app/dev.ts'],
},
output: { entry: {
path: path.resolve(__dirname, '../../public/build'), app: ['./public/app/index.ts'],
filename: '[name].[hash].js', dark: './public/sass/grafana.dark.scss',
publicPath: '/public/build/', light: './public/sass/grafana.light.scss',
pathinfo: false,
}, },
resolve: { watchOptions: {
extensions: ['.scss', '.ts', '.tsx', '.es6', '.js', '.json', '.svg', '.woff2', '.png', '.html'], ignored: /node_modules/,
}, },
devtool: 'eval-source-map',
devServer: { devServer: {
publicPath: '/public/build/', devMiddleware: {
writeToDisk: true,
},
historyApiFallback: true,
hot: true, hot: true,
open: false,
port: 3333, port: 3333,
proxy: { proxy: {
'!/public/build': 'http://localhost:3000', '!/public/build': 'http://localhost:3000',
}, },
watchOptions: { static: {
ignored: /node_modules/, publicPath: '/public/build/',
}, },
}, },
optimization: {
removeAvailableModules: false,
runtimeChunk: false,
removeEmptyChunks: false,
splitChunks: false,
},
module: { module: {
// Note: order is bottom-to-top and/or right-to-left // Note: order is bottom-to-top and/or right-to-left
rules: [ rules: [
{ {
test: /\.tsx?$/, test: /\.tsx?$/,
use: {
loader: 'babel-loader',
options: getBabelConfig({ BABEL_ENV: 'dev', REACT_REFRESH: true }),
},
exclude: /node_modules/, exclude: /node_modules/,
use: [ include: [path.resolve(__dirname, '../../public/'), path.resolve(__dirname, '../../packages/')],
{
loader: 'babel-loader',
options: getBabelConfig(),
},
],
},
{
test: /\.scss$/,
use: [
'style-loader', // creates style nodes from JS strings
'css-loader', // translates CSS into CommonJS
{
loader: 'postcss-loader',
options: {
config: {
path: __dirname + '/postcss.config.js',
},
},
},
{
loader: 'sass-loader',
},
],
},
{
test: /\.(png|jpg|gif|ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
loader: 'file-loader',
}, },
require('./sass.rule.js')({
sourceMap: false,
preserveUrl: false,
}),
], ],
}, },
// https://webpack.js.org/guides/build-performance/#output-without-path-info
output: {
filename: '[name].js',
pathinfo: false,
},
// https://webpack.js.org/guides/build-performance/#avoid-extra-optimization-steps
optimization: {
runtimeChunk: true,
removeAvailableModules: false,
removeEmptyChunks: false,
splitChunks: false,
},
plugins: [ plugins: [
new CleanWebpackPlugin(), new MiniCssExtractPlugin({
filename: 'grafana.[name].[fullhash].css',
}),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
filename: path.resolve(__dirname, '../../public/views/index.html'), filename: path.resolve(__dirname, '../../public/views/index.html'),
template: path.resolve(__dirname, '../../public/views/index-template.html'), template: path.resolve(__dirname, '../../public/views/index-template.html'),
inject: 'body', hash: true,
alwaysWriteToDisk: true, inject: false,
chunksSortMode: 'none', chunksSortMode: 'none',
excludeChunks: ['dark', 'light'],
}), }),
new HtmlWebpackHarddiskPlugin(), new ReactRefreshWebpackPlugin(),
new webpack.NamedModulesPlugin(), new DefinePlugin({
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
GRAFANA_THEME: JSON.stringify(process.env.GRAFANA_THEME || 'dark'),
'process.env': { 'process.env': {
NODE_ENV: JSON.stringify('development'), NODE_ENV: JSON.stringify('development'),
}, },

@ -1,12 +1,12 @@
'use strict'; 'use strict';
const merge = require('webpack-merge'); const { merge } = require('webpack-merge');
const TerserPlugin = require('terser-webpack-plugin'); const TerserPlugin = require('terser-webpack-plugin');
const common = require('./webpack.common.js'); const common = require('./webpack.common.js');
const path = require('path'); const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const getBabelConfig = require('./babel.config'); const getBabelConfig = require('./babel.config');
module.exports = merge(common, { module.exports = merge(common, {
@ -41,16 +41,14 @@ module.exports = merge(common, {
nodeEnv: 'production', nodeEnv: 'production',
minimizer: [ minimizer: [
new TerserPlugin({ new TerserPlugin({
cache: false,
parallel: false, parallel: false,
sourceMap: true,
}), }),
new OptimizeCSSAssetsPlugin({}), new CssMinimizerPlugin(),
], ],
}, },
plugins: [ plugins: [
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
filename: 'grafana.[name].[hash].css', filename: 'grafana.[name].[fullhash].css',
}), }),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
filename: path.resolve(__dirname, '../../public/views/error.html'), filename: path.resolve(__dirname, '../../public/views/error.html'),

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save