aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/config
diff options
context:
space:
mode:
authorJeremy Davis <jeremy.davis@sonarsource.com>2021-09-17 16:29:12 +0200
committersonartech <sonartech@sonarsource.com>2021-09-30 20:03:00 +0000
commit18582f55e72704e61c331467e90de7b023d0b46c (patch)
tree98baf9a40895b0fedb19f5d739e55ea2592f385b /server/sonar-web/config
parent62b21006de51a5b15819e70f4a0943ab983d2b68 (diff)
downloadsonarqube-18582f55e72704e61c331467e90de7b023d0b46c.tar.gz
sonarqube-18582f55e72704e61c331467e90de7b023d0b46c.zip
[NO-JIRA] use esbuild for sonar-web
Diffstat (limited to 'server/sonar-web/config')
-rw-r--r--server/sonar-web/config/InterpolateHtmlPlugin.js54
-rw-r--r--server/sonar-web/config/esbuild-config.js57
-rw-r--r--server/sonar-web/config/esbuild-documentation-plugin.js56
-rw-r--r--server/sonar-web/config/process-shim.js22
-rw-r--r--server/sonar-web/config/utils.js82
-rw-r--r--server/sonar-web/config/webpack.config.js189
6 files changed, 159 insertions, 301 deletions
diff --git a/server/sonar-web/config/InterpolateHtmlPlugin.js b/server/sonar-web/config/InterpolateHtmlPlugin.js
deleted file mode 100644
index f45b9329f98..00000000000
--- a/server/sonar-web/config/InterpolateHtmlPlugin.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2021 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-// Copied from https://github.com/facebook/create-react-app/blob/master/packages/react-dev-utils/InterpolateHtmlPlugin.js
-
-// This Webpack plugin lets us interpolate custom variables into `index.html`.
-// Usage: `new InterpolateHtmlPlugin({ 'MY_VARIABLE': 42 })`
-// Then, you can use %MY_VARIABLE% in your `index.html`.
-
-// It works in tandem with HtmlWebpackPlugin.
-// Learn more about creating plugins like this:
-// https://github.com/ampedandwired/html-webpack-plugin#events
-
-'use strict';
-const escapeStringRegexp = require('escape-string-regexp');
-
-class InterpolateHtmlPlugin {
- constructor(replacements) {
- this.replacements = replacements;
- }
-
- apply(compiler) {
- compiler.hooks.compilation.tap('InterpolateHtmlPlugin', compilation => {
- compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing.tap('InterpolateHtmlPlugin', data => {
- // Run HTML through a series of user-specified string replacements.
- Object.keys(this.replacements).forEach(key => {
- const value = this.replacements[key];
- data.html = data.html.replace(
- new RegExp('%' + escapeStringRegexp(key) + '%', 'g'),
- value
- );
- });
- });
- });
- }
-}
-
-module.exports = InterpolateHtmlPlugin;
diff --git a/server/sonar-web/config/esbuild-config.js b/server/sonar-web/config/esbuild-config.js
new file mode 100644
index 00000000000..c1cec016ba5
--- /dev/null
+++ b/server/sonar-web/config/esbuild-config.js
@@ -0,0 +1,57 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+const autoprefixer = require('autoprefixer');
+const postCssPlugin = require('esbuild-plugin-postcss2').default;
+const postCssCalc = require('postcss-calc');
+const postCssCustomProperties = require('postcss-custom-properties');
+const documentationPlugin = require('./esbuild-documentation-plugin');
+const { getCustomProperties } = require('./utils');
+
+module.exports = release => ({
+ entryPoints: ['src/main/js/app/index.ts'],
+ tsconfig: './tsconfig.json',
+ external: ['/images/*'],
+ loader: {
+ '.png': 'dataurl',
+ '.md': 'text'
+ },
+ define: {
+ 'process.cwd': 'dummy_process_cwd'
+ },
+ inject: ['config/process-shim.js'],
+ bundle: true,
+ minify: release,
+ sourcemap: true,
+ target: ['chrome58', 'firefox57', 'safari11', 'edge18'],
+ outfile: 'build/webapp/js/out.js',
+ plugins: [
+ postCssPlugin({
+ plugins: [
+ autoprefixer,
+ postCssCustomProperties({
+ importFrom: { customProperties: getCustomProperties() },
+ preserve: false
+ }),
+ postCssCalc
+ ]
+ }),
+ documentationPlugin()
+ ]
+});
diff --git a/server/sonar-web/config/esbuild-documentation-plugin.js b/server/sonar-web/config/esbuild-documentation-plugin.js
new file mode 100644
index 00000000000..57cf43aa919
--- /dev/null
+++ b/server/sonar-web/config/esbuild-documentation-plugin.js
@@ -0,0 +1,56 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+const fs = require('fs-extra');
+const path = require('path');
+const glob = require('glob-promise');
+
+module.exports = () => ({
+ name: 'doc-plugin',
+ setup({ onLoad }) {
+ /**
+ * @param {string} content
+ * @param {string} root
+ * @returns {string}
+ */
+ function handleIncludes(content, root) {
+ return content.replace(/@include (.+)/, (match, p) => {
+ const filePath = path.join(root, '..', `${p}.md`);
+ return fs.readFileSync(filePath, 'utf8');
+ });
+ }
+
+ onLoad({ filter: /\.directory-loader\.js$/ }, async args => {
+ const root = path.resolve(path.dirname(process.cwd()), './sonar-docs/src/pages');
+
+ const files = await glob(root + '/**/*.md');
+
+ const result = files
+ .map(file => file.substr(root.length + 1))
+ .map(file => ({
+ path: file.slice(0, -3),
+ content: handleIncludes(fs.readFileSync(`${root}/${file}`, 'utf8'), root)
+ }));
+
+ const contents = `module.exports = ${JSON.stringify(result)};`;
+
+ return { contents };
+ });
+ }
+});
diff --git a/server/sonar-web/config/process-shim.js b/server/sonar-web/config/process-shim.js
new file mode 100644
index 00000000000..4c815e22a6d
--- /dev/null
+++ b/server/sonar-web/config/process-shim.js
@@ -0,0 +1,22 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+export function dummy_process_cwd() {
+ return '';
+}
diff --git a/server/sonar-web/config/utils.js b/server/sonar-web/config/utils.js
index 78ab4e12b86..a9fe52eafc0 100644
--- a/server/sonar-web/config/utils.js
+++ b/server/sonar-web/config/utils.js
@@ -17,66 +17,32 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-const cssLoader = () => ({
- loader: 'css-loader',
- options: {
- importLoaders: 1,
- modules: 'global',
- url: false
- }
-});
-
-const customProperties = {};
-const parseCustomProperties = theme => {
- Object.keys(theme).forEach(key => {
- if (typeof theme[key] === 'object') {
- parseCustomProperties(theme[key]);
- } else if (typeof theme[key] === 'string') {
- if (!customProperties[`--${key}`]) {
- customProperties[`--${key}`] = theme[key];
- } else {
- console.error(
- `Custom CSS property "${key}" already exists with value "${
- customProperties[`--${key}`]
- }".`
- );
- process.exit(1);
+/* eslint-disable no-console */
+function getCustomProperties() {
+ const customProperties = {};
+ const parseCustomProperties = theme => {
+ Object.keys(theme).forEach(key => {
+ if (typeof theme[key] === 'object') {
+ parseCustomProperties(theme[key]);
+ } else if (typeof theme[key] === 'string') {
+ if (!customProperties[`--${key}`]) {
+ customProperties[`--${key}`] = theme[key];
+ } else {
+ console.error(
+ `Custom CSS property "${key}" already exists with value "${
+ customProperties[`--${key}`]
+ }".`
+ );
+ process.exit(1);
+ }
}
- }
- });
-};
-
-parseCustomProperties(require('../src/main/js/app/theme'));
-
-const postcssLoader = production => ({
- loader: 'postcss-loader',
- options: {
- ident: 'postcss',
- plugins: () => [
- require('autoprefixer'),
- require('postcss-custom-properties')({ importFrom: { customProperties }, preserve: false }),
- require('postcss-calc'),
- ...(production ? [require('cssnano')({ calc: false, svgo: false })] : [])
- ]
- }
-});
-
-const minifyParams = ({ production }) =>
- production && {
- removeComments: true,
- collapseWhitespace: true,
- removeRedundantAttributes: true,
- useShortDoctype: true,
- removeEmptyAttributes: true,
- removeStyleLinkTypeAttributes: true,
- keepClosingSlash: true,
- minifyJS: true,
- minifyCSS: true,
- minifyURLs: true
+ });
};
+ parseCustomProperties(require('../src/main/js/app/theme'));
+
+ return customProperties;
+}
module.exports = {
- cssLoader,
- postcssLoader,
- minifyParams
+ getCustomProperties
};
diff --git a/server/sonar-web/config/webpack.config.js b/server/sonar-web/config/webpack.config.js
deleted file mode 100644
index dbaaac11938..00000000000
--- a/server/sonar-web/config/webpack.config.js
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2021 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-/* eslint-disable import/no-extraneous-dependencies, complexity */
-const path = require('path');
-const CleanWebpackPlugin = require('clean-webpack-plugin');
-const CopyWebpackPlugin = require('copy-webpack-plugin');
-const MiniCssExtractPlugin = require('mini-css-extract-plugin');
-const HtmlWebpackPlugin = require('html-webpack-plugin');
-const LodashPlugin = require('lodash-webpack-plugin');
-const webpack = require('webpack');
-const InterpolateHtmlPlugin = require('./InterpolateHtmlPlugin');
-const paths = require('./paths');
-const utils = require('./utils');
-
-module.exports = ({ production = true, release = false }) => {
- const timestamp = Date.now();
-
- const commonConfig = {
- mode: production ? 'production' : 'development',
- devtool: production && release ? 'source-map' : 'cheap-module-source-map',
- resolve: {
- // Add '.ts' and '.tsx' as resolvable extensions.
- extensions: ['.ts', '.tsx', '.js', '.json'],
- // import from 'Docs/foo.md' is rewritten to import from 'sonar-docs/src/foo.md'
- alias: {
- Docs: path.resolve(__dirname, '../../sonar-docs/src'),
- // d3-selection exports an event object, which requires live-binding.
- // In order to support this, we need to tell Webpack to NOT look into
- // the dist/ folder of this module, but in the src/ folder instead.
- // See https://github.com/d3/d3-selection#event
- 'd3-selection': path.resolve(__dirname, '../node_modules/d3-selection/src/index.js')
- }
- },
- optimization: {
- splitChunks: {
- chunks: 'all',
- automaticNameDelimiter: '-'
- },
- minimize: production && release
- }
- };
-
- const commonRules = [
- {
- // extract styles from 'app/' into separate file
- test: /\.css$/,
- include: path.resolve(__dirname, '../src/main/js/app/styles'),
- use: [
- production ? MiniCssExtractPlugin.loader : 'style-loader',
- utils.cssLoader(),
- utils.postcssLoader(production)
- ]
- },
- {
- // inline all other styles
- test: /\.css$/,
- exclude: path.resolve(__dirname, '../src/main/js/app/styles'),
- use: ['style-loader', utils.cssLoader(), utils.postcssLoader(production)]
- },
- {
- test: /\.md$/,
- use: 'raw-loader'
- },
- { test: require.resolve('react'), loader: 'expose-loader?React' },
- { test: require.resolve('react-dom'), loader: 'expose-loader?ReactDOM' },
- {
- test: /\.directory-loader\.js$/,
- loader: path.resolve(__dirname, 'documentation-loader/index.js')
- }
- ];
-
- const commonPlugins = [
- production &&
- new MiniCssExtractPlugin({
- filename: 'css/[name].[chunkhash:8].css',
- chunkFilename: 'css/[name].[chunkhash:8].chunk.css'
- }),
-
- new LodashPlugin({
- // keep these features
- // https://github.com/lodash/lodash-webpack-plugin#feature-sets
- shorthands: true,
- collections: true,
- exotics: true, // used to compare "exotic" values, like dates
- memoizing: true,
- flattening: true
- })
- ];
-
- return [
- Object.assign({ name: 'modern' }, commonConfig, {
- entry: [
- !production && require.resolve('react-dev-utils/webpackHotDevClient'),
- !production && require.resolve('react-error-overlay'),
- './src/main/js/app/utils/setPublicPath.js',
- './src/main/js/app/index.ts'
- ].filter(Boolean),
- output: {
- path: paths.appBuild,
- pathinfo: !production,
- filename: production ? 'js/[name].m.[chunkhash:8].js' : 'js/[name].js',
- chunkFilename: production ? 'js/[name].m.[chunkhash:8].chunk.js' : 'js/[name].chunk.js'
- },
- module: {
- rules: [
- {
- test: /(\.js$|\.ts(x?)$)/,
- exclude: /(node_modules|libs)/,
- use: [
- { loader: 'babel-loader' },
- {
- loader: 'ts-loader',
- options: { transpileOnly: true }
- }
- ]
- },
- ...commonRules
- ]
- },
- plugins: [
- production && new CleanWebpackPlugin(),
-
- production &&
- new CopyWebpackPlugin([
- {
- from: paths.docImages,
- to: paths.appBuild + '/images/embed-doc/images'
- }
- ]),
-
- production &&
- new CopyWebpackPlugin([
- {
- from: paths.appPublic,
- to: paths.appBuild,
- ignore: [paths.appHtml]
- }
- ]),
-
- ...commonPlugins,
-
- new HtmlWebpackPlugin({
- inject: false,
- template: paths.appHtml,
- minify: utils.minifyParams({ production: production && release }),
- timestamp
- }),
-
- // keep `InterpolateHtmlPlugin` after `HtmlWebpackPlugin`
- !production &&
- new InterpolateHtmlPlugin({
- WEB_CONTEXT: process.env.WEB_CONTEXT || '',
- SERVER_STATUS: process.env.SERVER_STATUS || 'UP',
- INSTANCE: process.env.INSTANCE || 'SonarQube',
- OFFICIAL: process.env.OFFICIAL || 'true'
- }),
-
- !production && new webpack.HotModuleReplacementPlugin()
- ].filter(Boolean),
- performance:
- production && release
- ? {
- // ignore source maps and documentation chunk
- assetFilter: assetFilename =>
- !assetFilename.endsWith('.map') && !assetFilename.startsWith('js/docs'),
- maxAssetSize: 400000,
- hints: 'error'
- }
- : undefined
- })
- ];
-};