Browse Source

SONAR-8448 generate index.html during the build

tags/6.3-RC1
Stas Vilchik 7 years ago
parent
commit
673b03c6f6

+ 1
- 0
server/sonar-web/.gitignore View File

build/ build/
src/main/webapp/js/ src/main/webapp/js/
src/main/webapp/css/ src/main/webapp/css/
src/main/webapp/index.html
src/main/webapp/WEB-INF/lib/*.jar src/main/webapp/WEB-INF/lib/*.jar


# tests # tests

+ 5
- 1
server/sonar-web/config/paths.js View File



// config after eject: we're in ./config/ // config after eject: we're in ./config/
module.exports = { module.exports = {
appBuild: resolveApp('src/main/webapp/js/bundles'),
appBuild: resolveApp('src/main/webapp'),
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
appPackageJson: resolveApp('package.json'), appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src/main/js'), appSrc: resolveApp('src/main/js'),
jsBuild: resolveApp('src/main/webapp/js'),
cssBuild: resolveApp('src/main/webapp/css'), cssBuild: resolveApp('src/main/webapp/css'),
htmlBuild: resolveApp('src/main/webapp/index.html'),
appNodeModules: resolveApp('node_modules'), appNodeModules: resolveApp('node_modules'),
ownNodeModules: resolveApp('node_modules'), ownNodeModules: resolveApp('node_modules'),
nodePaths: nodePaths nodePaths: nodePaths

+ 3
- 12
server/sonar-web/config/webpack/webpack.config.base.js View File

/* eslint no-var: 0 */
var path = require('path'); var path = require('path');
var autoprefixer = require('autoprefixer'); var autoprefixer = require('autoprefixer');
var webpack = require('webpack'); var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin'); var ExtractTextPlugin = require('extract-text-webpack-plugin');
var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
var url = require('url');
var paths = require('../paths'); var paths = require('../paths');
var autoprefixerOptions = require('../autoprefixer'); var autoprefixerOptions = require('../autoprefixer');




'sonar': './src/main/js/libs/sonar.js', 'sonar': './src/main/js/libs/sonar.js',


'app': './src/main/js/app/index.js',

// not unique url
'source-viewer': './src/main/js/apps/source-viewer/app.js'
'app': './src/main/js/app/index.js'
}, },
output: { output: {
path: paths.appBuild, path: paths.appBuild,
filename: '[name].js'
filename: 'js/[name].[chunkhash:8].js',
chunkFilename: 'js/[name].[chunkhash:8].chunk.js',
}, },
plugins: [
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js'),
new ExtractTextPlugin('../../css/sonar.css', { allChunks: true })
],
resolve: { resolve: {
// This allows you to set a fallback for where Webpack should look for modules. // This allows you to set a fallback for where Webpack should look for modules.
// We read `NODE_PATH` environment variable in `paths.js` and pass paths here. // We read `NODE_PATH` environment variable in `paths.js` and pass paths here.

+ 29
- 6
server/sonar-web/config/webpack/webpack.config.dev.js View File

* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
var webpack = require('webpack'); var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); var CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); var WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
var paths = require('../paths'); var paths = require('../paths');
var config = require('./webpack.config.base'); var config = require('./webpack.config.base');
var getClientEnvironment = require('../env'); var getClientEnvironment = require('../env');


// Webpack uses `publicPath` to determine where the app is being served from.
var publicPath = '/js/bundles/';

// Get environment variables to inject into our app.
var publicPath = '';
var webContext = '';
var env = getClientEnvironment(); var env = getClientEnvironment();


// This makes the bundle appear split into separate modules in the devtools. // This makes the bundle appear split into separate modules in the devtools.


// This is the URL that app is served from. // This is the URL that app is served from.
config.output.publicPath = publicPath; config.output.publicPath = publicPath;
config.output.filename = 'js/[name].js';
config.output.chunkFilename = 'js/[name].chunk.js';

