Zum Inhalt

Grunt Cheatsheet

Grunt - Die JavaScript Task Runner

Grunt ist ein JavaScript-Task-Läufer, der repetitive Aufgaben wie Minification, Compilation, Unit Testing und Linting automatisiert. Es verwendet einen Konfiguration-over-Code-Ansatz mit einem riesigen Ökosystem von Plugins, um praktisch jede Aufgabe zu bewältigen. < p>

generieren

Inhaltsverzeichnis

Installation

Globale Installation

```bash

Install Grunt CLI globally

npm install -g grunt-cli

Verify installation

grunt --version ```_

Lokale Installation

```bash

Initialize npm project

npm init -y

Install Grunt locally

npm install --save-dev grunt

Install common plugins

npm install --save-dev grunt-contrib-uglify grunt-contrib-cssmin grunt-contrib-concat grunt-contrib-watch ```_

Projektaufbau

```bash

Create project structure

mkdir my-grunt-project cd my-grunt-project

Initialize package.json

npm init -y

Install Grunt and essential plugins

npm install --save-dev grunt grunt-contrib-uglify grunt-contrib-cssmin grunt-contrib-concat grunt-contrib-copy grunt-contrib-clean grunt-contrib-watch grunt-contrib-connect

Create Gruntfile

touch Gruntfile.js

Create source directories

mkdir -p src/{css,js,images,html} mkdir dist ```_

Paket.json Konfiguration

json { "name": "my-grunt-project", "version": "1.0.0", "description": "A Grunt-powered project", "scripts": { "build": "grunt build", "dev": "grunt dev", "watch": "grunt watch", "serve": "grunt serve", "test": "grunt test" }, "devDependencies": { "grunt": "^1.6.1", "grunt-contrib-uglify": "^5.2.2", "grunt-contrib-cssmin": "^4.0.0", "grunt-contrib-concat": "^2.1.0", "grunt-contrib-copy": "^1.0.0", "grunt-contrib-clean": "^2.0.1", "grunt-contrib-watch": "^1.1.0", "grunt-contrib-connect": "^3.0.0", "grunt-contrib-jshint": "^3.2.0", "grunt-sass": "^3.1.0" } }_

Erste Schritte

Basic Gruntfile

```javascript // Gruntfile.js module.exports = function(grunt) {

// Project configuration grunt.initConfig({ pkg: grunt.file.readJSON('package.json'),

// Concatenate files
concat: {
  js: {
    src: ['src/js/**/*.js'],
    dest: 'dist/js/bundle.js'
  },
  css: {
    src: ['src/css/**/*.css'],
    dest: 'dist/css/styles.css'
  }
},

// Minify JavaScript
uglify: {
  options: {
    banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
  },
  build: {
    src: 'dist/js/bundle.js',
    dest: 'dist/js/bundle.min.js'
  }
},

// Minify CSS
cssmin: {
  target: {
    files: {
      'dist/css/styles.min.css': ['dist/css/styles.css']
    }
  }
},

// Watch for changes
watch: {
  js: {
    files: ['src/js/**/*.js'],
    tasks: ['concat:js', 'uglify']
  },
  css: {
    files: ['src/css/**/*.css'],
    tasks: ['concat:css', 'cssmin']
  }
}

});

// Load plugins grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-cssmin'); grunt.loadNpmTasks('grunt-contrib-watch');

// Register tasks grunt.registerTask('default', ['concat', 'uglify', 'cssmin']); grunt.registerTask('build', ['concat', 'uglify', 'cssmin']); grunt.registerTask('dev', ['build', 'watch']); }; ```_

Aufgaben ausführen

```bash

Run default task

grunt

Run specific task

grunt uglify grunt cssmin

Run multiple tasks

grunt concat uglify

Run with options

grunt build --force grunt watch --verbose

List available tasks

grunt --help ```_

Projektstruktur

bash my-grunt-project/ ├── src/ │ ├── css/ │ │ ├── main.css │ │ └── components/ │ ├── js/ │ │ ├── main.js │ │ └── modules/ │ ├── images/ │ └── html/ ├── dist/ │ ├── css/ │ ├── js/ │ ├── images/ │ └── index.html ├── Gruntfile.js └── package.json_

Gruntfile Konfiguration

Konfigurationsstruktur

```javascript module.exports = function(grunt) { grunt.initConfig({ // Package information pkg: grunt.file.readJSON('package.json'),

// Global options
globalConfig: {
  src: 'src',
  dist: 'dist'
},

// Task configurations
taskName: {
  options: {
    // Global options for this task
  },
  target1: {
    options: {
      // Target-specific options
    },
    src: 'source/files',
    dest: 'destination/file'
  },
  target2: {
    // Another target configuration
  }
}

}); }; ```_

Erweiterte Konfiguration

