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

@@ -12,6 +12,7 @@ npm.tar.gz
build/
src/main/webapp/js/
src/main/webapp/css/
src/main/webapp/index.html
src/main/webapp/WEB-INF/lib/*.jar

# tests

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

@@ -45,10 +45,14 @@ var nodePaths = (process.env.NODE_PATH || '')

// config after eject: we're in ./config/
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'),
appSrc: resolveApp('src/main/js'),
jsBuild: resolveApp('src/main/webapp/js'),
cssBuild: resolveApp('src/main/webapp/css'),
htmlBuild: resolveApp('src/main/webapp/index.html'),
appNodeModules: resolveApp('node_modules'),
ownNodeModules: resolveApp('node_modules'),
nodePaths: nodePaths

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

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

@@ -25,19 +22,13 @@ module.exports = {

'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: {
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: {
// 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.

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

@@ -18,16 +18,17 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
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 WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
var paths = require('../paths');
var config = require('./webpack.config.base');
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();

// This makes the bundle appear split into separate modules in the devtools.
@@ -53,22 +54,44 @@ config.output.pathinfo = true;

// This is the URL that app is served from.
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:
// if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
new webpack.DefinePlugin(env),

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

// 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.
// See https://github.com/facebookincubator/create-react-app/issues/240
new CaseSensitivePathsPlugin(),

// 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
// makes the discovery automatic so you don't have to restart.
// See https://github.com/facebookincubator/create-react-app/issues/186
new WatchMissingNodeModulesPlugin(paths.appNodeModules)
]);
];

module.exports = config;

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

@@ -17,9 +17,31 @@
* along with this program; if not, write to the Free Software Foundation,
* 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 getClientEnvironment = require('../env');
var paths = require('../paths');

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

// disable eslint loader
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;

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

@@ -18,8 +18,11 @@
* 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 getClientEnvironment = require('../env');
var paths = require('../paths');

// Get environment variables to inject into our app.
var env = getClientEnvironment();
@@ -33,16 +36,40 @@ if (env['process.env.NODE_ENV'] !== '"production"') {
// Don't attempt to continue if there are any errors.
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:
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
// It is absolutely essential that NODE_ENV was set to production here.
// Otherwise React will be compiled in the very slow development mode.
new webpack.DefinePlugin(env),

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

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

// Minify the code.
new webpack.optimize.UglifyJsPlugin({
compress: {
@@ -56,7 +83,7 @@ config.plugins = [].concat(config.plugins, [
comments: false,
screw_ie8: true
}
}),
]);
})
];

module.exports = config;

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

@@ -48,6 +48,7 @@
"handlebars": "2.0.0",
"handlebars-loader": "1.1.4",
"history": "2.0.0",
"html-webpack-plugin": "2.24.1",
"imports-loader": "0.6.5",
"jest": "15.1.1",
"jquery": "2.2.0",

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

@@ -0,0 +1,18 @@
<!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

@@ -20,7 +20,7 @@
process.env.NODE_ENV = 'production';

var chalk = require('chalk');
var fs = require('fs');
var fs = require('fs-extra');
var path = require('path');
var rimrafSync = require('rimraf').sync;
var webpack = require('webpack');
@@ -33,54 +33,73 @@ var config = isFastBuild ?
require('../config/webpack/webpack.config.fast') :
require('../config/webpack/webpack.config.prod');

function clean () {
// Remove all content but keep the directory so that
// 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

@@ -45,19 +45,6 @@ var handleCompile;

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) {
// "Compiler" is a low-level interface to Webpack.
// It lets us listen to some events and provide our own custom messages.
@@ -181,7 +168,7 @@ function addMiddleware (devServer) {
// - /*.hot-update.json (WebpackDevServer uses this too for hot reloading)
// - /sockjs-node/* (WebpackDevServer uses this for hot reloading)
// 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,
// Pass the scope regex both to Express and to the middleware for proxying
// of both HTTP and WebSockets to work without false positives.
@@ -201,6 +188,8 @@ function addMiddleware (devServer) {

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

Loading…
Cancel
Save