Преглед изворни кода

optimize js build (#1145)

tags/6.1-RC1
Stas Vilchik пре 7 година
родитељ
комит
2d5742c852

+ 19
- 8
server/sonar-web/.babelrc Прегледај датотеку

@@ -1,17 +1,28 @@
{
"presets": ["es2015", "stage-0", "react"],
"presets": ["es2015", "es2016", "react"],
"ignore": [
"**/libs/**"
],
"plugins": [
"transform-class-properties",
"transform-object-rest-spread"
],
"env": {
"hot": {
"plugins": [["react-transform", {
"transforms": [{
"transform": "react-transform-hmr",
"imports": ["react"],
"locals": ["module"]
"production": {
"plugins": [
"transform-react-constant-elements"
]
},
"development": {
"plugins": [
["react-transform", {
"transforms": [{
"transform": "react-transform-hmr",
"imports": ["react"],
"locals": ["module"]
}]
}]
}]]
]
}
}
}

+ 2
- 0
server/sonar-web/.eslintignore Прегледај датотеку

@@ -1,2 +1,4 @@
src/main/js/libs
tests
scripts
config

+ 1
- 1
server/sonar-web/.gitignore Прегледај датотеку

@@ -5,7 +5,7 @@ node/
node_modules/

# npm logs
npm-debug.log.*
npm-debug.log
npm.tar.gz

# build

+ 28
- 0
server/sonar-web/config/autoprefixer.js Прегледај датотеку

@@ -0,0 +1,28 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.
*/
module.exports = {
browsers: [
'last 3 Chrome versions',
'last 3 Firefox versions',
'Safari >= 8',
'Edge >= 12',
'IE 11'
]
};

+ 27
- 0
server/sonar-web/config/paths.js Прегледај датотеку

@@ -0,0 +1,27 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.
*/
var path = require('path');

var base = process.env.OUTPUT || path.join(__dirname, '../src/main/webapp');

module.exports = {
jsBuild: path.join(base, 'js/bundles'),
cssBuild: path.join(base, 'css')
};

server/sonar-web/webpack.config.js → server/sonar-web/config/webpack/webpack.config.base.js Прегледај датотеку

@@ -1,14 +1,9 @@
/* eslint no-var: 0 */
/* eslint object-shorthand: 0 */
/* jscs:disable requireEnhancedObjectLiterals */
var path = require('path');
var webpack = require('webpack');
var autoprefixer = require('autoprefixer');

var autoprefixerOptions = require('./gulp/styles').autoprefixerOptions;

var baseOutput = process.env.OUTPUT || path.join(__dirname, 'src/main/webapp');
var output = path.join(baseOutput, 'js/bundles');
var autoprefixerOptions = require('./../autoprefixer');
var paths = require('./../paths');

module.exports = {
entry: {
@@ -59,21 +54,21 @@ module.exports = {
'widgets': './src/main/js/widgets/widgets.js'
},
output: {
path: output,
path: paths.jsBuild,
filename: '[name].js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js')
],
resolve: {
root: path.join(__dirname, 'src/main/js')
root: path.join(__dirname, '../../src/main/js')
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
exclude: /(node_modules|libs)/
exclude: /(node_modules|libs)/,
},
{
test: /(blueimp-md5|numeral)/,
@@ -81,9 +76,9 @@ module.exports = {
},
{
test: /\.hbs$/,
loader: 'handlebars-loader',
loader: 'handlebars',
query: {
helperDirs: path.join(__dirname, 'src/main/js/helpers/handlebars')
helperDirs: path.join(__dirname, '../../src/main/js/helpers/handlebars')
}
},
{

server/sonar-web/webpack.config.dev.js → server/sonar-web/config/webpack/webpack.config.dev.js Прегледај датотеку

@@ -17,15 +17,14 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* eslint no-var: 0 */
var webpack = require('webpack');

var config = require('./webpack.config');
var config = require('./webpack.config.base');

config.devtool = 'cheap-module-eval-source-map';
config.output.publicPath = '/js/bundles/';
config.entry.vendor.unshift('webpack-hot-middleware/client');
config.plugins = [].concat(config.plugins, [
new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"development"' }),
new webpack.HotModuleReplacementPlugin()
]);


server/sonar-web/devServer.js → server/sonar-web/config/webpack/webpack.config.fast.js Прегледај датотеку

@@ -17,40 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* eslint no-var: 0 */
/* eslint no-console: 0 */
/* eslint object-shorthand: 0 */
/* jscs:disable requireEnhancedObjectLiterals */
var url = require('url');
var express = require('express');
var proxy = require('express-http-proxy');
var webpack = require('webpack');
var config = require('./webpack.config.dev');
var config = require('./webpack.config.base');

var app = express();
var compiler = webpack(config);
config.plugins = [].concat(config.plugins, [
new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"development"' }),
]);

var PORT = process.env.PORT || 8080;
var API_HOST = process.env.API_HOST || 'http://localhost:9000';

app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true,
publicPath: config.output.publicPath
}));

app.use(require('webpack-hot-middleware')(compiler));

app.all('*', proxy(API_HOST, {
forwardPath: function (req) {
return url.parse(req.url).path;
}
}));

app.listen(PORT, 'localhost', function (err) {
if (err) {
console.log(err);
return;
}

console.log('Listening at http://localhost:' + PORT);
});
module.exports = config;

+ 34
- 0
server/sonar-web/config/webpack/webpack.config.prod.js Прегледај датотеку

@@ -0,0 +1,34 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.
*/
var webpack = require('webpack');
var config = require('./webpack.config.base');

config.plugins = [].concat(config.plugins, [
new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"production"' }),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: { screw_ie8: true, warnings: false },
mangle: { screw_ie8: true },
output: { screw_ie8: true, comments: false }
})
]);

module.exports = config;

+ 0
- 34
server/sonar-web/gulp/styles.js Прегледај датотеку

@@ -1,34 +0,0 @@
var path = require('path');

var gulp = require('gulp');
var gulpif = require('gulp-if');
var less = require('gulp-less');
var nano = require('gulp-cssnano');
var autoprefixer = require('gulp-autoprefixer');


var nanoOptions = {
zindex: false,
discardComments: { removeAll: true }
};

var autoprefixerOptions = {
browsers: [
'last 3 Chrome versions',
'last 3 Firefox versions',
'Safari >= 8',
'Edge >= 12',
'IE 11'
]
};


module.exports.autoprefixerOptions = autoprefixerOptions;

module.exports.styles = function (output, production) {
return gulp.src(['src/main/less/sonar.less'])
.pipe(less())
.pipe(autoprefixer(autoprefixerOptions))
.pipe(gulpif(production, nano(nanoOptions)))
.pipe(gulp.dest(path.join(output, 'css')));
};

+ 26
- 63
server/sonar-web/gulpfile.js Прегледај датотеку

@@ -1,75 +1,38 @@
var path = require('path');

/* eslint no-var: 0 */
var del = require('del');
var gulp = require('gulp');
var gutil = require('gulp-util');
var webpack = require('webpack');

var argv = require('yargs').argv;
var output = argv.output || path.join(__dirname, 'src/main/webapp');

var styles = require('./gulp/styles').styles;
var webpackConfig = require('./webpack.config.js');
webpackConfig.output.path = path.join(output, 'js/bundles');


// Clean
var gulpif = require('gulp-if');
var less = require('gulp-less');
var nano = require('gulp-cssnano');
var autoprefixer = require('gulp-autoprefixer');
var paths = require('./config/paths');
var autoprefixerOptions = require('./config/autoprefixer');

var nanoOptions = {
zindex: false,
discardComments: { removeAll: true }
};

function styles (output, production) {
return gulp.src(['src/main/less/sonar.less'])
.pipe(less())
.pipe(autoprefixer(autoprefixerOptions))
.pipe(gulpif(production, nano(nanoOptions)))
.pipe(gulp.dest(output));
}

gulp.task('clean', function (done) {
del([
path.join(output, 'js'),
path.join(output, 'css')
], done);
del(paths.cssBuild, done);
});


// Styles

gulp.task('styles:prod', function () {
return styles(output, true);
return styles(paths.cssBuild, true);
});

gulp.task('styles:dev', function () {
return styles(output, false, true);
});


// Webpack

gulp.task('webpack:prod', function (callback) {
var webpackProdConfig = Object.create(webpackConfig);
webpackProdConfig.plugins = webpackProdConfig.plugins.concat(
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production'),
'OUTPUT': output
}
}),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin()
);

webpack(webpackProdConfig, function (err) {
if (err) {
throw new gutil.PluginError('webpack:prod', err);
}
callback();
});
return styles(paths.cssBuild, false);
});