```javascript module.exports = function(grunt) {

// Configuration grunt.initConfig({ pkg: grunt.file.readJSON('package.json'),

// Global configuration
config: {
  src: 'src',
  dist: 'dist',
  tmp: '.tmp'
},

// Clean task
clean: {
  dist: ['<%= config.dist %>'],
  tmp: ['<%= config.tmp %>']
},

// Copy task
copy: {
  html: {
    expand: true,
    cwd: '<%= config.src %>',
    src: '**/*.html',
    dest: '<%= config.dist %>'
  },
  images: {
    expand: true,
    cwd: '<%= config.src %>/images',
    src: '**/*',
    dest: '<%= config.dist %>/images'
  }
},

// Sass compilation
sass: {
  options: {
    implementation: require('sass'),
    sourceMap: true
  },
  dist: {
    files: {
      '<%= config.dist %>/css/main.css': '<%= config.src %>/scss/main.scss'
    }
  }
},

// PostCSS processing
postcss: {
  options: {
    processors: [
      require('autoprefixer')({browsers: 'last 2 versions'}),
      require('cssnano')()
    ]
  },
  dist: {
    src: '<%= config.dist %>/css/*.css'
  }
}

});

// Load plugins require('load-grunt-tasks')(grunt);

// Custom tasks grunt.registerTask('build', [ 'clean:dist', 'copy', 'sass', 'postcss', 'uglify', 'cssmin' ]);

grunt.registerTask('default', ['build']); }; ```_

Vorlagenbearbeitung

```javascript grunt.initConfig({ pkg: grunt.file.readJSON('package.json'),

// Using templates concat: { options: { banner: '/! <%= pkg.name %> - v<%= pkg.version %> - ' + '<%= grunt.template.today("yyyy-mm-dd") %> */\n' }, dist: { src: ['src/js/*/*.js'], dest: 'dist/js/<%= pkg.name %>.js' } },

// Dynamic file mapping uglify: { dynamic: { files: [{ expand: true, cwd: 'src/js/', src: '**/*.js', dest: 'dist/js/', ext: '.min.js' }] } } }); ```_

Kernaufgaben

Dateioperationen

```javascript // Clean files and directories clean: { build: ['dist/'], tmp: ['.tmp/'], css: ['dist/css//*.css'], js: ['dist/js//*.js'] }

// Copy files copy: { main: { files: [ // Copy all files from src to dist { expand: true, cwd: 'src/', src: [''], dest: 'dist/' }, // Copy specific files { expand: true, cwd: 'src/assets/', src: ['fonts/', 'images/**'], dest: 'dist/assets/' } ] },

// Copy with renaming rename: { files: [{ expand: true, cwd: 'src/', src: ['**/*.txt'], dest: 'dist/', ext: '.bak' }] } }

// Concatenate files concat: { options: { separator: ';', stripBanners: true, banner: '/! <%= pkg.name %> - v<%= pkg.version %> */\n' }, js: { src: [ 'src/js/vendor/.js', 'src/js/modules/.js', 'src/js/main.js' ], dest: 'dist/js/bundle.js' }, css: { src: ['src/css/**/.css'], dest: 'dist/css/styles.css' } } ```_

Datei filtern

```javascript // File filtering and processing copy: { filterFiles: { files: [{ expand: true, cwd: 'src/', src: ['**/*'], dest: 'dist/', filter: function(filepath) { // Only copy files modified in last 24 hours return (Date.now() - fs.statSync(filepath).mtime) < 24*60*60*1000; } }] } }

// Conditional file processing uglify: { conditional: { files: [{ expand: true, cwd: 'src/js/', src: ['**/*.js'], dest: 'dist/js/', ext: '.min.js', filter: function(filepath) { // Only minify files larger than 1KB return fs.statSync(filepath).size > 1024; } }] } } ```_

CSS Aufgaben

Sass Compilation

```javascript // Sass compilation sass: { options: { implementation: require('sass'), sourceMap: true, outputStyle: 'expanded' },

// Development build dev: { options: { sourceMap: true, outputStyle: 'expanded' }, files: { 'dist/css/main.css': 'src/scss/main.scss' } },

// Production build prod: { options: { sourceMap: false, outputStyle: 'compressed' }, files: { 'dist/css/main.min.css': 'src/scss/main.scss' } },

// Multiple files multiple: { files: [{ expand: true, cwd: 'src/scss/', src: ['*.scss'], dest: 'dist/css/', ext: '.css' }] } }

// Less compilation less: { development: { options: { paths: ['src/less/includes'] }, files: { 'dist/css/main.css': 'src/less/main.less' } },

production: { options: { paths: ['src/less/includes'], cleancss: true, modifyVars: { imgPath: '"http://mycdn.com/path/to/images"', bgColor: 'red' } }, files: { 'dist/css/main.min.css': 'src/less/main.less' } } } ```_

CSS Verarbeitung

```javascript // CSS minification cssmin: { options: { mergeIntoShorthands: false, roundingPrecision: -1 }, target: { files: { 'dist/css/main.min.css': ['src/css/**/*.css'] } },

// Multiple targets multiple: { files: [{ expand: true, cwd: 'src/css/', src: ['.css', '!.min.css'], dest: 'dist/css/', ext: '.min.css' }] } }

// Autoprefixer autoprefixer: { options: { browsers: ['last 2 versions', 'ie 8', 'ie 9'] }, single_file: { src: 'dist/css/main.css', dest: 'dist/css/main.prefixed.css' }, multiple_files: { expand: true, flatten: true, src: 'dist/css/*.css', dest: 'dist/css/prefixed/' } }

// PostCSS postcss: { options: { map: true, processors: [ require('pixrem')(), require('autoprefixer')({browsers: 'last 2 versions'}), require('cssnano')() ] }, dist: { src: 'dist/css/*.css' } } ```_