config.plugins = [
new webpack.optimize.CommonsChunkPlugin('vendor', 'js/vendor.js'),

new ExtractTextPlugin('css/sonar.css', { allChunks: true }),

// Makes the web context available as %WEB_CONTEXT% in index.html, e.g.:
// <link rel="shortcut icon" href="%WEB_CONTEXT%/favicon.ico">
// In development, this will be an empty string.
new InterpolateHtmlPlugin({
WEB_CONTEXT: webContext
}),

// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: false,
template: paths.appHtml,
}),


config.plugins = [].concat(config.plugins, [
// Makes some environment variables available to the JS code, for example: // Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`. // if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
new webpack.DefinePlugin(env), new webpack.DefinePlugin(env),

// This is necessary to emit hot updates (currently CSS only): // This is necessary to emit hot updates (currently CSS only):
new webpack.HotModuleReplacementPlugin(), new webpack.HotModuleReplacementPlugin(),

// Watcher doesn't work well if you mistype casing in a path so we use // Watcher doesn't work well if you mistype casing in a path so we use
// a plugin that prints an error when you attempt to do this. // a plugin that prints an error when you attempt to do this.
// See https://github.com/facebookincubator/create-react-app/issues/240 // See https://github.com/facebookincubator/create-react-app/issues/240
new CaseSensitivePathsPlugin(), new CaseSensitivePathsPlugin(),

// If you require a missing module and then `npm install` it, you still have // If you require a missing module and then `npm install` it, you still have
// to restart the development server for Webpack to discover it. This plugin // to restart the development server for Webpack to discover it. This plugin
// makes the discovery automatic so you don't have to restart. // makes the discovery automatic so you don't have to restart.
// See https://github.com/facebookincubator/create-react-app/issues/186 // See https://github.com/facebookincubator/create-react-app/issues/186
new WatchMissingNodeModulesPlugin(paths.appNodeModules) new WatchMissingNodeModulesPlugin(paths.appNodeModules)
]);
];


module.exports = config; module.exports = config;

+ 22
- 0
server/sonar-web/config/webpack/webpack.config.fast.js View File

* along with this program; if not, write to the Free Software Foundation, * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var config = require('./webpack.config.base'); var config = require('./webpack.config.base');
var getClientEnvironment = require('../env');
var paths = require('../paths');

// Get environment variables to inject into our app.
var env = getClientEnvironment();


// disable eslint loader // disable eslint loader
config.module.preLoaders = []; config.module.preLoaders = [];


// Don't attempt to continue if there are any errors.
config.bail = true;

config.plugins = [
new webpack.optimize.CommonsChunkPlugin('vendor', 'js/vendor.[chunkhash:8].js'),

new ExtractTextPlugin('css/sonar.[chunkhash:8].css', { allChunks: true }),

new HtmlWebpackPlugin({
inject: false,
template: paths.appHtml
})
];

module.exports = config; module.exports = config;

+ 30
- 3
server/sonar-web/config/webpack/webpack.config.prod.js View File

* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
var webpack = require('webpack'); var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var config = require('./webpack.config.base'); var config = require('./webpack.config.base');
var getClientEnvironment = require('../env'); var getClientEnvironment = require('../env');
var paths = require('../paths');


// Get environment variables to inject into our app. // Get environment variables to inject into our app.
var env = getClientEnvironment(); var env = getClientEnvironment();
// Don't attempt to continue if there are any errors. // Don't attempt to continue if there are any errors.
config.bail = true; config.bail = true;


config.plugins = [].concat(config.plugins, [
config.plugins = [
new webpack.optimize.CommonsChunkPlugin('vendor', 'js/vendor.[chunkhash:8].js'),

new ExtractTextPlugin('css/sonar.[chunkhash:8].css', { allChunks: true }),

new HtmlWebpackPlugin({
inject: false,
template: paths.appHtml,
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true
}
}),

// Makes some environment variables available to the JS code, for example: // Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`. // if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
// It is absolutely essential that NODE_ENV was set to production here. // It is absolutely essential that NODE_ENV was set to production here.
// Otherwise React will be compiled in the very slow development mode. // Otherwise React will be compiled in the very slow development mode.
new webpack.DefinePlugin(env), new webpack.DefinePlugin(env),

// This helps ensure the builds are consistent if source hasn't changed: // This helps ensure the builds are consistent if source hasn't changed:
new webpack.optimize.OccurrenceOrderPlugin(), new webpack.optimize.OccurrenceOrderPlugin(),

// Try to dedupe duplicated modules, if any: // Try to dedupe duplicated modules, if any:
new webpack.optimize.DedupePlugin(), new webpack.optimize.DedupePlugin(),

// Minify the code. // Minify the code.
new webpack.optimize.UglifyJsPlugin({ new webpack.optimize.UglifyJsPlugin({
compress: { compress: {
comments: false, comments: false,
screw_ie8: true screw_ie8: true
} }
}),
]);
})
];