gulp.task('webpack:dev', function (callback) {
// run webpack
webpack(webpackConfig, function (err) {
if (err) {
throw new gutil.PluginError('webpack:dev', err);
}
callback();
});
});


// Tasks

gulp.task('build', ['clean', 'styles:prod', 'webpack:prod']);
gulp.task('build:dev', ['clean', 'styles:dev', 'webpack:dev']);
gulp.task('default', ['build']);
gulp.task('default', ['clean', 'styles:prod']);
gulp.task('build', ['clean', 'styles:prod']);
gulp.task('build-fast', ['clean', 'styles:dev']);

+ 18
- 10
server/sonar-web/package.json Прегледај датотеку

@@ -7,21 +7,27 @@
"devDependencies": {
"autoprefixer": "6.2.2",
"babel-cli": "6.3.17",
"babel-core": "6.3.17",
"babel-core": "6.13.2",
"babel-eslint": "^6.0.4",
"babel-loader": "6.2.0",
"babel-loader": "6.2.4",
"babel-plugin-react-transform": "2.0.2",
"babel-plugin-transform-class-properties": "6.11.5",
"babel-plugin-transform-object-rest-spread": "6.8.0",
"babel-plugin-transform-react-constant-elements": "6.9.1",
"babel-polyfill": "6.3.14",
"babel-preset-es2015": "6.3.13",
"babel-preset-react": "6.3.13",
"babel-preset-es2015": "6.13.2",
"babel-preset-es2016": "6.11.3",
"babel-preset-react": "6.11.1",
"babel-preset-stage-0": "6.3.13",
"babel-register": "6.3.13",
"backbone": "1.2.3",
"backbone.marionette": "2.4.3",
"blueimp-md5": "1.1.1",
"chai": "3.3.0",
"chalk": "1.1.3",
"classnames": "2.2.0",
"clipboard": "1.5.5",
"cross-env": "^2.0.0",
"css-loader": "0.23.1",
"d3": "3.5.6",
"del": "2.0.2",
@@ -53,6 +59,7 @@
"mockery": "1.7.0",
"moment": "2.10.6",
"numeral": "1.5.3",
"nyc": "^8.1.0",
"postcss-loader": "0.8.0",
"react": "15.0.1",
"react-addons-perf": "15.0.1",
@@ -69,6 +76,7 @@
"redux-logger": "2.2.1",
"redux-simple-router": "1.0.1",
"redux-thunk": "1.0.2",
"rimraf": "2.5.4",
"script-loader": "0.6.1",
"sinon": "1.15.4",
"sinon-chai": "2.8.0",
@@ -83,12 +91,12 @@
"yargs": "3.27.0"
},
"scripts": {
"build-fast": "gulp build:dev",
"build": "gulp build",
"test": "mocha --opts tests/mocha.opts src/main/js/**/__tests__/**/*",
"coverage": "nyc --exclude tests,**/__tests__/** mocha --opts tests/mocha.opts src/main/js/**/__tests__/**/* && nyc report --reporter lcov --report-dir target/coverage",
"lint": "eslint src/main/js",
"dev": "NODE_ENV=hot node devServer"
"start": "node ./scripts/start.js",
"build-fast": "node ./scripts/build.js --fast && gulp build-fast",
"build": "node ./scripts/build.js && gulp build",
"test": "cross-env NODE_ENV=test mocha --opts tests/mocha.opts src/main/js/**/__tests__/**/*",
"coverage": "cross-env NODE_ENV=test nyc mocha --opts tests/mocha.opts src/main/js/**/__tests__/**/* && nyc report --reporter lcov --report-dir target/coverage",
"lint": "eslint src/main/js"
},
"engines": {
"node": ">=4"

+ 62
- 0
server/sonar-web/scripts/build.js Прегледај датотеку

@@ -0,0 +1,62 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.
*/
process.env.NODE_ENV = 'production';

var chalk = require('chalk');
var fs = require('fs');
var path = require('path');
var rimrafSync = require('rimraf').sync;
var webpack = require('webpack');
var paths = require('../config/paths');

var isFastBuild = process.argv.some(arg => arg.indexOf('--fast') > -1);

var config = isFastBuild ?
require('../config/webpack/webpack.config.fast') :
require('../config/webpack/webpack.config.prod');

// 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 directory...'));
console.log(paths.jsBuild + '/*');
console.log();
rimrafSync(paths.jsBuild + '/*');

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

webpack(config).run(function (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);
}

console.log(chalk.green.bold('Compiled successfully!'));

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

+ 158
- 0
server/sonar-web/scripts/start.js Прегледај датотеку

@@ -0,0 +1,158 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact 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.
*/
process.env.NODE_ENV = 'development';

var url = require('url');
var express = require('express');
var proxy = require('express-http-proxy');
var webpack = require('webpack');
var chalk = require('chalk');
var config = require('../config/webpack/webpack.config.dev.js');

var app = express();

var DEFAULT_PORT = process.env.PORT || 8080;
var API_HOST = process.env.API_HOST || 'http://localhost:9000';

var compiler;

var friendlySyntaxErrorLabel = 'Syntax error:';

function isLikelyASyntaxError (message) {
return message.indexOf(friendlySyntaxErrorLabel) !== -1;
}

// This is a little hacky.
// It would be easier if webpack provided a rich error object.

function formatMessage (message) {
return message
// Make some common errors shorter:
.replace(
// Babel syntax error
'Module build failed: SyntaxError:',
friendlySyntaxErrorLabel
)
.replace(
// Webpack file not found error
/Module not found: Error: Cannot resolve 'file' or 'directory'/,
'Module not found:'
)
// Internal stacks are generally useless so we strip them
.replace(/^\s*at\s.*:\d+:\d+[\s\)]*\n/gm, '') // at ... ...:x:y
// Webpack loader names obscure CSS filenames
.replace('./~/css-loader!./~/postcss-loader!', '');
}