CSS Futter

```javascript // CSS Lint csslint: { options: { csslintrc: '.csslintrc' }, strict: { options: { import: 2 }, src: ['src/css//*.css'] }, lax: { options: { import: false }, src: ['src/css//*.css'] } }

// Stylelint stylelint: { all: ['src/css/**/*.css'], options: { configFile: '.stylelintrc', formatter: 'string', ignoreDisables: false, failOnError: true, outputFile: '', reportNeedlessDisables: false, syntax: '' } } ```_

JavaScript Aufgaben

JavaScript Mining

```javascript // UglifyJS uglify: { options: { banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n', mangle: { reserved: ['jQuery', '$'] }, compress: { drop_console: true } },

// Single file single: { src: 'src/js/main.js', dest: 'dist/js/main.min.js' },

// Multiple files multiple: { files: [{ expand: true, cwd: 'src/js/', src: '**/*.js', dest: 'dist/js/', ext: '.min.js' }] },

// With source maps sourcemap: { options: { sourceMap: true, sourceMapName: 'dist/js/main.min.js.map' }, src: 'src/js/main.js', dest: 'dist/js/main.min.js' } }

// Terser (ES6+ minification) terser: { options: { ecma: 2015, compress: { drop_console: true }, output: { comments: false } }, main: { files: { 'dist/js/main.min.js': ['src/js/main.js'] } } } ```_

JavaScript Transpilation

```javascript // Babel transpilation babel: { options: { sourceMap: true, presets: ['@babel/preset-env'] }, dist: { files: [{ expand: true, cwd: 'src/js/', src: ['**/*.js'], dest: 'dist/js/', ext: '.js' }] } }

// TypeScript compilation typescript: { base: { src: ['src/ts/**/*.ts'], dest: 'dist/js/app.js', options: { module: 'amd', target: 'es5', sourceMap: true, declaration: true } } }

// CoffeeScript compilation coffee: { compile: { files: { 'dist/js/app.js': 'src/coffee/app.coffee' } },

multiple: { expand: true, flatten: true, cwd: 'src/coffee/', src: ['*.coffee'], dest: 'dist/js/', ext: '.js' } } ```_

JavaScript Futter

```javascript // JSHint jshint: { options: { curly: true, eqeqeq: true, eqnull: true, browser: true, globals: { jQuery: true } }, uses_defaults: ['src/js/**/*.js'], with_overrides: { options: { curly: false, undef: true }, files: { src: ['src/js/specific.js'] } } }

// ESLint eslint: { options: { configFile: '.eslintrc.js', rulePaths: ['conf/rules'] }, target: ['src/js/**/*.js'] }

// JSLint jslint: { client: { src: ['src/js/**/*.js'], directives: { browser: true, predef: ['jQuery'] } } } ```_

Browser-Integration

```javascript browserify: { dist: { files: { 'dist/js/bundle.js': ['src/js/main.js'] }, options: { transform: [['babelify', {presets: ['@babel/preset-env']}]] } },

// With external libraries vendor: { src: [], dest: 'dist/js/vendor.js', options: { require: ['jquery', 'underscore'] } },

app: { src: ['src/js/main.js'], dest: 'dist/js/app.js', options: { external: ['jquery', 'underscore'] } } }

// Webpack integration webpack: { options: { entry: './src/js/main.js', output: { path: 'dist/js/', filename: 'bundle.js' }, module: { rules: [{ test: /.js$/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } }] } }, dev: { mode: 'development', devtool: 'source-map' }, prod: { mode: 'production' } } ```_

Bildbearbeitung

Bildoptimierung

```javascript // Image minification imagemin: { dynamic: { files: [{ expand: true, cwd: 'src/images/', src: ['**/*.{png,jpg,gif,svg}'], dest: 'dist/images/' }] },

// With options options: { optimizationLevel: 3, svgoPlugins: [{removeViewBox: false}], use: [mozjpeg({quality: 80})] } }

// Responsive images responsive_images: { dev: { options: { engine: 'im', sizes: [{ width: 320, suffix: '_small', quality: 80 }, { width: 640, suffix: '_medium', quality: 80 }, { width: 1024, suffix: '_large', quality: 80 }] }, files: [{ expand: true, src: ['src/images/**/*.{jpg,gif,png}'], cwd: 'src/', dest: 'dist/' }] } }

// WebP conversion webp: { files: { expand: true, cwd: 'src/images/', src: ['**/*.{png,jpg,jpeg}'], dest: 'dist/images/webp/', ext: '.webp' }, options: { binpath: require('webp-bin'), preset: 'photo', verbose: true, quality: 80, alphaQuality: 80, compressionMethod: 6, segments: 4, psnr: 42, sns: 50, filterStrength: 40, filterSharpness: 3, simpleFilter: true, partitionLimit: 50, analysisPass: 6, multiThreading: true, lowMemory: false, alphaMethod: 0, alphaFilter: 'best', alphaCleanup: true, noAlpha: false, lossless: false } } ```_

