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
- [Frontend Style Guide](#frontend-style-guide)
- [Table of Contents](#table-of-contents)
- [Basic rules](#basic-rules)
- [Naming conventions](#naming-conventions)
@ -28,10 +29,10 @@ Generally we follow the Airbnb [React Style Guide](https://github.com/airbnb/jav
- [Linting](#linting)
- [React](#react)
- [Props](#props)
- [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 constructor](#react-component-constructor)
- [React Component defaultProps](#react-component-defaultprops)
- [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 constructor](#react-component-constructor)
- [React Component defaultProps](#react-component-defaultprops)
- [State management](#state-management)
- [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
function transform(value?: string) {
if (!value) {
return undefined
return undefined;
}
return applyTransform(value)
};
return applyTransform(value);
}
// good
function transform(value?: string): TransformedValue | undefined {
if (!value) {
return undefined
return undefined;
}
return applyTransform(value)
};
return applyTransform(value);
}
```
### File and directory naming conventions

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

@ -17,11 +17,11 @@ const startTaskRunner: TaskRunner<StartTaskOptions> = async ({ watchThemes, noTs
},
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',
}
: {
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',
},
];

@ -1,7 +1,8 @@
const path = require('path');
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 getBabelConfig = require('../../../scripts/webpack/babel.config');
const stories = ['../src/**/*.story.{js,jsx,ts,tsx,mdx}'];
@ -23,8 +24,12 @@ module.exports = {
'@storybook/addon-storysource',
'storybook-dark-mode',
],
reactOptions: {
fastRefresh: true,
// currently broken in webpack 5 builder support
// reactOptions: {
// fastRefresh: true,
// },
core: {
builder: 'webpack5',
},
typescript: {
check: true,
@ -39,6 +44,22 @@ module.exports = {
},
webpackFinal: async (config: any, { configType }: any) => {
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 || []),
{
@ -52,6 +73,8 @@ module.exports = {
},
},
],
exclude: /node_modules/,
include: [path.resolve(__dirname, '../../../public/'), path.resolve(__dirname, '../../../packages/')],
},
{
test: /\.scss$/,
@ -63,6 +86,7 @@ module.exports = {
{
loader: 'css-loader',
options: {
url: false,
importLoaders: 2,
},
},
@ -70,7 +94,9 @@ module.exports = {
loader: 'postcss-loader',
options: {
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'),
use: [
{
loader: 'expose-loader',
query: 'jQuery',
},
{
loader: 'expose-loader',
query: '$',
},
],
loader: 'expose-loader',
options: {
exposes: ['$', 'jQuery'],
},
},
];
config.optimization = {
nodeEnv: 'production',
moduleIds: 'hashed',
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
minChunks: 1,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/].*[jt]sx?$/,
chunks: 'initial',
priority: -10,
reuseExistingChunk: true,
enforce: true,
},
default: {
priority: -20,
chunks: 'all',
test: /.*[jt]sx?$/,
reuseExistingChunk: true,
if (isProductionBuild) {
config.optimization = {
nodeEnv: 'production',
moduleIds: 'deterministic',
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
minChunks: 1,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/].*[jt]sx?$/,
chunks: 'initial',
priority: -10,
reuseExistingChunk: true,
enforce: true,
},
default: {
priority: -20,
chunks: 'all',
test: /.*[jt]sx?$/,
reuseExistingChunk: true,
},
},
},
},
minimize: isProductionBuild,
minimizer: isProductionBuild
? [
new TerserPlugin({ cache: false, parallel: false, sourceMap: false, exclude: /monaco/ }),
new OptimizeCSSAssetsPlugin({}),
]
: [],
};
minimize: isProductionBuild,
minimizer: isProductionBuild
? [new TerserPlugin({ parallel: false, exclude: /monaco/ }), new CssMinimizerPlugin()]
: [],
};
}
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",
"typecheck": "tsc --noEmit"
},
"browserslist": [
"defaults",
"not IE 11"
],
"dependencies": {
"@emotion/css": "11.1.3",
"@emotion/react": "11.1.5",
@ -81,6 +85,8 @@
"@storybook/addon-storysource": "6.3.7",
"@storybook/react": "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",
"@types/classnames": "2.2.7",
"@types/common-tags": "^1.8.0",

@ -1,7 +1,5 @@
import React from 'react';
import { connect } from 'react-redux';
import { hot } from 'react-hot-loader';
import { getBackendSrv } from '@grafana/runtime';
import { NavModel } from '@grafana/data';
@ -74,4 +72,4 @@ const mapStateToProps = (state: StoreState) => ({
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 { connect } from 'react-redux';
import { hot } from 'react-hot-loader';
import { css } from '@emotion/css';
import { LinkButton, useStyles2 } from '@grafana/ui';
import { GrafanaTheme2, NavModel } from '@grafana/data';
@ -231,4 +230,4 @@ const mapStateToProps = (state: StoreState) => ({
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 { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux';
import { NavModel } from '@grafana/data';
import { getNavModel } from 'app/core/selectors/navModel';
@ -177,4 +176,4 @@ const mapDispatchToProps = {
const connector = connect(mapStateToProps, mapDispatchToProps);
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 { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
import { Form, Button, Input, Field } from '@grafana/ui';
import { NavModel } from '@grafana/data';
@ -83,4 +82,4 @@ const mapStateToProps = (state: StoreState) => ({
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 { css, cx } from '@emotion/css';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux';
import { Pagination, Tooltip, stylesFactory, LinkButton, Icon } from '@grafana/ui';
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 { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux';
import { NavModel } from '@grafana/data';
import { Alert, Button, LegacyForms } from '@grafana/ui';
@ -160,4 +159,4 @@ const mapDispatchToProps = {
const connector = connect(mapStateToProps, mapDispatchToProps);
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 { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux';
import Page from 'app/core/components/Page/Page';
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 { connect, ConnectedProps } from 'react-redux';
import { hot } from 'react-hot-loader';
// Utils
import { ApiKey, NewApiKey, StoreState } from 'app/types';
import { getNavModel } from 'app/core/selectors/navModel';
@ -168,4 +167,4 @@ export class ApiKeysPageUnconnected extends PureComponent<Props, State> {
}
const ApiKeysPage = connector(ApiKeysPageUnconnected);
export default hot(module)(ApiKeysPage);
export default ApiKeysPage;

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

@ -1,5 +1,4 @@
import React, { Component } from 'react';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux';
import AutoSizer from 'react-virtualized-auto-sizer';
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
import React, { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { hot } from 'react-hot-loader';
// Components
import Page from 'app/core/components/Page/Page';
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 { connect, ConnectedProps } from 'react-redux';
import { hot } from 'react-hot-loader';
import { DataSourcePluginMeta, NavModel } from '@grafana/data';
import { Button, LinkButton, List, PluginSignatureBadge } from '@grafana/ui';
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 { hot } from 'react-hot-loader';
import { css, cx } from '@emotion/css';
import { compose } from 'redux';
import { connect, ConnectedProps } from 'react-redux';
@ -408,4 +407,4 @@ const 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 { runQueries } from './state/query';
import { StoreState, ExploreItemState, ExploreId } from 'app/types';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux';
import { ExploreDrawer } from 'app/features/explore/ExploreDrawer';
import { InspectJSONTab } from 'app/features/inspector/InspectJSONTab';
@ -93,4 +92,4 @@ const 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 { connect, ConnectedProps } from 'react-redux';
import { hot } from 'react-hot-loader';
import classNames from 'classnames';
import { css } from '@emotion/css';
@ -251,4 +250,4 @@ const 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 { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux';
import { css } from 'emotion';
import { Collapse } from '@grafana/ui';
@ -192,4 +191,4 @@ const mapDispatchToProps = {
const connector = connect(mapStateToProps, mapDispatchToProps);
type PropsFromRedux = ConnectedProps<typeof connector>;
export default hot(module)(connector(LogsContainer));
export default connector(LogsContainer);

@ -1,7 +1,6 @@
// Libraries
import React, { PureComponent } from 'react';
import { debounce, has } from 'lodash';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux';
import AngularQueryEditor from './QueryEditor';
import { QueryRowActions } from './QueryRowActions';
@ -201,4 +200,4 @@ const 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 { connect, ConnectedProps } from 'react-redux';
import { hot } from 'react-hot-loader';
import { css, cx } from '@emotion/css';
import { stylesFactory, useTheme, TextArea, Button, IconButton } from '@grafana/ui';
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
import React, { useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { hot } from 'react-hot-loader';
// Services & Utils
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 { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux';
import { ValueLinkConfig } from '@grafana/data';
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 { getConfig } from 'app/core/config';
import { StoreState } from 'app/types';
import { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
import { NavModel } from '@grafana/data';
import { getNavModel } from '../../core/selectors/navModel';
@ -76,4 +75,4 @@ const mapStateToProps = (state: StoreState) => {
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 { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
import { NavModel } from '@grafana/data';
@ -62,4 +61,4 @@ const mapDispatchToProps = {
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 { hot } from 'react-hot-loader';
import { connect } from 'react-redux';
import UserInviteForm from './UserInviteForm';
import { contextSrv, NavModel } from 'app/core/core';
@ -30,4 +29,4 @@ const mapStateToProps = (state: StoreState) => ({
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 { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux';
import Page from 'app/core/components/Page/Page';
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 useAsync from 'react-use/lib/useAsync';
import { connect, ConnectedProps } from 'react-redux';
import { hot } from 'react-hot-loader';
import { PluginErrorCode, PluginSignatureStatus } from '@grafana/data';
import { css } from '@emotion/css';
@ -80,9 +79,7 @@ export const PluginsErrorsInfoUnconnected: React.FC<PluginsErrorsInfoProps> = ({
);
};
export const PluginsErrorsInfo = hot(module)(
connect(mapStateToProps, mapDispatchToProps)(PluginsErrorsInfoUnconnected)
);
export const PluginsErrorsInfo = connect(mapStateToProps, mapDispatchToProps)(PluginsErrorsInfoUnconnected);
function mapPluginErrorCodeToSignatureStatus(code: PluginErrorCode) {
switch (code) {

@ -1,6 +1,5 @@
import React from 'react';
import { useMount } from 'react-use';
import { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux';
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 { connect, ConnectedProps } from 'react-redux';
import { useMount } from 'react-use';
import { hot } from 'react-hot-loader';
import { NavModel } from '@grafana/data';
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,
} from 'app/core/components/QueryOperationRow/QueryOperationRow';
import { QueryOperationAction } from 'app/core/components/QueryOperationRow/QueryOperationAction';
import { DashboardModel } from '../../dashboard/state/DashboardModel';
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';
interface Props<TQuery extends DataQuery> {

@ -1,6 +1,5 @@
import React, { PureComponent } from 'react';
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 { NavModel } from '@grafana/data';
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 { hot } from 'react-hot-loader';
import Page from 'app/core/components/Page/Page';
import { DeleteButton, LinkButton } from '@grafana/ui';
import { NavModel } from '@grafana/data';
@ -167,4 +166,4 @@ const mapDispatchToProps = {
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 { hot } from 'react-hot-loader';
import { connect, ConnectedProps } from 'react-redux';
import { renderMarkdown } from '@grafana/data';
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>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#000">
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width" />
<meta name="theme-color" content="#000" />
<title>Grafana - Error</title>
<base href="[[.AppSubUrl]]/" />
<link rel="stylesheet" href="public/build/grafana.[[ .Theme ]].<%= webpack.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="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" />
</head>
<body class="theme-[[ .Theme ]]">
@ -43,10 +42,10 @@
</div>
<br />
[[if .ErrorMsg]]
<h4 class="page-heading">Error details</h4>
<div class="alert-text">
<pre>[[.ErrorMsg]]</pre>
</div>
<h4 class="page-heading">Error details</h4>
<div class="alert-text">
<pre>[[.ErrorMsg]]</pre>
</div>
[[end]]
<div style="padding: 2rem 0 0">
<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="apple-touch-icon" sizes="180x180" href="[[.AppleTouchIcon]]" />
<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]]">
performance.mark('frontend_boot_css_time_seconds');
@ -248,8 +251,8 @@
settings: [[.Settings]],
navTree: [[.NavTree]],
themePaths: {
light: '[[.ContentDeliveryURL]]public/build/grafana.light.<%= webpack.hash %>.css',
dark: '[[.ContentDeliveryURL]]public/build/grafana.dark.<%= webpack.hash %>.css'
light: '[[.ContentDeliveryURL]]public/build/grafana.light.<%= compilation.hash %>.css',
dark: '[[.ContentDeliveryURL]]public/build/grafana.dark.<%= compilation.hash %>.css'
}
};
@ -303,18 +306,18 @@
})(window, document, 'script', 'dataLayer', '[[.GoogleTagManagerId]]');
</script>
<!-- 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
nonce="[[.Nonce]]"
src="[[.ContentDeliveryURL]]<%= htmlWebpackPlugin.files.chunks[key].entry %>"
src="[[.ContentDeliveryURL]]<%= htmlWebpackPlugin.files.js[index] %>"
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 %>"
></script>
<% } else { %>
<script
nonce="[[.Nonce]]"
src="[[.ContentDeliveryURL]]<%= htmlWebpackPlugin.files.chunks[key].entry %>"
src="[[.ContentDeliveryURL]]<%= htmlWebpackPlugin.files.js[index] %>"
type="text/javascript"
></script>
<% } %> <% } %>

@ -1,6 +1,7 @@
module.exports = function getBabelConfig(options = {}) {
return {
const babelOptions = {
cacheDirectory: true,
cacheCompression: false,
babelrc: false,
// Note: order is bottom-to-top and/or right-to-left
presets: [
@ -43,4 +44,10 @@ module.exports = function getBabelConfig(options = {}) {
'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 }) {
if (!options) {
return { filename: `[hash].${target}.js`, options: undefined };
return { filename: `[fullhash].${target}.js`, options: undefined };
}
if (typeof options === 'string') {
return { filename: options, options: undefined };

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

@ -1,10 +1,12 @@
'use strict';
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = function (options) {
return {
test: /\.scss$/,
exclude: /node_modules/,
use: [
MiniCssExtractPlugin.loader,
{
@ -19,7 +21,9 @@ module.exports = function (options) {
loader: 'postcss-loader',
options: {
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 CopyWebpackPlugin = require('copy-webpack-plugin');
const getBabelConfig = require('./babel.config');
class CopyUniconsPlugin {
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 = {
target: 'web',
entry: {
app: './public/app/index.ts',
},
output: {
clean: true,
path: path.resolve(__dirname, '../../public/build'),
filename: '[name].[hash].js',
filename: '[name].[fullhash].js',
// Keep publicPath relative for host.com/grafana/ deployments
publicPath: 'public/build/',
},
@ -64,15 +47,16 @@ module.exports = {
// we need full path to root node_modules for grafana-enterprise symlink to work
path.resolve('node_modules'),
],
fallback: {
fs: false,
stream: false,
},
},
ignoreWarnings: [/export .* was not found in/],
stats: {
children: false,
warningsFilter: /export .* was not found in/,
source: false,
},
node: {
fs: 'empty',
},
plugins: [
new CopyUniconsPlugin(),
new CopyWebpackPlugin({
@ -97,33 +81,12 @@ module.exports = {
],
module: {
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'),
use: [
{
loader: 'expose-loader',
query: 'jQuery',
},
{
loader: 'expose-loader',
query: '$',
},
],
loader: 'expose-loader',
options: {
exposes: ['$', 'jQuery'],
},
},
{
test: /\.html$/,
@ -135,10 +98,11 @@ module.exports = {
{
loader: 'html-loader',
options: {
attrs: [],
minimize: true,
removeComments: false,
collapseWhitespace: false,
sources: false,
minimize: {
removeComments: false,
collapseWhitespace: false,
},
},
},
],
@ -170,7 +134,7 @@ module.exports = {
},
// https://webpack.js.org/plugins/split-chunks-plugin/#split-chunks-example-3
optimization: {
moduleIds: 'hashed',
moduleIds: 'named',
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
@ -194,7 +158,7 @@ module.exports = {
priority: 50,
enforce: true,
},
vendors: {
defaultVendors: {
test: /[\\/]node_modules[\\/].*[jt]sx?$/,
chunks: 'initial',
priority: -10,

@ -1,11 +1,11 @@
'use strict';
const merge = require('webpack-merge');
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const path = require('path');
const webpack = require('webpack');
const { DefinePlugin } = require('webpack');
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 MiniCssExtractPlugin = require('mini-css-extract-plugin');
const getBabelConfig = require('./babel.config');
@ -32,13 +32,11 @@ module.exports = (env = {}) =>
rules: [
{
test: /\.tsx?$/,
use: {
loader: 'babel-loader',
options: getBabelConfig({ BABEL_ENV: 'dev' }),
},
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: getBabelConfig({ BABEL_ENV: 'dev' }),
},
],
},
require('./sass.rule.js')({
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: [
new CleanWebpackPlugin(),
env.noTsCheck
? new webpack.DefinePlugin({}) // bogus plugin to satisfy webpack API
parseInt(env.noTsCheck, 10)
? new DefinePlugin({}) // bogus plugin to satisfy webpack API
: new ForkTsCheckerWebpackPlugin({
eslint: {
enabled: true,
files: ['public/app/**/*.{ts,tsx}', 'packages/*/src/**/*.{ts,tsx}'],
options: {
cache: true,
},
memoryLimit: 4096,
},
async: true, // don't block webpack emit
typescript: {
mode: 'write-references',
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({
filename: 'grafana.[name].[hash].css',
filename: 'grafana.[name].[fullhash].css',
}),
new HtmlWebpackPlugin({
filename: path.resolve(__dirname, '../../public/views/error.html'),
@ -82,13 +91,12 @@ module.exports = (env = {}) =>
new HtmlWebpackPlugin({
filename: path.resolve(__dirname, '../../public/views/index.html'),
template: path.resolve(__dirname, '../../public/views/index-template.html'),
hash: true,
inject: false,
chunksSortMode: 'none',
excludeChunks: ['dark', 'light'],
}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
new DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('development'),
},

@ -1,104 +1,91 @@
'use strict';
const merge = require('webpack-merge');
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
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 HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const getBabelConfig = require('./babel.config');
module.exports = merge(common, {
devtool: 'inline-source-map',
mode: 'development',
entry: {
app: ['webpack-dev-server/client?http://localhost:3333', './public/app/dev.ts'],
},
output: {
path: path.resolve(__dirname, '../../public/build'),
filename: '[name].[hash].js',
publicPath: '/public/build/',
pathinfo: false,
entry: {
app: ['./public/app/index.ts'],
dark: './public/sass/grafana.dark.scss',
light: './public/sass/grafana.light.scss',
},
resolve: {
extensions: ['.scss', '.ts', '.tsx', '.es6', '.js', '.json', '.svg', '.woff2', '.png', '.html'],
watchOptions: {
ignored: /node_modules/,
},
devtool: 'eval-source-map',
devServer: {
publicPath: '/public/build/',
devMiddleware: {
writeToDisk: true,
},
historyApiFallback: true,
hot: true,
open: false,
port: 3333,
proxy: {
'!/public/build': 'http://localhost:3000',
},
watchOptions: {
ignored: /node_modules/,
static: {
publicPath: '/public/build/',
},
},
optimization: {
removeAvailableModules: false,
runtimeChunk: false,
removeEmptyChunks: false,
splitChunks: false,
},
module: {
// Note: order is bottom-to-top and/or right-to-left
rules: [
{
test: /\.tsx?$/,
use: {
loader: 'babel-loader',
options: getBabelConfig({ BABEL_ENV: 'dev', REACT_REFRESH: true }),
},
exclude: /node_modules/,
use: [
{
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',
include: [path.resolve(__dirname, '../../public/'), path.resolve(__dirname, '../../packages/')],
},
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: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: 'grafana.[name].[fullhash].css',
}),
new HtmlWebpackPlugin({
filename: path.resolve(__dirname, '../../public/views/index.html'),
template: path.resolve(__dirname, '../../public/views/index-template.html'),
inject: 'body',
alwaysWriteToDisk: true,
hash: true,
inject: false,
chunksSortMode: 'none',
excludeChunks: ['dark', 'light'],
}),
new HtmlWebpackHarddiskPlugin(),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
GRAFANA_THEME: JSON.stringify(process.env.GRAFANA_THEME || 'dark'),
new ReactRefreshWebpackPlugin(),
new DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('development'),
},

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

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