function setupCompiler () {
compiler = webpack(config);

compiler.plugin('invalid', function () {
console.log(chalk.cyan.bold('Compiling...'));
});

compiler.plugin('done', function (stats) {
var hasErrors = stats.hasErrors();
var hasWarnings = stats.hasWarnings();
if (!hasErrors && !hasWarnings) {
console.log(chalk.green.bold('Compiled successfully!'));
return;
}

var json = stats.toJson();
var formattedErrors = json.errors.map(message =>
'Error in ' + formatMessage(message)
);
var formattedWarnings = json.warnings.map(message =>
'Warning in ' + formatMessage(message)
);

if (hasErrors) {
console.log(chalk.red.bold('Failed to compile:'));
console.log();
if (formattedErrors.some(isLikelyASyntaxError)) {
// If there are any syntax errors, show just them.
// This prevents a confusing ESLint parsing error
// preceding a much more useful Babel syntax error.
formattedErrors = formattedErrors.filter(isLikelyASyntaxError);
}
formattedErrors.forEach(message => {
console.log(message);
console.log();
});
// If errors exist, ignore warnings.
return;
}

if (hasWarnings) {
console.log(chalk.yellow('Compiled with warnings.'));
console.log();
formattedWarnings.forEach(message => {
console.log(message);
console.log();
});

console.log('You may use special comments to disable some warnings.');
console.log('Use ' + chalk.yellow(
'// eslint-disable-next-line') + ' to ignore the next line.');
console.log('Use ' + chalk.yellow(
'/* eslint-disable */') + ' to ignore all warnings in a file.');
}
});
}

function runDevServer (port) {
app.use(require('webpack-dev-middleware')(compiler, {
noInfo: true,
quiet: true,
publicPath: config.output.publicPath
}));

app.use(require('webpack-hot-middleware')(compiler, {
noInfo: true,
quiet: true
}));

app.all('*', proxy(API_HOST, {
forwardPath: function (req) {
return url.parse(req.url).path;
}
}));

app.listen(port, 'localhost', function (err) {
if (err) {
console.log(err);
return;
}

console.log(chalk.green.bold(
'The app is running at http://localhost:' + port + '/'));
console.log(chalk.cyan.bold('Compiling...'));
console.log();
});
}

function run (port) {
setupCompiler();
runDevServer(port);
}

run(DEFAULT_PORT);


Loading…
Откажи
Сачувај