Sprite Generation

```javascript // CSS Sprites sprite: { all: { src: 'src/images/icons/*.png', dest: 'dist/images/spritesheet.png', destCss: 'dist/css/sprites.css', cssFormat: 'css', algorithm: 'binary-tree', padding: 2 } }

// SVG Sprites svgstore: { options: { prefix: 'icon-', svg: { viewBox: '0 0 100 100', xmlns: 'http://www.w3.org/2000/svg' } }, default: { files: { 'dist/images/icons.svg': ['src/images/icons/*.svg'] } } }

// Icon fonts webfont: { icons: { src: 'src/images/icons/*.svg', dest: 'dist/fonts/', destCss: 'dist/css/', options: { font: 'icons', types: 'eot,woff,woff2,ttf,svg', syntax: 'bem', engine: 'node', autoHint: false, execMaxBuffer: 1024 * 200, htmlDemo: true, destHtml: 'dist/' } } } ```_

HTML Aufgaben

HTML Processing

```javascript // HTML minification htmlmin: { dist: { options: { removeComments: true, collapseWhitespace: true, removeRedundantAttributes: true, removeScriptTypeAttributes: true, removeStyleLinkTypeAttributes: true, minifyJS: true, minifyCSS: true }, files: [{ expand: true, cwd: 'src/', src: ['**/*.html'], dest: 'dist/' }] } }

// HTML includes includes: { files: { src: ['src/pages/*.html'], dest: 'dist/', flatten: true, cwd: '.', options: { silent: true, includePath: 'src/includes/' } } }

// Template processing template: { dev: { options: { data: { title: 'Development Site', version: '<%= pkg.version %>', timestamp: '<%= grunt.template.today() %>' } }, files: [{ expand: true, cwd: 'src/templates/', src: ['**/*.html'], dest: 'dist/' }] } } ```_

HTML Validierung

```javascript // HTML validation htmlhint: { build: { options: { 'tag-pair': true, 'tagname-lowercase': true, 'attr-lowercase': true, 'attr-value-double-quotes': true, 'doctype-first': true, 'spec-char-escape': true, 'id-unique': true, 'head-script-disabled': true, 'style-disabled': true }, src: ['dist/**/*.html'] } }

// W3C validation validation: { options: { reset: grunt.option('reset') || false, stoponerror: false, remotePath: 'http://localhost:9001/', remoteFiles: ['index.html', 'about.html'], relaxerror: ['Bad value X-UA-Compatible for attribute http-equiv on element meta.'] }, files: { src: ['dist/**/*.html'] } } ```_

Entwicklungsserver

Server herunterladen

```javascript // Basic server connect: { server: { options: { port: 9000, hostname: 'localhost', base: 'dist', open: true } } }

// Advanced server configuration connect: { options: { port: 9000, hostname: 'localhost', livereload: 35729 },

livereload: { options: { open: true, middleware: function(connect) { return [ connect.static('.tmp'), connect().use('/bower_components', connect.static('./bower_components')), connect.static('src') ]; } } },

test: { options: { port: 9001, middleware: function(connect) { return [ connect.static('.tmp'), connect.static('test'), connect().use('/bower_components', connect.static('./bower_components')), connect.static('src') ]; } } },

dist: { options: { open: true, base: 'dist' } } }

// Proxy server connect: { proxies: [{ context: '/api', host: 'localhost', port: 3000, https: false, xforward: false, headers: { 'x-custom-added-header': 'value' }, hideHeaders: ['x-removed-header'] }],

server: { options: { port: 9000, middleware: function(connect, options) { var middlewares = []; var directory = options.directory || options.base[options.base.length - 1];

    // Setup the proxy
    middlewares.push(require('grunt-connect-proxy/lib/utils').proxyRequest);

    // Serve static files
    if (!Array.isArray(options.base)) {
      options.base = [options.base];
    }
    options.base.forEach(function(base) {
      middlewares.push(connect.static(base));
    });

    // Make directory browse-able
    middlewares.push(connect.directory(directory));

    return middlewares;
  }
}

} } ```_

Live Reload

```javascript // Live reload configuration watch: { options: { livereload: true },

html: { files: ['src/**/*.html'], tasks: ['includes', 'htmlmin'] },

css: { files: ['src/css/**/*.css'], tasks: ['concat:css', 'cssmin'] },

js: { files: ['src/js/**/*.js'], tasks: ['jshint', 'concat:js', 'uglify'] },

livereload: { options: { livereload: '<%= connect.options.livereload %>' }, files: [ 'dist//*.html', 'dist/css//.css', 'dist/js/**/.js', 'dist/images/**/*.{png,jpg,jpeg,gif,webp,svg}' ] } }

// Browser Sync integration browserSync: { dev: { bsFiles: { src: [ 'dist/css/.css', 'dist/js/.js', 'dist/*.html' ] }, options: { watchTask: true, server: './dist' } } } ```_

Aufgaben ansehen

Basic Watch Konfiguration