module.exports = config; module.exports = config;

+ 1
- 0
server/sonar-web/package.json View File

"handlebars": "2.0.0", "handlebars": "2.0.0",
"handlebars-loader": "1.1.4", "handlebars-loader": "1.1.4",
"history": "2.0.0", "history": "2.0.0",
"html-webpack-plugin": "2.24.1",
"imports-loader": "0.6.5", "imports-loader": "0.6.5",
"jest": "15.1.1", "jest": "15.1.1",
"jquery": "2.2.0", "jquery": "2.2.0",

+ 18
- 0
server/sonar-web/public/index.html View File

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link href="%WEB_CONTEXT%/favicon.ico" rel="shortcut icon" type="image/x-icon">
<% for (var css in htmlWebpackPlugin.files.css) { %>
<link href="%WEB_CONTEXT%/<%= htmlWebpackPlugin.files.css[css] %>" rel="stylesheet">
<% } %>
<title>SonarQube</title>
</head>
<body>
<div id="content"></div>
<script>window.baseUrl = '%WEB_CONTEXT%';</script>
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
<script src="%WEB_CONTEXT%/<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"></script>
<% } %>
</body>
</html>

+ 56
- 37
server/sonar-web/scripts/build.js View File

process.env.NODE_ENV = 'production'; process.env.NODE_ENV = 'production';


var chalk = require('chalk'); var chalk = require('chalk');
var fs = require('fs');
var fs = require('fs-extra');
var path = require('path'); var path = require('path');
var rimrafSync = require('rimraf').sync; var rimrafSync = require('rimraf').sync;
var webpack = require('webpack'); var webpack = require('webpack');
require('../config/webpack/webpack.config.fast') : require('../config/webpack/webpack.config.fast') :
require('../config/webpack/webpack.config.prod'); require('../config/webpack/webpack.config.prod');


function clean () {
// Remove all content but keep the directory so that // Remove all content but keep the directory so that
// if you're in it, you don't end up in Trash // if you're in it, you don't end up in Trash
console.log(chalk.cyan.bold('Cleaning output directories...'));
console.log(chalk.cyan.bold('Cleaning output directories and files...'));


console.log(paths.appBuild + '/*');
rimrafSync(paths.appBuild + '/*');
console.log(paths.jsBuild + '/*');
rimrafSync(paths.jsBuild + '/*');


console.log(paths.cssBuild + '/*');
rimrafSync(paths.cssBuild + '/*');
console.log(paths.cssBuild + '/*');
rimrafSync(paths.cssBuild + '/*');


console.log();
console.log(paths.htmlBuild);
rimrafSync(paths.htmlBuild);


if (isFastBuild) {
console.log(chalk.magenta.bold('Running fast build...'));
} else {
console.log(chalk.cyan.bold('Creating optimized production build...'));
console.log();
} }
console.log();


