diff options
author | Jeremy Davis <jeremy.davis@sonarsource.com> | 2021-09-17 16:29:12 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2021-09-30 20:03:00 +0000 |
commit | 18582f55e72704e61c331467e90de7b023d0b46c (patch) | |
tree | 98baf9a40895b0fedb19f5d739e55ea2592f385b /server/sonar-web/config | |
parent | 62b21006de51a5b15819e70f4a0943ab983d2b68 (diff) | |
download | sonarqube-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.js | 54 | ||||
-rw-r--r-- | server/sonar-web/config/esbuild-config.js | 57 | ||||
-rw-r--r-- | server/sonar-web/config/esbuild-documentation-plugin.js | 56 | ||||
-rw-r--r-- | server/sonar-web/config/process-shim.js | 22 | ||||
-rw-r--r-- | server/sonar-web/config/utils.js | 82 | ||||
-rw-r--r-- | server/sonar-web/config/webpack.config.js | 189 |
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 - }) - ]; -}; |