```javascript watch: { // Watch CSS files css: { files: ['src/css/**/*.css'], tasks: ['concat:css', 'cssmin'], options: { spawn: false } },

// Watch JavaScript files js: { files: ['src/js/**/*.js'], tasks: ['jshint', 'concat:js', 'uglify'], options: { spawn: false } },

// Watch Sass files sass: { files: ['src/scss/**/*.scss'], tasks: ['sass', 'autoprefixer', 'cssmin'] },

// Watch HTML files html: { files: ['src/**/*.html'], tasks: ['includes', 'htmlmin'] },

// Watch images images: { files: ['src/images/**/*.{png,jpg,gif,svg}'], tasks: ['imagemin'] } } ```_

Erweiterte Uhrenmuster

```javascript watch: { options: { spawn: false, livereload: true },

// Conditional tasks based on file changes configFiles: { files: ['Gruntfile.js', 'package.json'], options: { reload: true } },

// Watch with different intervals slow: { files: ['src/large-files/**/*'], tasks: ['process-large-files'], options: { interval: 5000 } },

// Watch with custom event handling custom: { files: ['src/special/**/*'], tasks: [], options: { event: ['added', 'deleted'] } } }

// Dynamic watch configuration grunt.event.on('watch', function(action, filepath, target) { if (target === 'js') { // Only process the changed file grunt.config('jshint.single.src', filepath); grunt.config('uglify.single.src', filepath); grunt.config('uglify.single.dest', filepath.replace('src/', 'dist/').replace('.js', '.min.js')); } }); ```_

Uhr mit Fehlerbehandlung

```javascript watch: { options: { spawn: false, interrupt: true },

sass: { files: ['src/scss/**/*.scss'], tasks: ['sass'], options: { spawn: false, interrupt: true, event: ['added', 'deleted', 'changed'] } } }

// Error handling in tasks grunt.registerTask('safe-sass', function() { try { grunt.task.run('sass'); } catch (e) { grunt.log.error('Sass compilation failed: ' + e.message); grunt.fail.warn('Sass task failed, but continuing...'); } }); ```_

Pipeline erstellen

Entwicklung

```javascript // Development build pipeline grunt.registerTask('dev', [ 'clean:dist', 'jshint', 'sass:dev', 'autoprefixer', 'concat', 'copy:dev', 'includes', 'connect:livereload', 'watch' ]);

// Development build without server grunt.registerTask('build-dev', [ 'clean:dist', 'jshint', 'sass:dev', 'autoprefixer', 'concat', 'copy:dev', 'includes' ]); ```_

Produktionsaufbau

```javascript // Production build pipeline grunt.registerTask('build', [ 'clean:dist', 'jshint', 'sass:prod', 'autoprefixer', 'cssmin', 'concat', 'uglify', 'imagemin', 'copy:prod', 'includes', 'htmlmin', 'rev', 'usemin' ]);

// Build with testing grunt.registerTask('test-build', [ 'build', 'connect:test', 'qunit' ]);

// Complete production pipeline grunt.registerTask('production', [ 'build', 'test-build', 'compress', 'deploy' ]); ```_

Multi-Umwelt baut

```javascript // Environment-specific configurations grunt.initConfig({ env: { dev: { NODE_ENV: 'development' }, prod: { NODE_ENV: 'production' } },

// Conditional configuration uglify: { options: { compress: { drop_console: '<%= process.env.NODE_ENV === "production" %>' } }, build: { src: 'dist/js/bundle.js', dest: 'dist/js/bundle.min.js' } } });

// Environment-specific tasks grunt.registerTask('build-dev', ['env:dev', 'build-common']); grunt.registerTask('build-prod', ['env:prod', 'build-common']); grunt.registerTask('build-common', [ 'clean', 'sass', 'concat', 'uglify', 'copy' ]); ```_

Plugin Ecosystem

Grundlegende Plugins

```bash

File operations

npm install --save-dev grunt-contrib-clean grunt-contrib-copy grunt-contrib-concat

CSS processing

npm install --save-dev grunt-sass grunt-contrib-cssmin grunt-autoprefixer

JavaScript processing

npm install --save-dev grunt-contrib-uglify grunt-contrib-jshint grunt-babel

HTML processing

npm install --save-dev grunt-contrib-htmlmin grunt-includes

Image processing

npm install --save-dev grunt-contrib-imagemin grunt-responsive-images

Development

npm install --save-dev grunt-contrib-watch grunt-contrib-connect grunt-browser-sync

Build tools

npm install --save-dev grunt-usemin grunt-rev grunt-filerev ```_

Erweiterte Plugins

```javascript // File revisioning rev: { files: { src: ['dist/js//*.js', 'dist/css//*.css'] } }

// Asset injection usemin: { html: ['dist/**/*.html'], options: { assetsDirs: ['dist', 'dist/images'] } }

// Compression compress: { main: { options: { archive: 'dist.zip' }, files: [{ expand: true, cwd: 'dist/', src: ['**/*'], dest: '.' }] } }

// FTP deployment 'ftp-deploy': { build: { auth: { host: 'server.com', port: 21, authKey: 'key1' }, src: 'dist', dest: '/public_html', exclusions: ['dist//.DS_Store', 'dist//Thumbs.db'] } } ```_

Plugin geladen