webpack(config, (err, stats) => {
if (err) {
console.log(chalk.red.bold('Failed to create a production build!'));
console.log(chalk.red(err.message || err));
process.exit(1);
function build () {
if (isFastBuild) {
console.log(chalk.magenta.bold('Running fast build...'));
} else {
console.log(chalk.cyan.bold('Creating optimized production build...'));
} }
console.log();


if (stats.compilation.errors && stats.compilation.errors.length) {
console.log(chalk.red.bold('Failed to create a production build!'));
stats.compilation.errors.forEach(err => console.log(chalk.red(err.message || err)));
process.exit(1);
}
webpack(config, (err, stats) => {
if (err) {
console.log(chalk.red.bold('Failed to create a production build!'));
console.log(chalk.red(err.message || err));
process.exit(1);
}

if (stats.compilation.errors && stats.compilation.errors.length) {
console.log(chalk.red.bold('Failed to create a production build!'));
stats.compilation.errors.forEach(err => console.log(chalk.red(err.message || err)));
process.exit(1);
}

var jsonStats = stats.toJson();

console.log('Assets:');
var assets = jsonStats.assets.slice();
assets.sort((a, b) => b.size - a.size);
assets.forEach(asset => {
var sizeLabel = formatSize(asset.size);
var leftPadding = ' '.repeat(Math.max(0, 8 - sizeLabel.length));
sizeLabel = leftPadding + sizeLabel;
console.log('', chalk.yellow(sizeLabel), asset.name);
});
console.log();


var jsonStats = stats.toJson();
var seconds = jsonStats.time / 1000;
console.log('Duration: ' + seconds.toFixed(2) + 's');
console.log();


console.log('Assets:');
var assets = jsonStats.assets.slice();
assets.sort((a, b) => b.size - a.size);
assets.forEach(asset => {
var sizeLabel = formatSize(asset.size);
var leftPadding = ' '.repeat(8 - sizeLabel.length);
sizeLabel = leftPadding + sizeLabel;
console.log('', chalk.yellow(sizeLabel), asset.name);
console.log(chalk.green.bold('Compiled successfully!'));
}); });
console.log();
}

function copyPublicFolder () {
fs.copySync(paths.appPublic, paths.appBuild, {
dereference: true,
filter: file => file !== paths.appHtml
});
}


var seconds = jsonStats.time / 1000;
console.log('Duration: ' + seconds.toFixed(2) + 's');
console.log();


console.log(chalk.green.bold('Compiled successfully!'));
});
clean();
build();
copyPublicFolder();

+ 3
- 14
server/sonar-web/scripts/start.js View File



var PROXY_URL = 'http://localhost:9000'; var PROXY_URL = 'http://localhost:9000';


// You can safely remove this after ejecting.
// We only use this block for testing of Create React App itself:
var isSmokeTest = process.argv.some(arg => arg.indexOf('--smoke-test') > -1);
if (isSmokeTest) {
handleCompile = function (err, stats) {
if (err || stats.hasErrors() || stats.hasWarnings()) {
process.exit(1);
} else {
process.exit(0);
}
};
}

function setupCompiler (host, port, protocol) { function setupCompiler (host, port, protocol) {
// "Compiler" is a low-level interface to Webpack. // "Compiler" is a low-level interface to Webpack.
// It lets us listen to some events and provide our own custom messages. // It lets us listen to some events and provide our own custom messages.
// - /*.hot-update.json (WebpackDevServer uses this too for hot reloading) // - /*.hot-update.json (WebpackDevServer uses this too for hot reloading)
// - /sockjs-node/* (WebpackDevServer uses this for hot reloading) // - /sockjs-node/* (WebpackDevServer uses this for hot reloading)
// Tip: use https://jex.im/regulex/ to visualize the regex // Tip: use https://jex.im/regulex/ to visualize the regex
var mayProxy = /^(?!\/(.*\.hot-update\.json$|sockjs-node\/)).*$/;
var mayProxy = /^(?!\/(index\.html$|.*\.hot-update\.json$|sockjs-node\/)).*$/;
devServer.use(mayProxy, devServer.use(mayProxy,
// Pass the scope regex both to Express and to the middleware for proxying // Pass the scope regex both to Express and to the middleware for proxying
// of both HTTP and WebSockets to work without false positives. // of both HTTP and WebSockets to work without false positives.


function runDevServer (host, port, protocol) { function runDevServer (host, port, protocol) {
var devServer = new WebpackDevServer(compiler, { var devServer = new WebpackDevServer(compiler, {
// Enable gzip compression of generated files.
compress: true,
// Silence WebpackDevServer's own logs since they're generally not useful. // Silence WebpackDevServer's own logs since they're generally not useful.
// It will still show compile warnings and errors with this setting. // It will still show compile warnings and errors with this setting.
clientLogLevel: 'none', clientLogLevel: 'none',

Loading…
Cancel
Save