I use MAMP/Grunt/SublimeText/LESS/LiveReload at home, which works perfectly in Chrome. Instant reloads everytime I save any designated file.
But at work, I'm working in Eclipse with files and a jetty server. Now, for some reason, when I save a 'watched' file, all the LESS is compiled and minified, and the local server refreshes itself in the browser, but it takes 20-30 seconds (and another page reload) to get a simple CSS change to implement.
Here's my gruntfile. Any ideas on how I could get changes to render more quickly?
module.exports = function(grunt) {
grunt.initConfig({
project: {
name: 'web-standard',
version: grunt.option('pomVersion') || 'VERSION',
},
/* CSS */
less: {
build: {
files: [
{
expand: true,
flatten: true,
src: 'src/main/less/*.less',
dest: 'target/css',
ext: '.css'
}
]
}
},
autoprefixer: {
build: {
options: {
browsers: ['last 2 versions']
},
expand:true,
flatten:true,
src: 'target/css/*.css',
dest: 'target/css/'
}
},
cssmin: {
minify: {
options: {
banner: '<%= project.copyright %>'
},
expand: true,
cwd: 'target/css/',
src: '*.css',
dest: 'target/css-min/',
ext: '.min.css'
}
},
/* Utilities */
watch: {
less: {
options: {
livereload:true,
spawn: false
},
files: ['src/main/less/*.less','target/css-min/*.css','Gruntfile.js'],
tasks: ['less', 'autoprefixer','cssmin']
}
}
});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-autoprefixer');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('dev-css', ['less','autoprefixer','cssmin','watch:less']);
};
The files array of your watch task should not contain the 'target/css-min/*.css' and 'Gruntfile.js'. Most important to remove the'target/css-min/*.css'`
Also the 'autoprefixer' ask 'cssmin' are not necessary for development.
Note that changing the less files triggers the less task, which change the 'target/css-min/*.css' again which triggers the reload, also the autoprefixer will change the 'target/css-min/*.css' files again.
Try:
watch: {
less: {
options: {
livereload:true,
spawn: false
},
files: ['src/main/less/*.less'],
tasks: ['less']
}
}
Related
I was able prepare my OpenUI5 app for testing. I am having issue with the working directory for tests, because for my test I need to use a pre-populated sqlite3 database. For testing I use chrome with parameters --user-data-dir="C:\tmp" --profile-directory="karma", and I can place this file into chrome profile path. But I am not able to do this with karma, because karma always start with randomly generated id in path (karma-xxxxxx).
I am trying run custom browser config, with above chrome parameters, but it does not work.
module.exports = function(config) {
"use strict";
var chromeFlags = [
"--window-size=1280,1024",
"--disable-web-security",
"--allow-file-access-from-files",
'--user-data-dir="C:\\tmp"',
'--profile-directory="karma"'
];
config.set({
basePath: '',
ui5: {
type: "application",
preload: 'async',
animation: 'false',
paths: {
webapp: "www", // application
}
},
frameworks: ["ui5"],
browsers: ["CustomChrome"],
browserConsoleLogOptions: {
level: "error"
},
customLaunchers: {
CustomChrome: {
base: "Chrome",
flags: chromeFlags
},
CustomChromeHeadless: {
base: "ChromeHeadless",
flags: chromeFlags
}
},
});
};
with this config, chrome always start like this, so automatic testing does not work:
Using the Aurelia CLI I run my unit tests with au test. Karma logs to console (over and over again for multiple requests):
WARN [web-server]: 404: /src/assets/images/avatar-backup.png
I understand that including my image files with tests isn't necessary and I could change the log levels to ignore these warnings, but this seems like it should really be a non issue. If for nothing else I want to know why and how to fix this for my own curiosity.
I've tried a combination of different methods found here and here (and elsewhere), but I still cannot figure out what I'm doing wrong. I'm still somewhat new to Karma and Aurelia so maybe I'm missing some fundamental understanding... I don't know.
Currently my this is my karma.conf.js
'use strict';
const path = require('path');
const project = require('./aurelia_project/aurelia.json');
const tsconfig = require('./tsconfig.json');
let testSrc = [
{ pattern: project.unitTestRunner.source, included: false },
'test/aurelia-karma.js'
];
let output = project.platform.output;
let appSrc = project.build.bundles.map(x => path.join(output, x.name));
let entryIndex = appSrc.indexOf(path.join(output, project.build.loader.configTarget));
let entryBundle = appSrc.splice(entryIndex, 1)[0];
// Added the image file sources
let imgFiles = [
{pattern: 'src/assets/images/*', watched: false, included: false, served: true, nocache: false},
// Added an exact path in case my pattern was somehow wrong, still doesn't load
{pattern: 'src/assets/images/avatar-backup.png', watched: false, included: false, served: true, nocache: false}
];
// Concat imgFiles to file array
let files = [entryBundle].concat(imgFiles).concat(testSrc).concat(appSrc);
module.exports = function(config) {
config.set({
basePath: '',
frameworks: [project.testFramework.id],
files: files,
exclude: [],
preprocessors: {
[project.unitTestRunner.source]: [project.transpiler.id]
},
typescriptPreprocessor: {
typescript: require('typescript'),
options: tsconfig.compilerOptions
},
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
// client.args must be a array of string.
// Leave 'aurelia-root', projectName.paths.root in this order so we can find
// the root of the aurelia projectName.
client: {
args: ['aurelia-root', project.paths.root]
},
browserConsoleLogOptions: {
terminal: true,
level: ""
},
// Not sure how to use proxy in combination with my added file sources or if I even need to...
// proxies: {
// "/img/": "http://localhost:9876/base/src/assets/images/"
// },
});
};
My app file structure looks like:
app
- src
- assets
- images
- (..images)
- test
- unit
- (..tests)
I am trying to get my project working with Karma and SystemJS. I am using the karma-systemjs plugin with karma.
I keep getting the error below about System.import.
I believe it is because SystemJS is not being loaded by the time the karma-systemjs plugin runs. Please tell me what I am doing wrong.
Project structure
SystemJS configuration (system.conf.js)
System.config({
baseUrl: '',
defaultJSExtensions: true,
map: {
'jquery': 'vendor/kendo/js/jquery.min.js',
'angular': 'vendor/kendo/js/angular.js',
'kendo': 'vendor/kendo/js/kendo.all.min.js',
'angular-mocks': 'vendor/bower_components/angular-mocks/angular-mocks.js',
'angular-ui-router': 'vendor/bower_components/angular-ui-router/release/angular-ui-router.min.js',
'angular-toastr': 'vendor/bower_components/angular-toastr/dist/angular-toastr.tpls.min.js',
'angular-local-storage': 'vendor/bower_components/angular-local-storage/dist/angular-local-storage.min.js'
},
paths: {
'systemjs': 'vendor/bower_components/system.js/dist/system.js',
'system-polyfills': 'vendor/bower_components/system.js/dist/system-polyfills.js'
},
meta: {
'vendor/kendo/js/jquery.min.js': {
format: 'global',
exports: '$'
},
'vendor/kendo/js/angular.js': {
format: 'global',
deps: [
'vendor/kendo/js/jquery.min.js'
],
exports: 'angular'
},
'vendor/kendo/js/kendo.all.min.js': {
format: 'global',
deps: [
'vendor/kendo/js/angular.js'
],
exports: 'kendo'
},
'vendor/bower_components/angular-ui-router/release/angular-ui-router.min.js': {
format: 'global',
deps: [
'vendor/kendo/js/angular.js'
]
},
'vendor/bower_components/angular-mocks/angular-mocks.js': {
format: 'global',
deps: [
'vendor/kendo/js/angular.js'
],
exports: 'angular.mock'
},
'vendor/bower_components/angular-toastr/dist/angular-toastr.tpls.min.js': {
format: 'global',
deps: [
'vendor/kendo/js/angular.js'
]
},
'vendor/bower_components/angular-local-storage/dist/angular-local-storage.min': {
format: 'global',
deps: [
'vendor/kendo/js/angular.js'
]
}
}
});
Promise.all([
System.import('kendo'),
System.import('angular-mocks'),
System.import('angular-ui-router'),
System.import('angular-toastr'),
System.import('angular-local-storage')
]).then(function () {
System.import('angular')
.then(function (angular) {
System.import('ng/app/app.module')
.then(function (app) {
angular.bootstrap(document, ['s9.app']);
}, function (err) {
console.log(err);
});
}, function (err) {
console.log(err);
});
});
//# sourceMappingURL=system.conf.js.map
karma.conf.js
// Karma configuration
var configure = function (config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '.',
transpiler: null,
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['systemjs', 'jasmine'],
systemjs: {
// Path to your SystemJS configuration file
configFile: 'system.conf.js',
// Patterns for files that you want Karma to make available, but not loaded until a module
// requests them. eg. Third-party libraries.
serveFiles: [
'vendor/kendo/js/**/*.js',
'vendor/bower_components/**/*.js',
'ng/**/*.js',
'test/**/*Spec.js'
],
config: {
paths: {
'systemjs': 'vendor/bower_components/system.js/dist/system.js',
'system-polyfills': 'vendor/bower_components/system.js/dist/system-polyfills.js'
}
}
},
// list of files / patterns to load in the browser
files: [
{pattern: 'vendor/kendo/js/**/*.js', included: false},
{pattern: 'vendor/bower_components/**/*.js', included: false},
{pattern: 'ng/**/*.js', included: false},
{pattern: 'test/**/*Spec.js', included: false}
],
// list of files to exclude
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_DEBUG,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['PhantomJS'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity
});
};
module.exports = configure;
//# sourceMappingURL=karma.conf.js.map
Error
I fixed this by moving the bootstrap code out of the config code. Apparently when using the karma-systemjs plugin System.import is not available yet when this is called (although it is at normal runtime).
What I did: I moved the bootstrap code (i.e. Promise.all([....) into into a separate file called bootstrap.js (name is not important) and then in my index.html I added them in this order:
Also from this link (the karma system js plugin author says): https://github.com/rolaveric/karma-systemjs/issues/71
I see the problem. It's because you've got your bootstrapping code
(eg. System.import() calls) inside your SystemJS config file -
system.conf.js karma-systemjs expects just a simple System.config()
call that it can then intercept to find out where your transpiler and
polyfills are. It does this by evaluating your config file with a fake
System object which simply records whatever is passed to
System.config(). This fake object has no System.import() method, which
causes your error.
I'd recommend moving your bootstrapping code into a separate file (I
personally put it in a script tag with my HTML). Otherwise you'll run
into similar problems if you try to use systemjs-builder, and you
probably don't want angular.bootstrap() to be called at the start of
your unit tests.
I have several files named:
jquery.a.b.coffee
jquery.a.c.coffee
jquery.a.d.coffee
and they are all compiled into one jquery.js file in my output directory.
Although I guess this behavior might be nice in some cases, I would like to have them to compile into different files like jquery.a.b.js, jquery.a.c.js and so on. How can I tell grunt-contrib-coffeescript to do so?
My Gruntfile.js looks like this:
module.exports = function (grunt) {
grunt.initConfig({
coffee: {
dist: {
files: [{
expand: true,
flatten: true,
cwd: 'app/webroot/coffee',
src: ['{,*/}*.coffee'],
dest: 'app/webroot/js',
ext: '.js'
}]
}
}
});
grunt.loadNpmTasks('grunt-contrib-coffee');
};
Thanks for your help!
The problem lies on the filenames having multiple dots.
If it was jquery-a-b.coffee, jquery-a-c.coffee etc, you would have seen the expected output.
It is a known issue (extension is after last period only) and grunt developers made this on purpose.
Here is a quote from one of them:
There's two ways ext could work; it could consider everything after
the first dot the extension, or everything after the last dot the
extension. We chose the former because the use-case is more common (we
encounter .min.js files all the time). That being said, you can use
the rename option to specify a function that will use whatever custom
naming logic you need.
So, the only workaround for now is to remove ext and use rename like this:
coffee: {
dist: {
files: [{
expand: true,
cwd: 'app/webroot/coffee',
src: ['{,*/}*.coffee'],
dest: 'app/webroot/js',
rename: function(dest, src) {
return dest + '/' + src.replace(/\.coffee$/, '.js');
}
}]
}
}
Update as of Grunt 0.4.3:
You can now use the extDot option along with ext
ext: '.js',
extDot: 'last'
This works so you don't have to add the files by hand in your gruntFile:
coffee: {
glob_to_multiple: {
expand: true,
flatten: true,
cwd: 'app/webroot/coffee/',
src: ['*.coffee'],
dest: 'app/webroot/',
ext: '.js'
}
},
cwd: the folder where your files are
src: the matching pattern for your files, using glob
dest: The folder where your files are going.
See https://github.com/gruntjs/grunt-contrib-coffee#usage-examples for some sample usages
So on grunt-contrib-watch plugin info page, there is an example on how to make jshint run only for changed file.
grunt.initConfig({
watch: {
scripts: {
files: ['lib/*.js'],
tasks: ['jshint'],
options: {
nospawn: true,
},
},
},
jshint: {
all: ['lib/*.js'],
},
});
grunt.event.on('watch', function(action, filepath) {
grunt.config(['jshint', 'all'], filepath);
});
I have not tested example it self. But took this and applied to my copy task, unsuccessfully.
grunt-contrib-copy task set up to copy images and templates for my angular project. And I would be happy to know if I can make this work for copy task and if I can, what am I doing wrong.
Thank you so much.
Here is my stripped out Gruntfile.js.
// Build configurations.
module.exports = function(grunt){
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
// Copies directories and files from one location to another.
copy: {
// DEVELOPMENT
devTmpl: {
files: [{
cwd : 'src/tpl/',
src : ['**/*'],
dest : 'app/tpl/',
flatten : false,
expand : true
}]
},
devImg: {
files: [{
cwd : 'src/img/',
src : ['**/*'],
dest : 'app/img/',
flatten : false,
expand : true
}]
}
},
// Watch files for changes and run tasks
watch: {
// Templates, copy
templates: {
files : 'src/tpl/**/*',
tasks : ['copy:devTmpl'],
options: {
nospawn: true,
}
},
// Images, copy
images: {
files : 'src/img/**/*',
tasks : ['copy:devImg'],
options: {
nospawn: true,
}
}
}
});
// Watch events
grunt.event.on('watch', function(action, filepath) {
// configure copy:devTmpl to only run on changed file
grunt.config(['copy','devTmpl'], filepath);
// configure copy:devImg to only run on changed file
grunt.config(['copy','devImg'], filepath);
});
// PLUGINS:
grunt.loadNpmTasks('grunt-contrib-copy');
// TASKS:
/* DEV: Compiles the app with non-optimized build settings, places the build artifacts in the dist directory, and watches for file changes.
run: grunt dev */
grunt.registerTask('dev', 'Running "DEVELOPMENT", watching files and compiling...', [
'default',
'watch'
]);
/* DEFAULT: Compiles the app with non-optimized build settings and places the build artifacts in the dist directory.
run: grunt */
grunt.registerTask('default', 'Running "DEFAULT", compiling everything.', [
'copy:devTmpl',
'copy:devImg'
]);
}
Use grunt-sync (https://npmjs.org/package/grunt-sync) instead of grunt-contrib-copy, and watch the directories you want to be synced.
Update - here's an example:
grunt.initConfig({
sync: {
copy_resources_to_www: {
files: [
{ cwd: 'src', src: 'img/**', dest: 'www' },
{ cwd: 'src', src: 'res/**', dest: 'www' }
]
}
}
});
cwd means current working directory. copy_resources_to_www is just a label.
You need to point grunt.config to the correct property in your config:
grunt.event.on('watch', function(action, filepath) {
var cfgkey = ['copy', 'devTmpl', 'files'];
grunt.config.set(cfgkey, grunt.config.get(cfgkey).map(function(file) {
file.src = filepath;
return file;
}));
});
I have written a detailed example configuration file for synchronizing changed files in my projects. It runs automatically in any related project, and it can be updated to suit your specific needs.
Grunfile.js
module.exports = function (grunt) {
"use strict";
grunt.initConfig({
pkg: grunt.file.readJSON("package.json"),
sync: {
main: {
files: [
{
cwd: ".",
src: ["src/**", "LICENSE", "README.md"],
dest: "dist/<%= pkg.name%>/",
},
],
verbose: true,
pretend: false,
failOnError: true,
ignoreInDest: "**/.git/**",
updateAndDelete: true,
compareUsing: "md5",
},
}
});
grunt.util.linefeed = "\n";
};