```javascript // Load all grunt plugins require('load-grunt-tasks')(grunt);

// Load specific plugins grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-cssmin');

// Load plugins with pattern require('load-grunt-tasks')(grunt, { pattern: ['grunt-*', '!grunt-legacy-util'] });

// Load plugins from different locations grunt.loadTasks('custom-tasks'); ```_

Kundenspezifische Aufgaben

Grundlegende kundenspezifische Aufgaben

```javascript // Simple custom task grunt.registerTask('hello', 'Say hello', function() { grunt.log.writeln('Hello, World!'); });

// Task with parameters grunt.registerTask('greet', 'Greet someone', function(name) { if (!name) { grunt.log.writeln('Hello, stranger!'); } else { grunt.log.writeln('Hello, ' + name + '!'); } });

// Multi-task grunt.registerMultiTask('log', 'Log stuff', function() { grunt.log.writeln(this.target + ': ' + this.data); });

grunt.initConfig({ log: { foo: 'Hello', bar: 'World' } }); ```_

Erweiterte benutzerdefinierte Aufgaben

```javascript // Async task grunt.registerTask('async-task', 'An async task', function() { var done = this.async();

setTimeout(function() { grunt.log.writeln('Async task completed!'); done(); }, 1000); });

// Task with options grunt.registerTask('custom-build', function() { var options = this.options({ minify: true, sourcemap: false });

if (options.minify) { grunt.task.run('uglify'); }

if (options.sourcemap) { grunt.task.run('sourcemap'); } });

// File processing task grunt.registerMultiTask('process-files', function() { var options = this.options({ separator: '\n' });

this.files.forEach(function(file) { var src = file.src.filter(function(filepath) { if (!grunt.file.exists(filepath)) { grunt.log.warn('Source file "' + filepath + '" not found.'); return false; } else { return true; } }).map(function(filepath) { return grunt.file.read(filepath); }).join(options.separator);

grunt.file.write(file.dest, src);
grunt.log.writeln('File "' + file.dest + '" created.');

}); }); ```_

Aufgabenabhängigkeiten

```javascript // Task with dependencies grunt.registerTask('build-all', [ 'clean', 'jshint', 'sass', 'concat', 'uglify', 'cssmin' ]);

// Conditional task execution grunt.registerTask('conditional-build', function() { if (grunt.option('production')) { grunt.task.run(['build-prod']); } else { grunt.task.run(['build-dev']); } });

// Dynamic task creation grunt.registerTask('create-tasks', function() { var files = grunt.file.expand('src/modules/*.js');

files.forEach(function(file) { var taskName = 'process-' + path.basename(file, '.js');

grunt.registerTask(taskName, function() {
  // Process individual file
  grunt.log.writeln('Processing: ' + file);
});

}); }); ```_

Multi-Ziel Aufgaben

Konfiguration

```javascript grunt.initConfig({ // Multi-target task configuration uglify: { options: { banner: '/*! Global banner */\n' },

// Target 1: Main application
app: {
  options: {
    banner: '/*! App banner */\n'
  },
  src: 'src/js/app.js',
  dest: 'dist/js/app.min.js'
},

// Target 2: Vendor libraries
vendor: {
  src: ['src/js/vendor/*.js'],
  dest: 'dist/js/vendor.min.js'
},

// Target 3: Dynamic files
dynamic: {
  files: [{
    expand: true,
    cwd: 'src/js/',
    src: '**/*.js',
    dest: 'dist/js/',
    ext: '.min.js'
  }]
}

} });

// Run specific targets // grunt uglify:app // grunt uglify:vendor // grunt uglify (runs all targets) ```_

Kundenspezifisches Multi-Ziel Aufgaben

```javascript grunt.registerMultiTask('custom-process', 'Process files', function() { var options = this.options({ prefix: '', suffix: '' });

grunt.log.writeln('Processing target: ' + this.target);

this.files.forEach(function(file) { var contents = file.src.map(function(src) { return grunt.file.read(src); }).join('\n');

var processed = options.prefix + contents + options.suffix;

grunt.file.write(file.dest, processed);
grunt.log.writeln('Created: ' + file.dest);

}); });

grunt.initConfig({ 'custom-process': { options: { prefix: '/* Global prefix */\n' },

css: {
  options: {
    suffix: '\n/* CSS suffix */'
  },
  files: {
    'dist/css/processed.css': ['src/css/**/*.css']
  }
},

js: {
  options: {
    suffix: '\n/* JS suffix */'
  },
  files: {
    'dist/js/processed.js': ['src/js/**/*.js']
  }
}

} }); ```_

Vorlagenbearbeitung

Eingebaute Vorlagen

```javascript grunt.initConfig({ pkg: grunt.file.readJSON('package.json'),

// Using package.json data concat: { options: { banner: '/! <%= pkg.name %> - v<%= pkg.version %> - ' + '<%= grunt.template.today("yyyy-mm-dd") %> */\n' }, dist: { src: ['src/js/*/*.js'], dest: 'dist/js/<%= pkg.name %>.js' } },

// Date templates copy: { timestamped: { src: 'src/config.js', dest: 'dist/config-<%= grunt.template.today("yyyymmdd") %>.js' } } }); ```_

Benutzerdefinierte Vorlagen

