mirror of
https://github.com/grafana/grafana.git
synced 2025-08-02 23:53:10 +08:00
Webpack (#9391)
* webpack poc, this is not going to work for plugins, dam * tech: webpack and systemjs for plugins starting to work * tech: webpack and systemjs combo starting to work * tech: webpack + karma tests progress * tech: webpack + karma progress * tech: working on tests * tech: webpack * tech: webpack + karma, all tests pass * tech: webpack + karma, all tests pass * tech: webpack all tests pass * webpack: getting closer * tech: webpack progress * webpack: further build refinements * webpack: ng annotate fixes * webpack: optimized build fix * tech: minor fix for elasticsearch * tech: webpack + ace editor * tech: restored lodash move mixin compatability * tech: added enzyme react test and upgraded to react v16 * tech: package version fix * tech: added testdata to built in bundle * webpack: sass progress * tech: prod & dev build is working for the sass * tech: clean up unused grunt stuff and moved to scripts folder * tech: added vendor and manifest chunks, updated readme and docs * tech: webpack finishing touches
This commit is contained in:
13
scripts/grunt/build_task.js
Normal file
13
scripts/grunt/build_task.js
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
module.exports = function(grunt) {
|
||||
"use strict";
|
||||
|
||||
// Concat and Minify the src directory into dist
|
||||
grunt.registerTask('build', [
|
||||
'clean:release',
|
||||
'clean:build',
|
||||
'phantomjs',
|
||||
'webpack:prod',
|
||||
]);
|
||||
|
||||
};
|
34
scripts/grunt/default_task.js
Normal file
34
scripts/grunt/default_task.js
Normal file
@ -0,0 +1,34 @@
|
||||
// Lint and build CSS
|
||||
module.exports = function(grunt) {
|
||||
'use strict';
|
||||
|
||||
grunt.registerTask('default', [
|
||||
'clean:build',
|
||||
'phantomjs',
|
||||
'webpack:dev',
|
||||
]);
|
||||
|
||||
grunt.registerTask('test', [
|
||||
'clean:build',
|
||||
'jscs',
|
||||
'jshint',
|
||||
'sasslint',
|
||||
'exec:tslint',
|
||||
'karma:test',
|
||||
'no-only-tests'
|
||||
]);
|
||||
|
||||
grunt.registerTask('no-only-tests', function() {
|
||||
var files = grunt.file.expand('public/**/*_specs\.ts', 'public/**/*_specs\.js');
|
||||
|
||||
files.forEach(function(spec) {
|
||||
var rows = grunt.file.read(spec).split('\n');
|
||||
rows.forEach(function(row) {
|
||||
if (row.indexOf('.only(') > 0) {
|
||||
grunt.log.errorlns(row);
|
||||
grunt.fail.warn('found only statement in test: ' + spec)
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
11
scripts/grunt/options/clean.js
Normal file
11
scripts/grunt/options/clean.js
Normal file
@ -0,0 +1,11 @@
|
||||
module.exports = function(config) {
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
release: ['<%= destDir %>', '<%= tempDir %>', '<%= genDir %>'],
|
||||
build: ['<%= srcDir %>/build'],
|
||||
temp: ['<%= tempDir %>'],
|
||||
packaging: [
|
||||
],
|
||||
};
|
||||
};
|
30
scripts/grunt/options/compress.js
Normal file
30
scripts/grunt/options/compress.js
Normal file
@ -0,0 +1,30 @@
|
||||
module.exports = function(config) {
|
||||
'use strict';
|
||||
|
||||
var task = {
|
||||
release: {
|
||||
options: {
|
||||
archive: '<%= destDir %>/<%= pkg.name %>-<%= pkg.version %>.<%= platform %>-<%= arch %>.tar.gz'
|
||||
},
|
||||
files : [
|
||||
{
|
||||
expand: true,
|
||||
cwd: '<%= tempDir %>',
|
||||
src: ['**/*'],
|
||||
dest: '<%= pkg.name %>-<%= pkg.version %>/',
|
||||
},
|
||||
{
|
||||
expand: true,
|
||||
src: ['LICENSE.md', 'README.md', 'NOTICE.md'],
|
||||
dest: '<%= pkg.name %>-<%= pkg.version %>/',
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
if (config.platform === 'windows') {
|
||||
task.release.options.archive = '<%= destDir %>/<%= pkg.name %>-<%= pkg.version %>.<%= platform %>-<%= arch %>.zip';
|
||||
}
|
||||
|
||||
return task;
|
||||
};
|
6
scripts/grunt/options/exec.js
Normal file
6
scripts/grunt/options/exec.js
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports = function(config, grunt) {
|
||||
'use strict'
|
||||
return {
|
||||
tslint : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json --type-check",
|
||||
};
|
||||
};
|
22
scripts/grunt/options/jscs.js
Normal file
22
scripts/grunt/options/jscs.js
Normal file
@ -0,0 +1,22 @@
|
||||
module.exports = function(config) {
|
||||
return {
|
||||
src: [
|
||||
'Gruntfile.js',
|
||||
'<%= srcDir %>/app/**/*.js',
|
||||
'<%= srcDir %>/plugin/**/*.js',
|
||||
'!<%= srcDir %>/app/dashboards/*'
|
||||
],
|
||||
options: {
|
||||
config: ".jscs.json",
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
"requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch"],
|
||||
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"],
|
||||
"disallowLeftStickedOperators": ["?", "+", "-", "/", "*", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="],
|
||||
"disallowRightStickedOperators": ["?", "+", "/", "*", ":", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="],
|
||||
"requireRightStickedOperators": ["!"],
|
||||
"requireLeftStickedOperators": [","],
|
||||
*/
|
20
scripts/grunt/options/jshint.js
Normal file
20
scripts/grunt/options/jshint.js
Normal file
@ -0,0 +1,20 @@
|
||||
module.exports = function(config) {
|
||||
return {
|
||||
source: {
|
||||
files: {
|
||||
src: ['Gruntfile.js', '<%= srcDir %>/app/**/*.js'],
|
||||
}
|
||||
},
|
||||
options: {
|
||||
jshintrc: true,
|
||||
reporter: require('jshint-stylish'),
|
||||
ignores: [
|
||||
'node_modules/*',
|
||||
'dist/*',
|
||||
'sample/*',
|
||||
'<%= srcDir %>/vendor/*',
|
||||
'<%= srcDir %>/app/dashboards/*'
|
||||
]
|
||||
}
|
||||
};
|
||||
};
|
20
scripts/grunt/options/karma.js
Normal file
20
scripts/grunt/options/karma.js
Normal file
@ -0,0 +1,20 @@
|
||||
module.exports = function(config) {
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
dev: {
|
||||
configFile: 'karma.conf.js',
|
||||
singleRun: false,
|
||||
},
|
||||
|
||||
debug: {
|
||||
configFile: 'karma.conf.js',
|
||||
singleRun: false,
|
||||
browsers: ['Chrome']
|
||||
},
|
||||
|
||||
test: {
|
||||
configFile: 'karma.conf.js',
|
||||
}
|
||||
};
|
||||
};
|
37
scripts/grunt/options/phantomjs.js
Normal file
37
scripts/grunt/options/phantomjs.js
Normal file
@ -0,0 +1,37 @@
|
||||
module.exports = function(config,grunt) {
|
||||
'use strict';
|
||||
|
||||
grunt.registerTask('phantomjs', 'Copy phantomjs binary to vendor/', function() {
|
||||
|
||||
var dest = './vendor/phantomjs/phantomjs';
|
||||
var confDir = './node_modules/phantomjs-prebuilt/lib/';
|
||||
|
||||
if (process.platform === "win32") {
|
||||
dest += ".exe";
|
||||
}
|
||||
|
||||
src = config.phjs
|
||||
|
||||
if (!src){
|
||||
var m=grunt.file.read(confDir+"location.js")
|
||||
var src=/= \"([^\"]*)\"/.exec(m)[1];
|
||||
|
||||
if (!grunt.file.isPathAbsolute(src)) {
|
||||
src = confDir+src;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
grunt.config('copy.phantom_bin', {
|
||||
src: src,
|
||||
dest: dest,
|
||||
options: { mode: true},
|
||||
});
|
||||
grunt.task.run('copy:phantom_bin');
|
||||
} catch (err) {
|
||||
grunt.verbose.writeln(err);
|
||||
grunt.fail.warn('No working Phantomjs binary available')
|
||||
}
|
||||
|
||||
});
|
||||
};
|
12
scripts/grunt/options/sasslint.js
Normal file
12
scripts/grunt/options/sasslint.js
Normal file
@ -0,0 +1,12 @@
|
||||
module.exports = function(config) {
|
||||
'use strict';
|
||||
return {
|
||||
options: {
|
||||
configFile: 'public/sass/.sass-lint.yml',
|
||||
},
|
||||
target: [
|
||||
'public/sass/*.scss',
|
||||
'public/sass/components/*.scss',
|
||||
]
|
||||
};
|
||||
};
|
11
scripts/grunt/options/tslint.js
Normal file
11
scripts/grunt/options/tslint.js
Normal file
@ -0,0 +1,11 @@
|
||||
module.exports = function(config, grunt) {
|
||||
'use strict'
|
||||
// dummy to avoid template compile error
|
||||
return {
|
||||
source: {
|
||||
files: {
|
||||
src: ""
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
13
scripts/grunt/options/webpack.js
Normal file
13
scripts/grunt/options/webpack.js
Normal file
@ -0,0 +1,13 @@
|
||||
const dev = require('../../webpack/webpack.dev.js');
|
||||
const prod = require('../../webpack/webpack.prod.js');
|
||||
|
||||
module.exports = function() {
|
||||
'use strict';
|
||||
return {
|
||||
options: {
|
||||
stats: !process.env.NODE_ENV || process.env.NODE_ENV === 'development'
|
||||
},
|
||||
dev: dev,
|
||||
prod: prod
|
||||
};
|
||||
};
|
41
scripts/grunt/release_task.js
Normal file
41
scripts/grunt/release_task.js
Normal file
@ -0,0 +1,41 @@
|
||||
var path = require('path');
|
||||
|
||||
module.exports = function(grunt) {
|
||||
"use strict";
|
||||
|
||||
// build, then zip and upload to s3
|
||||
grunt.registerTask('release', [
|
||||
'build',
|
||||
'build-post-process',
|
||||
'compress:release'
|
||||
]);
|
||||
|
||||
grunt.registerTask('build-post-process', function() {
|
||||
grunt.config('copy.public_to_temp', {
|
||||
expand: true,
|
||||
cwd: '<%= srcDir %>',
|
||||
src: '**/*',
|
||||
dest: '<%= tempDir %>/public/',
|
||||
});
|
||||
grunt.config('copy.backend_bin', {
|
||||
cwd: 'bin',
|
||||
expand: true,
|
||||
src: ['*'],
|
||||
options: { mode: true},
|
||||
dest: '<%= tempDir %>/bin/'
|
||||
});
|
||||
grunt.config('copy.backend_files', {
|
||||
expand: true,
|
||||
src: ['conf/*', 'vendor/phantomjs/*', 'scripts/*'],
|
||||
options: { mode: true},
|
||||
dest: '<%= tempDir %>'
|
||||
});
|
||||
|
||||
grunt.task.run('copy:public_to_temp');
|
||||
grunt.task.run('copy:backend_bin');
|
||||
grunt.task.run('copy:backend_files');
|
||||
grunt.task.run('clean:packaging');
|
||||
|
||||
grunt.file.write(path.join(grunt.config('tempDir'), 'VERSION'), grunt.config('pkg.version'));
|
||||
});
|
||||
};
|
47
scripts/grunt/style_guide_task.js
Normal file
47
scripts/grunt/style_guide_task.js
Normal file
@ -0,0 +1,47 @@
|
||||
module.exports = function(grunt) {
|
||||
"use strict";
|
||||
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||
}
|
||||
|
||||
function extractColour(line) {
|
||||
var regex = /\s*:\s*(#[a-fA-F0-9]{3,6})\s*(!default|!default;)?/;
|
||||
var matches = line.match(regex);
|
||||
return matches ? matches[1] : matches;
|
||||
}
|
||||
|
||||
function extractVariable(line) {
|
||||
var matches = line.match(/(\$[0-9a-zA-Z_-]+)\s*(!default|!default;)?/)
|
||||
return matches ? matches[1] : matches
|
||||
}
|
||||
|
||||
function readVars(file, obj) {
|
||||
var content = grunt.file.read(file);
|
||||
var lines = content.split('\n');
|
||||
|
||||
lines.forEach(function(line) {
|
||||
var variable = extractVariable(line);
|
||||
if (variable) {
|
||||
var color = extractColour(line, variable);
|
||||
if (color) {
|
||||
obj[variable] = color;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
grunt.registerTask('styleguide', function() {
|
||||
var data = {
|
||||
dark: {}, light: {}
|
||||
};
|
||||
|
||||
readVars('public/sass/_variables.dark.scss', data.dark);
|
||||
readVars('public/sass/_variables.light.scss', data.light);
|
||||
|
||||
var styleGuideJson = grunt.config().srcDir + '/build/styleguide.json';
|
||||
grunt.file.write(styleGuideJson, JSON.stringify(data, null, 4));
|
||||
|
||||
});
|
||||
|
||||
};
|
7
scripts/webpack/postcss.config.js
Normal file
7
scripts/webpack/postcss.config.js
Normal file
@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
'autoprefixer': {},
|
||||
'postcss-reporter': {},
|
||||
'postcss-browser-reporter': {},
|
||||
}
|
||||
}
|
31
scripts/webpack/sass.rule.js
Normal file
31
scripts/webpack/sass.rule.js
Normal file
@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
const ExtractTextPlugin = require("extract-text-webpack-plugin");
|
||||
|
||||
module.exports = function(options) {
|
||||
return {
|
||||
test: /\.scss$/,
|
||||
use: ExtractTextPlugin.extract({
|
||||
use: [
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
importLoaders: 2,
|
||||
url: false,
|
||||
sourceMap: options.sourceMap,
|
||||
minimize: options.minimize,
|
||||
}
|
||||
},
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
sourceMap: options.sourceMap,
|
||||
config: { path: __dirname + '/postcss.config.js' }
|
||||
}
|
||||
},
|
||||
{ loader:'sass-loader', options: { sourceMap: options.sourceMap } }
|
||||
],
|
||||
})
|
||||
};
|
||||
}
|
||||
|
87
scripts/webpack/webpack.common.js
Normal file
87
scripts/webpack/webpack.common.js
Normal file
@ -0,0 +1,87 @@
|
||||
const path = require('path');
|
||||
const {CheckerPlugin} = require('awesome-typescript-loader')
|
||||
|
||||
module.exports = {
|
||||
target: 'web',
|
||||
stats: {
|
||||
children: false
|
||||
},
|
||||
entry: {
|
||||
app: './public/app/index.ts',
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, '../../public/build'),
|
||||
filename: '[name].[chunkhash].js',
|
||||
publicPath: "public/build/",
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.es6', '.js', '.json'],
|
||||
alias: {
|
||||
},
|
||||
modules: [
|
||||
path.resolve('public'),
|
||||
path.resolve('node_modules')
|
||||
],
|
||||
},
|
||||
node: {
|
||||
fs: 'empty',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(ts|tsx)$/,
|
||||
enforce: 'pre',
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'tslint-loader',
|
||||
options: {
|
||||
emitErrors: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{ loader: "awesome-typescript-loader" }
|
||||
]
|
||||
},
|
||||
{
|
||||
test: require.resolve('jquery'),
|
||||
use: [
|
||||
{
|
||||
loader: 'expose-loader',
|
||||
query: 'jQuery'
|
||||
},
|
||||
{
|
||||
loader: 'expose-loader',
|
||||
query: '$'
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
// test : /\.(ico|png|cur|jpg|ttf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
|
||||
// loader : 'file-loader',
|
||||
// },
|
||||
{
|
||||
test: /\.html$/,
|
||||
exclude: /index\.template.html/,
|
||||
use: [
|
||||
{ loader:'ngtemplate-loader?relativeTo=' + (path.resolve(__dirname, '../../public')) + '&prefix=public'},
|
||||
{
|
||||
loader: 'html-loader',
|
||||
options: {
|
||||
attrs: [],
|
||||
minimize: true,
|
||||
removeComments: false,
|
||||
collapseWhitespace: false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new CheckerPlugin(),
|
||||
]
|
||||
};
|
54
scripts/webpack/webpack.dev.js
Normal file
54
scripts/webpack/webpack.dev.js
Normal file
@ -0,0 +1,54 @@
|
||||
'use strict';
|
||||
|
||||
const merge = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const ExtractTextPlugin = require("extract-text-webpack-plugin");
|
||||
const WebpackCleanupPlugin = require('webpack-cleanup-plugin');
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
const pkg = require('../../package.json');
|
||||
let dependencies = Object.keys(pkg.dependencies);
|
||||
|
||||
module.exports = merge(common, {
|
||||
devtool: "source-map",
|
||||
|
||||
entry: {
|
||||
dark: './public/sass/grafana.dark.scss',
|
||||
light: './public/sass/grafana.light.scss',
|
||||
vendor: dependencies,
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
require('./sass.rule.js')({
|
||||
sourceMap: true, minimize: false
|
||||
})
|
||||
]
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new ExtractTextPlugin({ // define where to save the file
|
||||
filename: 'grafana.[name].css',
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
filename: path.resolve(__dirname, '../../public/views/index.html'),
|
||||
template: path.resolve(__dirname, '../../public/views/index.template.html'),
|
||||
inject: 'body',
|
||||
chunks: ['manifest', 'vendor', 'app'],
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
'NODE_ENV': JSON.stringify('development')
|
||||
}
|
||||
}),
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
names: ['vendor', 'manifest'],
|
||||
}),
|
||||
new WebpackCleanupPlugin(),
|
||||
// new BundleAnalyzerPlugin({
|
||||
// analyzerPort: 8889
|
||||
// })
|
||||
]
|
||||
});
|
62
scripts/webpack/webpack.prod.js
Normal file
62
scripts/webpack/webpack.prod.js
Normal file
@ -0,0 +1,62 @@
|
||||
'use strict';
|
||||
|
||||
const merge = require('webpack-merge');
|
||||
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
|
||||
const common = require('./webpack.common.js');
|
||||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
const ngAnnotatePlugin = require('ng-annotate-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const ExtractTextPlugin = require("extract-text-webpack-plugin");
|
||||
const pkg = require('../../package.json');
|
||||
let dependencies = Object.keys(pkg.dependencies);
|
||||
|
||||
module.exports = merge(common, {
|
||||
devtool: "source-map",
|
||||
|
||||
entry: {
|
||||
dark: './public/sass/grafana.dark.scss',
|
||||
light: './public/sass/grafana.light.scss',
|
||||
vendor: dependencies,
|
||||
},
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
require('./sass.rule.js')({
|
||||
sourceMap: false, minimize: true
|
||||
})
|
||||
]
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new ExtractTextPlugin({
|
||||
filename: 'grafana.[name].css',
|
||||
}),
|
||||
new ngAnnotatePlugin(),
|
||||
new UglifyJSPlugin({
|
||||
sourceMap: true,
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
'NODE_ENV': JSON.stringify('production')
|
||||
}
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
filename: path.resolve(__dirname, '../../public/views/index.html'),
|
||||
template: path.resolve(__dirname, '../../public/views/index.template.html'),
|
||||
inject: 'body',
|
||||
chunks: ['manifest', 'vendor', 'app'],
|
||||
}),
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
names: ['vendor', 'manifest'],
|
||||
}),
|
||||
function() {
|
||||
this.plugin("done", function(stats) {
|
||||
if (stats.compilation.errors && stats.compilation.errors.length) {
|
||||
console.log(stats.compilation.errors);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
]
|
||||
});
|
23
scripts/webpack/webpack.test.js
Normal file
23
scripts/webpack/webpack.test.js
Normal file
@ -0,0 +1,23 @@
|
||||
const webpack = require('webpack');
|
||||
const merge = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
|
||||
config = merge(common, {
|
||||
devtool: 'inline-source-map',
|
||||
externals: {
|
||||
'react/addons': true,
|
||||
'react/lib/ExecutionEnvironment': true,
|
||||
'react/lib/ReactContext': true,
|
||||
},
|
||||
node: {
|
||||
fs: 'empty'
|
||||
},
|
||||
plugins: [
|
||||
new webpack.SourceMapDevToolPlugin({
|
||||
filename: null, // if no value is provided the sourcemap is inlined
|
||||
test: /\.(ts|js)($|\?)/i // process .js and .ts files only
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
module.exports = config;
|
Reference in New Issue
Block a user