changed tooling from browserify to webpack

* using browsersync instead of livereload
* `gulp serve` works as before
* `gulp sync` starts browserSync and serves UI on port 3000
* everything is built in `build/`
* build release with `gulp build --release`
This commit is contained in:
David Kaltschmidt
2015-05-29 11:48:55 +02:00
parent 784c1e0e75
commit 4d027fef19
11 changed files with 329 additions and 174 deletions

View File

@@ -37,14 +37,14 @@ $(APP_EXE) $(PROBE_EXE):
go get -tags netgo ./$(@D)
go build -ldflags "-extldflags \"-static\" -X main.version $(GIT_REVISION)" -tags netgo -o $@ ./$(@D)
static: client/dist/scripts/bundle.js
esc -o app/static.go -prefix client/dist client/dist
static: client/build/app.js
esc -o app/static.go -prefix client/build client/build
client/dist/scripts/bundle.js: client/app/scripts/*
mkdir -p client/dist
client/build/app.js: client/app/scripts/*
mkdir -p client/build
docker run -ti -v $(shell pwd)/client/app:/home/weave/app \
-v $(shell pwd)/client/dist:/home/weave/dist \
$(SCOPE_UI_BUILD_IMAGE) gulp build
-v $(shell pwd)/client/build:/home/weave/build \
$(SCOPE_UI_BUILD_IMAGE) gulp build --release
client-test: client/test/*
docker run -ti -v $(shell pwd)/client/app:/home/weave/app \
@@ -62,7 +62,7 @@ $(SCOPE_UI_BUILD_EXPORT): client/Dockerfile client/gulpfile.js client/package.js
clean:
go clean ./...
rm -rf $(SCOPE_EXPORT) $(SCOPE_UI_BUILD_EXPORT) client/dist
rm -rf $(SCOPE_EXPORT) $(SCOPE_UI_BUILD_EXPORT) client/build
deps:
go get \

6
client/.gitignore vendored
View File

@@ -1,6 +1,2 @@
node_modules
dist
.tmp
.sass-cache
bower_components
test/bower_components
build

View File

@@ -5,14 +5,6 @@
<title>Weave Scope</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- build:css styles/vendor.css -->
<!-- endbuild -->
<!-- build:css styles/main.css -->
<link rel="stylesheet" href="styles/main.css">
<!-- endbuild -->
</head>
<body>
<!--[if lt IE 10]>
@@ -26,8 +18,6 @@
<script>window.WS_URL = 'ws://localhost:4040';</script>
<!-- @endif -->
<!-- build:js scripts/bundle.js -->
<script src="scripts/bundle.js"></script>
<!-- endbuild -->
<script src="app.js"></script>
</body>
</html>

View File

@@ -1,3 +1,6 @@
require('font-awesome-webpack');
require('../styles/main.less');
const React = require('react');
const App = require('./components/app.js');

View File

@@ -1,6 +1,5 @@
@import "../../node_modules/material-ui/src/less/scaffolding";
@import "../../node_modules/material-ui/src/less/components";
@import "../../node_modules/font-awesome/less/font-awesome.less";
@import "~material-ui/src/less/scaffolding.less";
@import "~material-ui/src/less/components.less";
@import url(http://fonts.googleapis.com/css?family=Roboto:300,400);

View File

@@ -1,83 +1,151 @@
const gulp = require('gulp');
const connect = require('gulp-connect');
const livereload = require('gulp-livereload');
const babelify = require('babelify');
const browserify = require('browserify');
const del = require('del');
const source = require('vinyl-source-stream');
const vbuffer = require('vinyl-buffer');
const reactify = require('reactify');
'use strict';
// load plugins
const $ = require('gulp-load-plugins')();
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var del = require('del');
var path = require('path');
var runSequence = require('run-sequence');
var webpack = require('webpack');
var argv = require('minimist')(process.argv.slice(2));
var isDev = true;
var isProd = false;
var watch = false;
var browserSync;
gulp.task('styles', function() {
return gulp.src('app/styles/main.less')
.pipe($.if(isDev, $.sourcemaps.init()))
.pipe($.less())
.pipe($.autoprefixer('last 1 version'))
.pipe($.if(isDev, $.sourcemaps.write()))
.pipe($.if(isDev, gulp.dest('.tmp/styles')))
.pipe($.if(isProd, $.csso()))
.pipe($.if(isProd, gulp.dest('dist/styles')))
.pipe($.size())
.pipe(livereload());
});
// The default task
gulp.task('default', ['build']);
gulp.task('scripts', function() {
const bundler = browserify('./app/scripts/main.js', {debug: isDev});
bundler.transform(reactify);
bundler.transform(babelify);
// Clean output directory
gulp.task('clean', del.bind(
null, ['.tmp', 'build/*'], {dot: true}
));
const stream = bundler.bundle();
return stream
.pipe(source('bundle.js'))
.pipe($.if(isDev, gulp.dest('.tmp/scripts')))
.pipe($.if(isProd, vbuffer()))
.pipe($.if(isProd, $.uglify()))
.on('error', $.util.log)
.pipe($.if(isProd, gulp.dest('dist/scripts')))
.pipe(livereload());
});
gulp.task('html', ['styles', 'scripts'], function() {
return gulp.src('app/*.html')
.pipe($.preprocess())
.pipe(gulp.dest('dist'))
.pipe($.size())
.pipe(livereload());
});
gulp.task('images', function() {
return gulp.src('app/images/**/*')
.pipe(gulp.dest('dist/images'))
.pipe($.size());
});
gulp.task('fonts', function() {
return gulp.src('node_modules/font-awesome/fonts/*')
// 3rd party libraries
gulp.task('vendor', function() {
return gulp.src('node_modules/font-awesome/fonts/**')
.pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}'))
.pipe($.flatten())
.pipe($.if(isDev, gulp.dest('.tmp/fonts')))
.pipe($.if(isProd, gulp.dest('dist/fonts')))
.pipe($.size());
.pipe(gulp.dest('build/fonts'));
});
gulp.task('extras', function() {
return gulp.src(['app/*.*', '!app/*.html'], { dot: true })
.pipe(gulp.dest('dist'));
});
gulp.task('clean', function() {
return del(['.tmp', 'dist']);
// Favicon
gulp.task('favicon', function() {
return gulp.src(['app/favicon.ico'])
.pipe(gulp.dest('build'));
});
// Static files
gulp.task('html', function() {
var release = !!argv.release;
return gulp.src('app/*.html')
.pipe($.changed('build'))
.pipe($.if(release, $.preprocess()))
.pipe(gulp.dest('build'))
.pipe($.size({title: 'html'}));
});
// Bundle
gulp.task('bundle', function(cb) {
var started = false;
var config = require('./webpack.config.js');
var bundler = webpack(config);
var verbose = !!argv.verbose;
function bundle(err, stats) {
if (err) {
throw new $.util.PluginError('webpack', err);
}
console.log(stats.toString({
colors: $.util.colors.supportsColor,
hash: verbose,
version: verbose,
timings: verbose,
chunks: verbose,
chunkModules: verbose,
cached: verbose,
cachedAssets: verbose
}));
if (!started) {
started = true;
return cb();
}
}
if (watch) {
bundler.watch(200, bundle);
} else {
bundler.run(bundle);
}
});
// Build the app from source code
gulp.task('build', ['clean'], function(cb) {
runSequence(['vendor', 'html', 'favicon', 'bundle'], cb);
});
// Build and start watching for modifications
gulp.task('build:watch', function(cb) {
watch = true;
runSequence('build', function() {
gulp.watch('app/*.html', ['html']);
cb();
});
});
// Launch a Node.js/Express server
gulp.task('serve', ['build:watch'], function() {
$.connect.server({
root: ['build'],
port: 4041,
middleware: function() {
return [(function() {
var url = require('url');
var proxy = require('proxy-middleware');
var options = url.parse('http://localhost:4040/api');
options.route = '/api';
return proxy(options);
})()];
},
livereload: false
});
});
// Launch BrowserSync development server
gulp.task('sync', ['serve'], function(cb) {
browserSync = require('browser-sync');
browserSync({
logPrefix: 'RSK',
// Stop the browser from automatically opening
open: false,
notify: false,
// Run as an https by setting 'https: true'
// Note: this uses an unsigned certificate which on first access
// will present a certificate warning in the browser.
https: false,
// Informs browser-sync to proxy our Express app which would run
// at the following location
proxy: 'localhost:4041'
}, cb);
process.on('exit', function() {
browserSync.exit();
});
gulp.watch('build/**/*.*', browserSync.reload);
// FIX this part to only reload styles parts that changed
// gulp.watch(['build/**/*.*'].concat(
// src.server.map(function(file) { return '!' + file; })
// ), function(file) {
// browserSync.reload(path.relative(__dirname, file.path));
// });
});
// Lint
gulp.task('lint', function() {
return gulp.src(['app/**/*.js'])
// eslint() attaches the lint output to the eslint property
@@ -90,54 +158,3 @@ gulp.task('lint', function() {
// lint error, return the stream and pipe to failOnError last.
.pipe($.eslint.failOnError());
});
gulp.task('production', ['html', 'images', 'fonts', 'extras']);
gulp.task('build', function() {
isDev = false;
isProd = true;
gulp.start('production');
});
gulp.task('default', ['clean'], function() {
gulp.start('build');
});
gulp.task('connect', function() {
const root = isProd ? ['dist'] : ['.tmp', 'app'];
connect.server({
root: root,
port: 4041,
middleware: function() {
return [(function() {
const url = require('url');
const proxy = require('proxy-middleware');
const options = url.parse('http://localhost:4040/api');
options.route = '/api';
return proxy(options);
})()];
},
livereload: false
});
});
gulp.task('serve', ['connect', 'styles', 'scripts', 'fonts']);
gulp.task('serve-build', function() {
isDev = false;
isProd = true;
// use local WS api
gulp.src('app/*.html')
.pipe($.preprocess({context: {DEBUG: true} }))
.pipe(gulp.dest('dist'));
gulp.start('connect');
});
gulp.task('watch', ['serve'], function() {
livereload.listen();
gulp.watch('app/styles/**/*.less', ['styles']);
gulp.watch('app/scripts/**/*.js', ['scripts']);
gulp.watch('app/images/**/*', ['images']);
});

View File

@@ -11,53 +11,61 @@
"flux": "^2.0.3",
"font-awesome": "^4.3.0",
"keymirror": "^0.1.1",
"lodash": "~3.8.0",
"material-ui": "^0.7.5",
"lodash": "~3.9.3",
"material-ui": "~0.7.5",
"object-assign": "^2.0.0",
"page": "^1.6.3",
"react": "^0.13.3",
"react-tap-event-plugin": "^0.1.6",
"react-tap-event-plugin": "^0.1.7",
"react-tween-state": "0.0.5",
"reqwest": "~1.1.5"
},
"devDependencies": {
"autoprefixer-core": "^5.2.0",
"babel-core": "^5.4.7",
"babel-eslint": "^3.1.9",
"babel-loader": "^5.1.3",
"babelify": "^6.1.2",
"browserify": "^10.2.0",
"del": "^1.1.1",
"browser-sync": "^2.7.6",
"css-loader": "^0.14.4",
"del": "^1.2.0",
"eslint": "^0.21.2",
"eslint-loader": "^0.11.2",
"eslint-plugin-jasmine": "^1.0.0",
"eslint-plugin-react": "^2.3.0",
"file-loader": "^0.8.4",
"font-awesome-webpack": "0.0.3",
"gulp": "^3.8.11",
"gulp-autoprefixer": "^2.3.0",
"gulp-changed": "^1.2.1",
"gulp-connect": "^2.2.0",
"gulp-csso": "^1.0.0",
"gulp-eslint": "^0.12.0",
"gulp-filter": "^2.0.2",
"gulp-flatten": "^0.0.4",
"gulp-if": "^1.2.5",
"gulp-less": "^3.0.3",
"gulp-livereload": "^3.8.0",
"gulp-load-plugins": "^0.10.0",
"gulp-preprocess": "^1.2.0",
"gulp-size": "^1.2.1",
"gulp-sourcemaps": "^1.5.2",
"gulp-uglify": "^1.2.0",
"gulp-useref": "^1.1.1",
"gulp-util": "^3.0.4",
"jasmine-core": "^2.3.4",
"jshint-stylish": "^1.0.2",
"karma": "^0.12.32",
"karma-browserify": "^4.2.1",
"karma": "^0.12.33",
"karma-cli": "0.0.4",
"karma-jasmine": "^0.3.5",
"karma-phantomjs-launcher": "^0.1.4",
"opn": "^1.0.1",
"proxy-middleware": "^0.11.1",
"karma-webpack": "^1.5.1",
"less": "^2.5.1",
"less-loader": "^2.2.0",
"minimist": "^1.1.1",
"node-libs-browser": "^0.5.2",
"postcss-loader": "^0.4.3",
"proxy-middleware": "^0.12.0",
"react-tools": "^0.13.3",
"reactify": "^1.1.1",
"run-sequence": "^1.1.0",
"style-loader": "^0.12.3",
"url-loader": "^0.5.6",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0"
"vinyl-source-stream": "^1.1.0",
"webpack": "^1.9.10"
},
"scripts": {
"lint": "gulp lint",

View File

@@ -1,3 +0,0 @@
{
"directory": "bower_components"
}

View File

@@ -4,20 +4,34 @@ module.exports = function(config) {
'PhantomJS'
],
files: [
'../app/**/__tests__/*.js'
{
pattern: 'tests.webpack.js',
watched: false
}
],
frameworks: [
'jasmine', 'browserify'
'jasmine'
],
preprocessors: {
'../app/**/__tests__/*.js': ['browserify']
},
browserify: {
debug: true,
transform: ['reactify', 'babelify']
'tests.webpack.js': ['webpack']
},
reporters: [
'dots'
]
],
webpack: {
module: {
loaders: [
{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
},
watch: true
},
webpackServer: {
noInfo: true
}
});
};

View File

@@ -0,0 +1,2 @@
var context = require.context('../app/scripts', true, /-test\.js$/);
context.keys().forEach(context);

129
client/webpack.config.js Normal file
View File

@@ -0,0 +1,129 @@
/*
* React.js Starter Kit
* Copyright (c) Konstantin Tarkus (@koistya), KriaSoft LLC
*
* This source code is licensed under the MIT license found in the
* LICENSE.txt file in the root directory of this source tree.
*/
'use strict';
var autoprefixer = require('autoprefixer-core');
var _ = require('lodash');
var webpack = require('webpack');
var argv = require('minimist')(process.argv.slice(2));
var DEBUG = !argv.release;
var STYLE_LOADER = 'style-loader';
var CSS_LOADER = DEBUG ? 'css-loader' : 'css-loader?minimize';
var AUTOPREFIXER_LOADER = 'postcss-loader';
var GLOBALS = {
'process.env.NODE_ENV': DEBUG ? '"development"' : '"production"',
'__DEV__': DEBUG
};
//
// Common configuration chunk to be used for both
// client-side (app.js) and server-side (server.js) bundles
// -----------------------------------------------------------------------------
var config = {
output: {
path: './build/',
publicPath: './',
sourcePrefix: ' '
},
cache: DEBUG,
debug: DEBUG,
devtool: DEBUG ? '#inline-source-map' : false,
stats: {
colors: true,
reasons: DEBUG
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin()
],
resolve: {
extensions: ['', '.webpack.js', '.web.js', '.js', '.jsx']
},
module: {
preLoaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader'
}
],
loaders: [
{
test: /\.css$/,
loader: STYLE_LOADER + '!' + CSS_LOADER + '!' + AUTOPREFIXER_LOADER
},
{
test: /\.less$/,
loader: STYLE_LOADER + '!' + CSS_LOADER + '!' + AUTOPREFIXER_LOADER +
'!less-loader'
},
{
test: /\.gif/,
loader: 'url-loader?limit=10000&mimetype=image/gif'
},
{
test: /\.jpg/,
loader: 'url-loader?limit=10000&mimetype=image/jpg'
},
{
test: /\.png/,
loader: 'url-loader?limit=10000&mimetype=image/png'
},
{
test: /\.svg/,
loader: 'url-loader?limit=10000&mimetype=image/svg+xml'
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url-loader?limit=10000&minetype=application/font-woff'
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader'
}
]
},
postcss: [
autoprefixer({
browsers: ['last 2 version']
})
]
};
//
// Configuration for the client-side bundle (app.js)
// -----------------------------------------------------------------------------
var appConfig = _.merge({}, config, {
entry: './app/scripts/main.js',
output: {
filename: 'app.js'
},
plugins: config.plugins.concat(DEBUG ? [] : [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin(),
new webpack.optimize.AggressiveMergingPlugin()
]
)
});
module.exports = [appConfig];