```javascript // Custom template data grunt.initConfig({ config: { app: { name: 'MyApp', version: '1.0.0', author: 'John Doe' }, build: { timestamp: '<%= grunt.template.today("isoDateTime") %>', environment: process.env.NODE_ENV || 'development' } },

// Using custom data replace: { config: { src: ['src/js/config.js'], dest: 'dist/js/config.js', replacements: [{ from: '{{APP_NAME}}', to: '<%= config.app.name %>' }, { from: '{{VERSION}}', to: '<%= config.app.version %>' }, { from: '{{BUILD_TIME}}', to: '<%= config.build.timestamp %>' }] } } });

// Template processing task grunt.registerTask('process-templates', function() { var config = grunt.config('config');

grunt.file.expand('src/templates/**/*.html').forEach(function(file) { var content = grunt.file.read(file); var processed = grunt.template.process(content, { data: config });

var dest = file.replace('src/templates/', 'dist/');
grunt.file.write(dest, processed);

}); }); ```_

Integration testen

Einheitsprüfung

```javascript // QUnit qunit: { files: ['test/**/*.html'] }

// Mocha mocha: { test: { src: ['test/**/*.html'], options: { run: true, reporter: 'Spec' } } }

// Jasmine jasmine: { src: 'src/js//*.js', options: { specs: 'test/spec//.js', helpers: 'test/helpers/**/.js' } }

// Karma karma: { unit: { configFile: 'karma.conf.js' }, continuous: { configFile: 'karma.conf.js', singleRun: true, browsers: ['PhantomJS'] } } ```_

Code Coverage

```javascript // Istanbul coverage instrument: { files: 'src/js/**/*.js', options: { lazy: true, basePath: 'instrumented/' } }

storeCoverage: { options: { dir: 'coverage/' } }

makeReport: { src: 'coverage/**/*.json', options: { type: 'lcov', dir: 'coverage/', print: 'detail' } }

// Coverage task grunt.registerTask('coverage', [ 'clean:coverage', 'instrument', 'qunit', 'storeCoverage', 'makeReport' ]); ```_

End-to-End-Test

```javascript // Protractor protractor: { options: { configFile: 'protractor.conf.js', keepAlive: true, noColor: false }, e2e: { options: { args: { suite: 'e2e' } } } }

// WebDriver webdriver: { chrome: { tests: ['test/e2e/**/*.js'], options: { timeout: 10000, reporter: 'spec', browser: 'chrome' } } }

// Nightwatch nightwatch: { options: { standalone: true, jar_version: '2.53.0', jar_url: 'http://selenium-release.storage.googleapis.com/2.53/selenium-server-standalone-2.53.0.jar' } } ```_

Bereitstellung

Aufbau und Bereitstellung

```javascript // Build for deployment grunt.registerTask('deploy-build', [ 'clean', 'jshint', 'test', 'sass:prod', 'autoprefixer', 'cssmin', 'concat', 'uglify', 'imagemin', 'htmlmin', 'rev', 'usemin' ]);

// FTP deployment 'ftp-deploy': { production: { auth: { host: 'ftp.example.com', port: 21, authKey: 'production' }, src: 'dist/', dest: '/public_html/', exclusions: [ 'dist//.DS_Store', 'dist//Thumbs.db', 'dist/tmp' ] } }

// SFTP deployment sftp: { production: { files: { './': 'dist/**' }, options: { path: '/var/www/html/', host: 'example.com', username: 'deploy', privateKey: grunt.file.read('deploy_key'), showProgress: true } } } ```_

Git Bereitstellung

```javascript // Git deployment 'gh-pages': { options: { base: 'dist' }, src: ['**'] }

// Git push gitpush: { production: { options: { remote: 'production', branch: 'master' } } }

// Complete deployment pipeline grunt.registerTask('deploy', [ 'deploy-build', 'ftp-deploy:production' ]);

grunt.registerTask('deploy-github', [ 'deploy-build', 'gh-pages' ]); ```_

Einsatz von Docker

```javascript // Docker build shell: { docker_build: { command: 'docker build -t myapp:latest .' },

docker_push: { command: 'docker push myapp:latest' },

docker_deploy: { command: 'docker run -d -p 80:80 myapp:latest' } }

// Docker deployment task grunt.registerTask('deploy-docker', [ 'deploy-build', 'shell:docker_build', 'shell:docker_push', 'shell:docker_deploy' ]); ```_

Leistungsoptimierung

Parallele Verarbeitung

```javascript // Concurrent task execution concurrent: { dev: ['sass', 'coffee', 'jshint'], prod: ['cssmin', 'uglify', 'imagemin'], options: { logConcurrentOutput: true } }

// Use in build pipeline grunt.registerTask('build-fast', [ 'clean', 'concurrent:dev', 'concat', 'concurrent:prod' ]); ```_

Incremental Builds

```javascript // Newer files only newer: { options: { cache: '.grunt/newer' } }

// Use with tasks grunt.registerTask('build-incremental', [ 'newer:jshint', 'newer:sass', 'newer:imagemin' ]);

// Watch with newer watch: { js: { files: ['src/js/**/*.js'], tasks: ['newer:jshint', 'newer:uglify'] } } ```_

Caching

```javascript // Cache configuration cache: { options: { cache: '.grunt/cache' } }

// Cached image processing imagemin: { dynamic: { files: [{ expand: true, cwd: 'src/images/', src: ['**/*.{png,jpg,gif}'], dest: 'dist/images/' }] }, options: { cache: false // Disable cache for this task } } ```_

Best Practices

Projektorganisation

```javascript // Organized Gruntfile structure module.exports = function(grunt) {

// Time how long tasks take require('time-grunt')(grunt);

// Load all grunt tasks matching the ['grunt-', '@/grunt-*'] patterns require('load-grunt-tasks')(grunt);

// Configurable paths var config = { src: 'src', dist: 'dist', tmp: '.tmp' };

grunt.initConfig({ // Reference the config config: config,

// Load package.json
pkg: grunt.file.readJSON('package.json'),

// Task configurations
// ... (organized by type)

});

// Custom tasks grunt.registerTask('serve', function(target) { if (target === 'dist') { return grunt.task.run(['build', 'connect:dist:keepalive']); }

grunt.task.run([
  'clean:server',
  'concurrent:server',
  'autoprefixer',
  'connect:livereload',
  'watch'
]);

});

grunt.registerTask('build', [ 'clean:dist', 'useminPrepare', 'concurrent:dist', 'autoprefixer', 'concat', 'cssmin', 'uglify', 'copy:dist', 'rev', 'usemin', 'htmlmin' ]);

grunt.registerTask('default', [ 'newer:jshint', 'test', 'build' ]); }; ```_

Konfigurationsmanagement

```javascript // External configuration var config = require('./grunt.config.js');

grunt.initConfig(config);

// Environment-specific configs var env = process.env.NODE_ENV || 'development'; var config = require('./config/' + env + '.js');

// Modular configuration grunt.initConfig({ // Load task configs sass: require('./grunt/sass.js'), uglify: require('./grunt/uglify.js'), watch: require('./grunt/watch.js') }); ```_

Fehlerbehebung

```javascript // Graceful error handling grunt.option('force', true); // Continue on errors

// Custom error handling grunt.registerTask('safe-build', function() { try { grunt.task.run(['jshint', 'sass', 'uglify']); } catch (e) { grunt.log.error('Build failed: ' + e.message); grunt.fail.warn('Build task failed, but continuing...'); } });

// Conditional error handling grunt.registerTask('conditional-fail', function() { if (grunt.option('strict')) { grunt.fail.fatal('Strict mode enabled, failing on any error'); } }); ```_

Performance Best Practices

  • **Diese gleichzeitigen Aufgaben* für unabhängige Operationen
  • **Inkrementelle Builds implementieren* mit grunt-newer_
  • **Cache teure Operationen* nach Möglichkeit
  • Optimieren Sie die Uhrmuster, um unnötige Umbauten zu vermeiden
  • Benutzen spawn: false* in Uhrenaufgaben für schnellere Neuaufbauten

Best Practices der Wartung

  • **Keep Plugins aktualisiert* regelmäßig
  • ** Verwenden Sie semantische Versionierung* für Ihre Builds
  • Dokumentieren Sie Ihre Aufgaben und Konfiguration
  • **Implementieren Sie die richtige Fehlerbehandlung* *
  • Umgebungsvariablen für sensible Daten
  • ** Modulare Konfigurationsdateien erstellen* *
  • Monitor Bauleistung mit time-grunt_

--

Zusammenfassung

Grunt ist ein leistungsfähiger JavaScript-Task-Läufer, der bei der Automatisierung repetitiver Entwicklungsaufgaben durch Konfiguration übertrifft. Zu den wichtigsten Merkmalen gehören:

  • **Configuration-driven*: JSON-basierte Konfiguration für einfaches Setup
  • **Extensive Plugin Ecosystem*: Tausende von Plugins für jede Aufgabe
  • **Mehrzweck Aufgaben*: Führen Sie verschiedene Konfigurationen für dieselbe Aufgabe aus
  • Template System: Dynamische Konfiguration mit Vorlagen
  • **File Processing*: Leistungsstarke Datei-Globing- und Verarbeitungsfunktionen
  • **Watch und Live Reload*: Automatische Task-Ausführung bei Dateiänderungen
  • **Kundenspezifische Aufgaben*: Einfache Erstellung von Sonderaufgaben und Workflows
  • **Mature Ecosystem*: Mit umfangreichen Dokumentationen etabliert

Durch die Verwendung von Grunts konfigurationsgetriebenem Ansatz und riesigem Plugin-Ökosystem können Sie robuste, pflegefähige Build-Prozesse erstellen, die alles von einfacher Dateikonsultation bis hin zu komplexen Bereitstellungspipelines verarbeiten.

<= <= <= <================================================================================= Funktion copyToClipboard() {\cHFFFF} const commands = document.querySelectorAll('code'); alle Befehle = ''; Befehle. Für jede(cmd) => alle Befehle += cmd.textContent + '\n'); navigator.clipboard.writeText (allCommands); Alarm ('Alle Befehle, die in die Zwischenablage kopiert werden!'); }

Funktion generierenPDF() { Fenster.print(); }