Aller au contenu

Feuilles de caillebotis

Gulp - Le système de construction de flux

Gulp est une boîte à outils pour automatiser les tâches douloureuses ou longues dans votre workflow de développement, afin que vous puissiez arrêter de vous ennuyer et construire quelque chose. Il utilise les flux Node.js, rendant les constructions plus rapides en évitant la nécessité d'écrire des fichiers temporaires sur le disque.

Copier toutes les commandes Générer PDF

Sommaire

  • [Installation] (#installation)
  • [Pour commencer] (#getting-started)
  • [Concepts de base] (#core-concepts)
  • [Tâches de base] (#basic-tasks)
  • [Exploitation des dossiers] (#file-operations)
  • [Traitement du SSC] (#css-processing)
  • [Traitement JavaScript] (#javascript-processing)
  • [Optimisation de l'image] (#image-optimization)
  • [Traitement HTML] (#html-processing)
  • Serveur de développement
  • [Tâches de surveillance] (#watch-tasks)
  • [Compagnie de construction] (#build-pipeline)
  • [Écosystà ̈me de Plugin] (#plugin-ecosystem)
  • [Plans avancés] (#advanced-patterns)
  • [Optimisation du rendement] (#performance-optimization)
  • [Manipulation d'erreurs] (#error-handling)
  • [Tests] (#testing)
  • [Déploiement] (#deployment)
  • [Meilleures pratiques] (#best-practices)

Installation

Installation mondiale

# Install Gulp CLI globally
npm install -g gulp-cli

# Verify installation
gulp --version

Installation locale

# Initialize npm project
npm init -y

# Install Gulp locally
npm install --save-dev gulp

# Install common plugins
npm install --save-dev gulp-sass gulp-uglify gulp-concat gulp-clean-css
```_

### Configuration du projet
```bash
# Create project structure
mkdir my-gulp-project
cd my-gulp-project

# Initialize package.json
npm init -y

# Install Gulp and plugins
npm install --save-dev gulp gulp-sass gulp-autoprefixer gulp-clean-css gulp-uglify gulp-concat gulp-imagemin gulp-htmlmin

# Create gulpfile
touch gulpfile.js

# Create source directories
mkdir -p src/{scss,js,images,html}
mkdir dist
```_

### Paquet.json Scripts
```json
{
  "name": "my-gulp-project",
  "version": "1.0.0",
  "scripts": {
    "build": "gulp build",
    "dev": "gulp dev",
    "watch": "gulp watch",
    "clean": "gulp clean",
    "serve": "gulp serve"
  },
  "devDependencies": {
    "gulp": "^4.0.2",
    "gulp-sass": "^5.1.0",
    "gulp-autoprefixer": "^8.0.0",
    "gulp-clean-css": "^4.3.0",
    "gulp-uglify": "^3.0.2",
    "gulp-concat": "^2.6.1",
    "gulp-imagemin": "^8.0.0",
    "gulp-htmlmin": "^5.0.1"
  }
}

Commencer

Gulpfile de base

// gulpfile.js
const gulp = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const cleanCSS = require('gulp-clean-css');
const uglify = require('gulp-uglify');
const concat = require('gulp-concat');

// Define paths
const paths = {
  styles: {
    src: 'src/scss/**/*.scss',
    dest: 'dist/css/'
  },
  scripts: {
    src: 'src/js/**/*.js',
    dest: 'dist/js/'
  }
};

// Compile Sass
function styles() {
  return gulp.src(paths.styles.src)
    .pipe(sass().on('error', sass.logError))
    .pipe(cleanCSS())
    .pipe(gulp.dest(paths.styles.dest));
}

// Process JavaScript
function scripts() {
  return gulp.src(paths.scripts.src)
    .pipe(concat('main.js'))
    .pipe(uglify())
    .pipe(gulp.dest(paths.scripts.dest));
}

// Watch files
function watch() {
  gulp.watch(paths.styles.src, styles);
  gulp.watch(paths.scripts.src, scripts);
}

// Export tasks
exports.styles = styles;
exports.scripts = scripts;
exports.watch = watch;
exports.build = gulp.parallel(styles, scripts);
exports.default = gulp.series(exports.build, watch);

Tâches d'exécution

# Run individual tasks
gulp styles
gulp scripts

# Run build task
gulp build

# Run default task (build + watch)
gulp

# Run with specific gulpfile
gulp --gulpfile custom.gulpfile.js

# List available tasks
gulp --tasks

Structure du projet

my-gulp-project/
├── src/
   ├── scss/
      ├── main.scss
      ├── _variables.scss
      └── components/
   ├── js/
      ├── main.js
      └── modules/
   ├── images/
   └── html/
├── dist/
   ├── css/
   ├── js/
   ├── images/
   └── index.html
├── gulpfile.js
└── package.json

Concepts fondamentaux

Courroies et tuyaux

// Basic stream example
gulp.src('src/**/*.js')        // Read files
  .pipe(uglify())              // Transform
  .pipe(gulp.dest('dist/'));   // Write files

// Multiple transformations
gulp.src('src/scss/**/*.scss')
  .pipe(sass())                // Compile Sass
  .pipe(autoprefixer())        // Add vendor prefixes
  .pipe(cleanCSS())           // Minify CSS
  .pipe(gulp.dest('dist/css/'));

Modèles de gants

// Glob pattern examples
gulp.src('src/*.js')           // All .js files in src/
gulp.src('src/**/*.js')        // All .js files in src/ and subdirectories
gulp.src('src/js/*.{js,ts}')   // All .js and .ts files in src/js/
gulp.src(['src/**/*.js', '!src/vendor/**']) // Exclude vendor directory

// Multiple sources
gulp.src([
  'src/js/vendor/*.js',
  'src/js/main.js',
  'src/js/modules/*.js'
])

Fonctions des tâches

// Named function
function buildCSS() {
  return gulp.src('src/scss/**/*.scss')
    .pipe(sass())
    .pipe(gulp.dest('dist/css/'));
}

// Arrow function
const buildJS = () => {
  return gulp.src('src/js/**/*.js')
    .pipe(uglify())
    .pipe(gulp.dest('dist/js/'));
};

// Async function
async function copyFiles() {
  return gulp.src('src/assets/**/*')
    .pipe(gulp.dest('dist/assets/'));
}

// Export tasks
exports.css = buildCSS;
exports.js = buildJS;
exports.copy = copyFiles;

Série et parallèle

const { series, parallel } = require('gulp');

// Run tasks in series (one after another)
const build = series(clean, parallel(styles, scripts), copyAssets);

// Run tasks in parallel (simultaneously)
const dev = parallel(styles, scripts, serve, watch);

// Mixed series and parallel
const deploy = series(
  clean,
  parallel(styles, scripts, images),
  copyFiles,
  uploadToServer
);

exports.build = build;
exports.dev = dev;
exports.deploy = deploy;

Tâches de base

Copie de fichier

// Simple file copy
function copyHTML() {
  return gulp.src('src/**/*.html')
    .pipe(gulp.dest('dist/'));
}

// Copy with base option
function copyAssets() {
  return gulp.src('src/assets/**/*', { base: 'src' })
    .pipe(gulp.dest('dist/'));
}

// Copy specific files
function copyFonts() {
  return gulp.src([
    'src/fonts/**/*.{woff,woff2,ttf,eot}',
    'node_modules/font-awesome/fonts/**/*'
  ])
  .pipe(gulp.dest('dist/fonts/'));
}

Nettoyage des fichiers

const del = require('del');

// Clean build directory
function clean() {
  return del(['dist/**', '!dist']);
}

// Clean specific files
function cleanCSS() {
  return del(['dist/css/**/*.css']);
}

// Clean with patterns
function cleanOld() {
  return del([
    'dist/**',
    '!dist/vendor',
    '!dist/vendor/**'
  ]);
}

exports.clean = clean;

Renaming de fichiers

const rename = require('gulp-rename');

// Add suffix
function minifyCSS() {
  return gulp.src('src/css/**/*.css')
    .pipe(cleanCSS())
    .pipe(rename({ suffix: '.min' }))
    .pipe(gulp.dest('dist/css/'));
}

// Change extension
function compileTypeScript() {
  return gulp.src('src/**/*.ts')
    .pipe(typescript())
    .pipe(rename({ extname: '.js' }))
    .pipe(gulp.dest('dist/js/'));
}

// Custom rename function
function customRename() {
  return gulp.src('src/**/*.scss')
    .pipe(sass())
    .pipe(rename((path) => {
      path.dirname += '/compiled';
      path.basename += '-processed';
    }))
    .pipe(gulp.dest('dist/css/'));
}

Opérations de fichiers

Concaténation des fichiers

const concat = require('gulp-concat');

// Concatenate JavaScript files
function concatJS() {
  return gulp.src([
    'src/js/vendor/*.js',
    'src/js/modules/*.js',
    'src/js/main.js'
  ])
  .pipe(concat('bundle.js'))
  .pipe(gulp.dest('dist/js/'));
}

// Concatenate CSS files
function concatCSS() {
  return gulp.src('src/css/**/*.css')
    .pipe(concat('styles.css'))
    .pipe(gulp.dest('dist/css/'));
}

// Conditional concatenation
function buildVendorJS() {
  return gulp.src([
    'node_modules/jquery/dist/jquery.min.js',
    'node_modules/bootstrap/dist/js/bootstrap.min.js',
    'src/js/vendor/*.js'
  ])
  .pipe(concat('vendor.js'))
  .pipe(gulp.dest('dist/js/'));
}

Filtre de fichiers

const gulpif = require('gulp-if');
const filter = require('gulp-filter');

// Conditional processing
function processFiles() {
  const isProduction = process.env.NODE_ENV === 'production';

  return gulp.src('src/js/**/*.js')
    .pipe(gulpif(isProduction, uglify()))
    .pipe(gulp.dest('dist/js/'));
}

// Filter specific files
function processAssets() {
  const jsFilter = filter('**/*.js', { restore: true });
  const cssFilter = filter('**/*.css', { restore: true });

  return gulp.src('src/**/*')
    .pipe(jsFilter)
    .pipe(uglify())
    .pipe(jsFilter.restore)
    .pipe(cssFilter)
    .pipe(cleanCSS())
    .pipe(cssFilter.restore)
    .pipe(gulp.dest('dist/'));
}

Transformation de fichiers

const replace = require('gulp-replace');
const template = require('gulp-template');

// String replacement
function updateVersion() {
  return gulp.src('src/**/*.js')
    .pipe(replace('{{VERSION}}', process.env.npm_package_version))
    .pipe(gulp.dest('dist/js/'));
}

// Template processing
function processTemplates() {
  return gulp.src('src/templates/**/*.html')
    .pipe(template({
      title: 'My Website',
      version: '1.0.0',
      timestamp: new Date().toISOString()
    }))
    .pipe(gulp.dest('dist/'));
}

// Multiple replacements
function processConfig() {
  return gulp.src('src/config.js')
    .pipe(replace('{{API_URL}}', process.env.API_URL || 'http://localhost:3000'))
    .pipe(replace('{{DEBUG}}', process.env.NODE_ENV === 'development'))
    .pipe(gulp.dest('dist/js/'));
}

CSS Traitement

Compilation de Sass

const sass = require('gulp-sass')(require('sass'));
const autoprefixer = require('gulp-autoprefixer');
const cleanCSS = require('gulp-clean-css');
const sourcemaps = require('gulp-sourcemaps');

// Basic Sass compilation
function compileSass() {
  return gulp.src('src/scss/**/*.scss')
    .pipe(sass().on('error', sass.logError))
    .pipe(gulp.dest('dist/css/'));
}

// Advanced Sass processing
function processCSS() {
  return gulp.src('src/scss/main.scss')
    .pipe(sourcemaps.init())
    .pipe(sass({
      outputStyle: 'expanded',
      includePaths: ['node_modules']
    }).on('error', sass.logError))
    .pipe(autoprefixer({
      cascade: false
    }))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('dist/css/'))
    .pipe(cleanCSS())
    .pipe(rename({ suffix: '.min' }))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('dist/css/'));
}

// Production CSS build
function buildProductionCSS() {
  return gulp.src('src/scss/**/*.scss')
    .pipe(sass({
      outputStyle: 'compressed',
      includePaths: ['node_modules/bootstrap/scss']
    }))
    .pipe(autoprefixer({
      browsers: ['last 2 versions', '> 1%'],
      cascade: false
    }))
    .pipe(cleanCSS({
      level: 2
    }))
    .pipe(gulp.dest('dist/css/'));
}

PostCSS Traitement

const postcss = require('gulp-postcss');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const tailwindcss = require('tailwindcss');

// PostCSS with plugins
function processPostCSS() {
  const plugins = [
    tailwindcss(),
    autoprefixer(),
    cssnano()
  ];

  return gulp.src('src/css/**/*.css')
    .pipe(postcss(plugins))
    .pipe(gulp.dest('dist/css/'));
}

// Tailwind CSS processing
function buildTailwind() {
  return gulp.src('src/css/tailwind.css')
    .pipe(postcss([
      tailwindcss('./tailwind.config.js'),
      autoprefixer(),
      ...(process.env.NODE_ENV === 'production' ? [cssnano()] : [])
    ]))
    .pipe(gulp.dest('dist/css/'));
}

CSS Optimisation

const purgecss = require('gulp-purgecss');
const critical = require('critical');

// Remove unused CSS
function purgeCSS() {
  return gulp.src('dist/css/**/*.css')
    .pipe(purgecss({
      content: ['dist/**/*.html', 'dist/**/*.js'],
      safelist: ['active', 'show', /^carousel-/]
    }))
    .pipe(gulp.dest('dist/css/'));
}

// Extract critical CSS
function extractCritical() {
  return critical.generate({
    base: 'dist/',
    src: 'index.html',
    dest: 'css/critical.css',
    inline: true,
    width: 1300,
    height: 900
  });
}

// CSS linting
const stylelint = require('gulp-stylelint');

function lintCSS() {
  return gulp.src('src/scss/**/*.scss')
    .pipe(stylelint({
      reporters: [
        { formatter: 'string', console: true }
      ]
    }));
}

Traitement JavaScript

Basic JavaScript Traitement

const uglify = require('gulp-uglify');
const babel = require('gulp-babel');
const concat = require('gulp-concat');

// Basic JavaScript minification
function minifyJS() {
  return gulp.src('src/js/**/*.js')
    .pipe(uglify())
    .pipe(gulp.dest('dist/js/'));
}

// Babel transpilation
function transpileJS() {
  return gulp.src('src/js/**/*.js')
    .pipe(babel({
      presets: ['@babel/env']
    }))
    .pipe(gulp.dest('dist/js/'));
}

// Complete JavaScript pipeline
function processJS() {
  return gulp.src('src/js/**/*.js')
    .pipe(sourcemaps.init())
    .pipe(babel({
      presets: ['@babel/env']
    }))
    .pipe(concat('bundle.js'))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('dist/js/'))
    .pipe(uglify())
    .pipe(rename({ suffix: '.min' }))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('dist/js/'));
}

Traitement des scripts de type

const typescript = require('gulp-typescript');

// TypeScript compilation
function compileTypeScript() {
  const tsProject = typescript.createProject('tsconfig.json');

  return tsProject.src()
    .pipe(tsProject())
    .js
    .pipe(gulp.dest('dist/js/'));
}

// TypeScript with source maps
function buildTypeScript() {
  const tsProject = typescript.createProject('tsconfig.json');

  return gulp.src('src/ts/**/*.ts')
    .pipe(sourcemaps.init())
    .pipe(tsProject())
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('dist/js/'));
}

Bundling JavaScript

const browserify = require('browserify');
const source = require('vinyl-source-stream');
const buffer = require('vinyl-buffer');

// Browserify bundling
function bundleJS() {
  return browserify({
    entries: 'src/js/main.js',
    debug: true
  })
  .bundle()
  .pipe(source('bundle.js'))
  .pipe(buffer())
  .pipe(sourcemaps.init({ loadMaps: true }))
  .pipe(uglify())
  .pipe(sourcemaps.write('./'))
  .pipe(gulp.dest('dist/js/'));
}

// Webpack integration
const webpack = require('webpack-stream');

function webpackBundle() {
  return gulp.src('src/js/main.js')
    .pipe(webpack({
      mode: 'production',
      output: {
        filename: 'bundle.js'
      },
      module: {
        rules: [
          {
            test: /\.js$/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-env']
              }
            }
          }
        ]
      }
    }))
    .pipe(gulp.dest('dist/js/'));
}

JavaScript Doublure

const eslint = require('gulp-eslint');
const jshint = require('gulp-jshint');

// ESLint
function lintJS() {
  return gulp.src('src/js/**/*.js')
    .pipe(eslint())
    .pipe(eslint.format())
    .pipe(eslint.failAfterError());
}

// JSHint
function hintJS() {
  return gulp.src('src/js/**/*.js')
    .pipe(jshint())
    .pipe(jshint.reporter('default'))
    .pipe(jshint.reporter('fail'));
}

// Combined linting
function checkJS() {
  return gulp.src('src/js/**/*.js')
    .pipe(eslint())
    .pipe(eslint.format())
    .pipe(jshint())
    .pipe(jshint.reporter('default'));
}

Optimisation de l'image

Traitement de l'image de base

const imagemin = require('gulp-imagemin');
const webp = require('gulp-webp');
const responsive = require('gulp-responsive');

// Basic image optimization
function optimizeImages() {
  return gulp.src('src/images/**/*')
    .pipe(imagemin([
      imagemin.gifsicle({ interlaced: true }),
      imagemin.mozjpeg({ quality: 75, progressive: true }),
      imagemin.optipng({ optimizationLevel: 5 }),
      imagemin.svgo({
        plugins: [
          { removeViewBox: true },
          { cleanupIDs: false }
        ]
      })
    ]))
    .pipe(gulp.dest('dist/images/'));
}

// WebP conversion
function generateWebP() {
  return gulp.src('src/images/**/*.{jpg,jpeg,png}')
    .pipe(webp())
    .pipe(gulp.dest('dist/images/webp/'));
}

// Responsive images
function createResponsiveImages() {
  return gulp.src('src/images/**/*.{jpg,jpeg,png}')
    .pipe(responsive({
      '**/*': [
        {
          width: 320,
          rename: { suffix: '-small' }
        },
        {
          width: 640,
          rename: { suffix: '-medium' }
        },
        {
          width: 1024,
          rename: { suffix: '-large' }
        },
        {
          width: 1920,
          rename: { suffix: '-xlarge' }
        }
      ]
    }))
    .pipe(gulp.dest('dist/images/responsive/'));
}

Traitement d'image avancé

const sharp = require('gulp-sharp-responsive');
const sprite = require('gulp.spritesmith');

// Sharp image processing
function processWithSharp() {
  return gulp.src('src/images/**/*.{jpg,jpeg,png}')
    .pipe(sharp({
      formats: [
        { format: 'jpeg', options: { quality: 80 } },
        { format: 'webp', options: { quality: 80 } }
      ]
    }))
    .pipe(gulp.dest('dist/images/'));
}

// CSS Sprites
function createSprites() {
  const spriteData = gulp.src('src/images/icons/*.png')
    .pipe(sprite({
      imgName: 'sprite.png',
      cssName: 'sprite.css',
      imgPath: '../images/sprite.png'
    }));

  spriteData.img.pipe(gulp.dest('dist/images/'));
  spriteData.css.pipe(gulp.dest('dist/css/'));

  return spriteData;
}

// SVG sprites
const svgSprite = require('gulp-svg-sprite');

function createSVGSprites() {
  return gulp.src('src/images/icons/*.svg')
    .pipe(svgSprite({
      mode: {
        symbol: {
          dest: '.',
          sprite: 'sprite.svg'
        }
      }
    }))
    .pipe(gulp.dest('dist/images/'));
}

Traitement HTML

Minification HTML

const htmlmin = require('gulp-htmlmin');
const fileinclude = require('gulp-file-include');
const replace = require('gulp-replace');

// Basic HTML minification
function minifyHTML() {
  return gulp.src('src/**/*.html')
    .pipe(htmlmin({
      collapseWhitespace: true,
      removeComments: true,
      removeRedundantAttributes: true,
      removeScriptTypeAttributes: true,
      removeStyleLinkTypeAttributes: true,
      useShortDoctype: true
    }))
    .pipe(gulp.dest('dist/'));
}

// HTML includes
function processHTML() {
  return gulp.src('src/pages/*.html')
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(gulp.dest('dist/'));
}

// HTML templating
function buildHTML() {
  return gulp.src('src/templates/*.html')
    .pipe(replace('{{TITLE}}', 'My Website'))
    .pipe(replace('{{VERSION}}', process.env.npm_package_version))
    .pipe(htmlmin({
      collapseWhitespace: true,
      removeComments: true
    }))
    .pipe(gulp.dest('dist/'));
}

Validation et traitement HTML

const htmlhint = require('gulp-htmlhint');
const w3cjs = require('gulp-w3cjs');
const inject = require('gulp-inject');

// HTML validation
function validateHTML() {
  return gulp.src('dist/**/*.html')
    .pipe(htmlhint())
    .pipe(htmlhint.reporter())
    .pipe(w3cjs())
    .pipe(w3cjs.reporter());
}

// Asset injection
function injectAssets() {
  const target = gulp.src('src/index.html');
  const sources = gulp.src(['dist/js/**/*.js', 'dist/css/**/*.css'], { read: false });

  return target
    .pipe(inject(sources, {
      relative: true,
      transform: function (filepath) {
        if (filepath.slice(-3) === '.js') {
          return '<script src="' + filepath + '"></script>';
        }
        return '<link rel="stylesheet" href="' + filepath + '">';
      }
    }))
    .pipe(gulp.dest('dist/'));
}

Serveur de développement

Configuration du serveur de base

const browserSync = require('browser-sync').create();
const connect = require('gulp-connect');

// Browser Sync server
function serve() {
  browserSync.init({
    server: {
      baseDir: 'dist'
    },
    port: 3000,
    open: true
  });
}

// Connect server
function connectServer() {
  connect.server({
    root: 'dist',
    livereload: true,
    port: 8080
  });
}

// Reload browser
function reload(done) {
  browserSync.reload();
  done();
}

Configuration avancée du serveur

// Advanced Browser Sync setup
function advancedServe() {
  browserSync.init({
    server: {
      baseDir: 'dist',
      middleware: [
        // Custom middleware
        function(req, res, next) {
          console.log('Request:', req.url);
          next();
        }
      ]
    },
    port: 3000,
    ui: {
      port: 3001
    },
    files: [
      'dist/**/*.html',
      'dist/**/*.css',
      'dist/**/*.js'
    ],
    reloadDelay: 1000,
    notify: false,
    ghostMode: {
      clicks: true,
      forms: true,
      scroll: true
    }
  });
}

// Proxy server
function proxyServe() {
  browserSync.init({
    proxy: 'localhost:8080',
    port: 3000,
    files: ['dist/**/*'],
    reloadDelay: 1000
  });
}

Recharger en direct

// Live reload with gulp-connect
function liveReload() {
  return gulp.src('dist/**/*.html')
    .pipe(connect.reload());
}

// Watch with live reload
function watchWithReload() {
  gulp.watch('src/scss/**/*.scss', gulp.series(styles, reload));
  gulp.watch('src/js/**/*.js', gulp.series(scripts, reload));
  gulp.watch('src/**/*.html', gulp.series(copyHTML, reload));
}

// Complete development server
function dev() {
  serve();
  watchWithReload();
}

exports.serve = serve;
exports.dev = dev;

Regarder les tâches

Configuration de la montre de base

// Basic watch
function watch() {
  gulp.watch('src/scss/**/*.scss', styles);
  gulp.watch('src/js/**/*.js', scripts);
  gulp.watch('src/**/*.html', copyHTML);
  gulp.watch('src/images/**/*', images);
}

// Watch with options
function watchAdvanced() {
  gulp.watch('src/scss/**/*.scss', {
    events: 'all',
    delay: 500
  }, styles);

  gulp.watch('src/js/**/*.js', {
    ignoreInitial: false
  }, scripts);
}

Modèles de montres avancés

const chokidar = require('chokidar');

// Custom watcher
function customWatch() {
  // Watch SCSS files
  const scssWatcher = chokidar.watch('src/scss/**/*.scss');
  scssWatcher.on('change', () => {
    console.log('SCSS file changed');
    styles();
  });

  // Watch JS files
  const jsWatcher = chokidar.watch('src/js/**/*.js');
  jsWatcher.on('add', () => {
    console.log('JS file added');
    scripts();
  });
  jsWatcher.on('unlink', () => {
    console.log('JS file removed');
    scripts();
  });
}

// Conditional watching
function conditionalWatch() {
  if (process.env.NODE_ENV === 'development') {
    gulp.watch('src/scss/**/*.scss', gulp.series(styles, reload));
    gulp.watch('src/js/**/*.js', gulp.series(lintJS, scripts, reload));
  } else {
    gulp.watch('src/scss/**/*.scss', styles);
    gulp.watch('src/js/**/*.js', scripts);
  }
}

Regarder avec la manipulation des erreurs

const plumber = require('gulp-plumber');
const notify = require('gulp-notify');

// Error handling in watch
function watchWithErrors() {
  gulp.watch('src/scss/**/*.scss', () => {
    return gulp.src('src/scss/**/*.scss')
      .pipe(plumber({
        errorHandler: notify.onError({
          title: 'Sass Error',
          message: '<%= error.message %>'
        })
      }))
      .pipe(sass())
      .pipe(gulp.dest('dist/css/'))
      .pipe(browserSync.stream());
  });
}

// Graceful error handling
function gracefulWatch() {
  gulp.watch('src/js/**/*.js', () => {
    return gulp.src('src/js/**/*.js')
      .pipe(plumber())
      .pipe(babel())
      .on('error', function(err) {
        console.error('Error:', err.message);
        this.emit('end');
      })
      .pipe(uglify())
      .pipe(gulp.dest('dist/js/'));
  });
}

Construire un pipeline

Développement

// Development build pipeline
const developmentBuild = gulp.series(
  clean,
  gulp.parallel(
    copyHTML,
    gulp.series(lintCSS, styles),
    gulp.series(lintJS, scripts),
    copyAssets,
    optimizeImages
  )
);

// Development with watch
const dev = gulp.series(
  developmentBuild,
  gulp.parallel(serve, watch)
);

exports.dev = dev;

Construction de production

// Production build pipeline
const productionBuild = gulp.series(
  clean,
  gulp.parallel(
    minifyHTML,
    buildProductionCSS,
    buildProductionJS,
    optimizeImages,
    copyAssets
  ),
  injectAssets,
  generateSitemap
);

// Production JavaScript build
function buildProductionJS() {
  return gulp.src('src/js/**/*.js')
    .pipe(babel({
      presets: ['@babel/env']
    }))
    .pipe(concat('bundle.js'))
    .pipe(uglify())
    .pipe(rev())
    .pipe(gulp.dest('dist/js/'))
    .pipe(rev.manifest())
    .pipe(gulp.dest('dist/'));
}

exports.build = productionBuild;

Constructions multi-environnement

const gulpif = require('gulp-if');

// Environment-aware build
function buildForEnvironment() {
  const isProduction = process.env.NODE_ENV === 'production';
  const isDevelopment = process.env.NODE_ENV === 'development';

  return gulp.src('src/js/**/*.js')
    .pipe(gulpif(isDevelopment, sourcemaps.init()))
    .pipe(babel())
    .pipe(gulpif(isProduction, uglify()))
    .pipe(gulpif(isDevelopment, sourcemaps.write('.')))
    .pipe(gulp.dest('dist/js/'));
}

// Multiple environment configs
const environments = {
  development: {
    sourcemaps: true,
    minify: false,
    baseUrl: 'http://localhost:3000'
  },
  staging: {
    sourcemaps: true,
    minify: true,
    baseUrl: 'https://staging.example.com'
  },
  production: {
    sourcemaps: false,
    minify: true,
    baseUrl: 'https://example.com'
  }
};

function buildWithConfig() {
  const env = process.env.NODE_ENV || 'development';
  const config = environments[env];

  return gulp.src('src/**/*.js')
    .pipe(gulpif(config.sourcemaps, sourcemaps.init()))
    .pipe(replace('{{BASE_URL}}', config.baseUrl))
    .pipe(gulpif(config.minify, uglify()))
    .pipe(gulpif(config.sourcemaps, sourcemaps.write('.')))
    .pipe(gulp.dest('dist/js/'));
}

Écosystème greffon

Greffons essentiels

# Core plugins
npm install --save-dev gulp-sass gulp-autoprefixer gulp-clean-css
npm install --save-dev gulp-uglify gulp-concat gulp-babel
npm install --save-dev gulp-imagemin gulp-htmlmin

# Utility plugins
npm install --save-dev gulp-sourcemaps gulp-rename gulp-if
npm install --save-dev gulp-plumber gulp-notify gulp-filter

# Development plugins
npm install --save-dev browser-sync gulp-connect
npm install --save-dev gulp-eslint gulp-stylelint

# Advanced plugins
npm install --save-dev gulp-rev gulp-inject gulp-replace
npm install --save-dev gulp-zip gulp-ftp gulp-s3-upload

Greffons de traitement de fichiers

// File manipulation
const rev = require('gulp-rev');
const revReplace = require('gulp-rev-replace');
const size = require('gulp-size');

// Asset revisioning
function revisionAssets() {
  return gulp.src(['dist/**/*.css', 'dist/**/*.js'])
    .pipe(rev())
    .pipe(gulp.dest('dist/'))
    .pipe(rev.manifest())
    .pipe(gulp.dest('dist/'));
}

// Replace revisioned assets
function replaceRevisionedAssets() {
  const manifest = gulp.src('dist/rev-manifest.json');

  return gulp.src('dist/**/*.html')
    .pipe(revReplace({ manifest: manifest }))
    .pipe(gulp.dest('dist/'));
}

// File size reporting
function reportSizes() {
  return gulp.src('dist/**/*')
    .pipe(size({
      showFiles: true,
      gzip: true
    }));
}

Essai des greffons

const mocha = require('gulp-mocha');
const karma = require('karma').Server;
const jest = require('gulp-jest');

// Mocha tests
function runMochaTests() {
  return gulp.src('test/**/*.js', { read: false })
    .pipe(mocha({
      reporter: 'spec'
    }));
}

// Karma tests
function runKarmaTests(done) {
  new karma({
    configFile: __dirname + '/karma.conf.js',
    singleRun: true
  }, done).start();
}

// Jest tests
function runJestTests() {
  return gulp.src('.')
    .pipe(jest({
      preprocessorIgnorePatterns: [
        '<rootDir>/dist/', '<rootDir>/node_modules/'
      ],
      automock: false
    }));
}

Greffons de déploiement

const ftp = require('vinyl-ftp');
const s3 = require('gulp-s3-upload')();
const ghPages = require('gulp-gh-pages');

// FTP deployment
function deployFTP() {
  const conn = ftp.create({
    host: 'ftp.example.com',
    user: process.env.FTP_USER,
    password: process.env.FTP_PASSWORD,
    parallel: 10
  });

  return gulp.src('dist/**/*', { base: 'dist', buffer: false })
    .pipe(conn.newer('/public_html'))
    .pipe(conn.dest('/public_html'));
}

// S3 deployment
function deployS3() {
  return gulp.src('dist/**/*')
    .pipe(s3({
      Bucket: 'my-bucket',
      ACL: 'public-read'
    }));
}

// GitHub Pages deployment
function deployGitHub() {
  return gulp.src('dist/**/*')
    .pipe(ghPages());
}

Modèles avancés

Plugins personnalisés

const through = require('through2');
const PluginError = require('plugin-error');

// Simple custom plugin
function customPlugin(options) {
  options = options || {};

  return through.obj(function(file, encoding, callback) {
    if (file.isNull()) {
      return callback(null, file);
    }

    if (file.isStream()) {
      return callback(new PluginError('custom-plugin', 'Streaming not supported'));
    }

    try {
      // Process file content
      const content = file.contents.toString();
      const processed = content.replace(/foo/g, 'bar');
      file.contents = Buffer.from(processed);

      this.push(file);
      callback();
    } catch (err) {
      callback(new PluginError('custom-plugin', err));
    }
  });
}

// Usage
function useCustomPlugin() {
  return gulp.src('src/**/*.js')
    .pipe(customPlugin({ option: 'value' }))
    .pipe(gulp.dest('dist/'));
}

Traitement des flux

const map = require('map-stream');
const transform = require('stream-transform');

// Map stream processing
function processWithMap() {
  return gulp.src('src/**/*.js')
    .pipe(map((file, callback) => {
      // Process each file
      const content = file.contents.toString();
      const processed = content.toUpperCase();
      file.contents = Buffer.from(processed);
      callback(null, file);
    }))
    .pipe(gulp.dest('dist/'));
}

// Transform stream
function processWithTransform() {
  return gulp.src('src/**/*.json')
    .pipe(transform((file, encoding, callback) => {
      try {
        const data = JSON.parse(file.contents.toString());
        data.processed = true;
        data.timestamp = new Date().toISOString();
        file.contents = Buffer.from(JSON.stringify(data, null, 2));
        callback(null, file);
      } catch (err) {
        callback(err);
      }
    }))
    .pipe(gulp.dest('dist/'));
}

Traitement sous condition

const yargs = require('yargs');
const gulpif = require('gulp-if');

// Command line arguments
const argv = yargs.argv;

function conditionalBuild() {
  return gulp.src('src/**/*.js')
    .pipe(gulpif(argv.lint, eslint()))
    .pipe(gulpif(argv.babel, babel()))
    .pipe(gulpif(argv.minify, uglify()))
    .pipe(gulp.dest('dist/'));
}

// Environment-based conditions
function environmentalBuild() {
  const isProduction = process.env.NODE_ENV === 'production';
  const isDevelopment = !isProduction;

  return gulp.src('src/**/*.js')
    .pipe(gulpif(isDevelopment, sourcemaps.init()))
    .pipe(babel())
    .pipe(gulpif(isProduction, uglify()))
    .pipe(gulpif(isDevelopment, sourcemaps.write('.')))
    .pipe(gulp.dest('dist/'));
}

// File-based conditions
function fileBasedProcessing() {
  return gulp.src('src/**/*')
    .pipe(gulpif('*.js', uglify()))
    .pipe(gulpif('*.css', cleanCSS()))
    .pipe(gulpif('*.html', htmlmin()))
    .pipe(gulp.dest('dist/'));
}

Optimisation des performances

Traitement parallèle

// Parallel task execution
const parallelBuild = gulp.parallel(
  styles,
  scripts,
  images,
  copyAssets
);

// Mixed series and parallel
const optimizedBuild = gulp.series(
  clean,
  gulp.parallel(
    gulp.series(lintCSS, styles),
    gulp.series(lintJS, scripts),
    images
  ),
  injectAssets
);

exports.build = optimizedBuild;

Constructions supplémentaires

const changed = require('gulp-changed');
const newer = require('gulp-newer');

// Process only changed files
function incrementalStyles() {
  return gulp.src('src/scss/**/*.scss')
    .pipe(changed('dist/css/', { extension: '.css' }))
    .pipe(sass())
    .pipe(gulp.dest('dist/css/'));
}

// Process only newer files
function incrementalImages() {
  return gulp.src('src/images/**/*')
    .pipe(newer('dist/images/'))
    .pipe(imagemin())
    .pipe(gulp.dest('dist/images/'));
}

// Cache-based processing
const cache = require('gulp-cache');

function cachedImages() {
  return gulp.src('src/images/**/*')
    .pipe(cache(imagemin()))
    .pipe(gulp.dest('dist/images/'));
}

Optimisation de la mémoire

const remember = require('gulp-remember');
const cached = require('gulp-cached');

// Cached processing with remember
function optimizedScripts() {
  return gulp.src('src/js/**/*.js')
    .pipe(cached('scripts'))
    .pipe(eslint())
    .pipe(remember('scripts'))
    .pipe(concat('bundle.js'))
    .pipe(gulp.dest('dist/js/'));
}

// Clear cache when needed
function clearCache() {
  return cache.clearAll();
}

// Memory-efficient streaming
function streamEfficient() {
  return gulp.src('src/**/*.js', { buffer: false })
    .pipe(someTransform())
    .pipe(gulp.dest('dist/'));
}

Gestion des erreurs

Gestion des erreurs de base

const plumber = require('gulp-plumber');
const notify = require('gulp-notify');

// Plumber for error handling
function errorHandledStyles() {
  return gulp.src('src/scss/**/*.scss')
    .pipe(plumber({
      errorHandler: function(err) {
        console.error('Error:', err.message);
        this.emit('end');
      }
    }))
    .pipe(sass())
    .pipe(gulp.dest('dist/css/'));
}

// Notify on errors
function notifyOnError() {
  return gulp.src('src/scss/**/*.scss')
    .pipe(plumber({
      errorHandler: notify.onError({
        title: 'Sass Error',
        message: '<%= error.message %>'
      })
    }))
    .pipe(sass())
    .pipe(gulp.dest('dist/css/'));
}

Gestion avancée des erreurs

// Custom error handler
function createErrorHandler(taskName) {
  return function(err) {
    console.error(`Error in ${taskName}:`, err.message);
    if (err.stack) {
      console.error(err.stack);
    }
    this.emit('end');
  };
}

// Error handling with logging
const log = require('fancy-log');
const colors = require('ansi-colors');

function advancedErrorHandling() {
  return gulp.src('src/js/**/*.js')
    .pipe(plumber({
      errorHandler: function(err) {
        log.error(colors.red('JavaScript Error:'));
        log.error(colors.red(err.message));
        if (err.fileName) {
          log.error(colors.yellow('File:'), err.fileName);
        }
        if (err.lineNumber) {
          log.error(colors.yellow('Line:'), err.lineNumber);
        }
        this.emit('end');
      }
    }))
    .pipe(babel())
    .pipe(gulp.dest('dist/js/'));
}

// Graceful degradation
function gracefulBuild() {
  return gulp.src('src/**/*.js')
    .pipe(plumber())
    .pipe(babel())
    .on('error', function(err) {
      log.error('Babel compilation failed, using original files');
      return gulp.src('src/**/*.js')
        .pipe(gulp.dest('dist/js/'));
    })
    .pipe(uglify())
    .pipe(gulp.dest('dist/js/'));
}

Essais

Essai en unité

const mocha = require('gulp-mocha');
const istanbul = require('gulp-istanbul');

// Run Mocha tests
function runTests() {
  return gulp.src('test/**/*.js', { read: false })
    .pipe(mocha({
      reporter: 'spec',
      timeout: 5000
    }));
}

// Code coverage
function coverage() {
  return gulp.src('src/**/*.js')
    .pipe(istanbul())
    .pipe(istanbul.hookRequire());
}

function testWithCoverage() {
  return gulp.src('test/**/*.js', { read: false })
    .pipe(mocha())
    .pipe(istanbul.writeReports())
    .pipe(istanbul.enforceThresholds({ thresholds: { global: 90 } }));
}

const testSuite = gulp.series(coverage, testWithCoverage);
exports.test = testSuite;

Essais d'intégration

const puppeteer = require('puppeteer');
const assert = require('assert');

// Browser testing
async function browserTest() {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  await page.goto('http://localhost:3000');

  const title = await page.title();
  assert.strictEqual(title, 'My Website');

  await browser.close();
}

// Visual regression testing
const backstop = require('backstopjs');

function visualTest() {
  return backstop('test', {
    config: 'backstop.json'
  });
}

// Performance testing
const lighthouse = require('lighthouse');

async function performanceTest() {
  const results = await lighthouse('http://localhost:3000', {
    output: 'json',
    onlyCategories: ['performance']
  });

  const score = results.lhr.categories.performance.score * 100;
  console.log('Performance Score:', score);

  if (score < 90) {
    throw new Error('Performance score too low');
  }
}

Déploiement

Construction et déploiement d'un pipeline

const zip = require('gulp-zip');
const ftp = require('vinyl-ftp');

// Create deployment package
function createPackage() {
  return gulp.src('dist/**/*')
    .pipe(zip('deploy.zip'))
    .pipe(gulp.dest('packages/'));
}

// Deploy via FTP
function deployToServer() {
  const conn = ftp.create({
    host: process.env.FTP_HOST,
    user: process.env.FTP_USER,
    password: process.env.FTP_PASSWORD,
    parallel: 10,
    log: console.log
  });

  return gulp.src('dist/**/*', { base: 'dist', buffer: false })
    .pipe(conn.newer('/public_html'))
    .pipe(conn.dest('/public_html'));
}

// Complete deployment pipeline
const deploy = gulp.series(
  productionBuild,
  runTests,
  createPackage,
  deployToServer
);

exports.deploy = deploy;

Intégration CI/CD

// Environment-aware deployment
function deployToEnvironment() {
  const env = process.env.NODE_ENV || 'development';
  const configs = {
    development: {
      host: 'dev.example.com',
      path: '/dev'
    },
    staging: {
      host: 'staging.example.com',
      path: '/staging'
    },
    production: {
      host: 'example.com',
      path: '/public_html'
    }
  };

  const config = configs[env];

  return gulp.src('dist/**/*')
    .pipe(deployTo(config));
}

// Docker deployment
function buildDockerImage() {
  return gulp.src(['dist/**/*', 'Dockerfile'])
    .pipe(docker.build({
      tag: 'my-app:latest'
    }));
}

// Kubernetes deployment
function deployToK8s() {
  return gulp.src('k8s/*.yaml')
    .pipe(kubectl.apply());
}

Meilleures pratiques

Organisation du projet

// Organized gulpfile structure
const { src, dest, watch, series, parallel } = require('gulp');

// Task modules
const styles = require('./gulp-tasks/styles');
const scripts = require('./gulp-tasks/scripts');
const images = require('./gulp-tasks/images');
const server = require('./gulp-tasks/server');

// Configuration
const config = require('./gulp.config.js');

// Export tasks
exports.styles = styles;
exports.scripts = scripts;
exports.images = images;
exports.serve = server.serve;
exports.build = parallel(styles, scripts, images);
exports.dev = series(exports.build, server.serve, server.watch);

Gestion de la configuration

// gulp.config.js
module.exports = {
  paths: {
    src: 'src',
    dest: 'dist',
    styles: {
      src: 'src/scss/**/*.scss',
      dest: 'dist/css/'
    },
    scripts: {
      src: 'src/js/**/*.js',
      dest: 'dist/js/'
    },
    images: {
      src: 'src/images/**/*',
      dest: 'dist/images/'
    }
  },

  options: {
    sass: {
      outputStyle: 'compressed',
      includePaths: ['node_modules']
    },
    autoprefixer: {
      browsers: ['last 2 versions', '> 1%']
    },
    imagemin: {
      optimizationLevel: 5,
      progressive: true,
      interlaced: true
    }
  },

  server: {
    port: 3000,
    baseDir: 'dist'
  }
};

Meilleures pratiques en matière de rendement

  • Utilisez des constructions progressives avec gulp-changed ou gulp-newer
  • Mise en oeuvre du traitement parallèle pour des tâches indépendantes
  • Cache opérations coûteuses avec gulp-cache
  • Utilisez streaming au lieu de tamponner pour les grands fichiers
  • Optimiser les modèles de montre pour éviter les reconstructions inutiles

Qualité du code Meilleures pratiques

  • Lintage d'application pour CSS, JavaScript et HTML
  • Utiliser les cartes sources pour le débogage dans le développement
  • Ajouter le traitement des erreurs avec gulp-plumber
  • Inclure les essais dans votre pipeline de construction
  • Documentez vos tâches et configuration

Pratiques exemplaires de maintenance

  • Garder régulièrement les plugins à jour
  • Utilisez la version sémantique pour vos constructions
  • Mise en œuvre de l'enregistrement approprié pour le débogage
  • Créer des fichiers de tâches modulaires pour une meilleure organisation
  • Utiliser des variables d'environnement pour une configuration sensible

Résumé

Gulp est un puissant système de construction en streaming qui excelle dans l'automatisation des tâches répétitives dans le développement web. Les principales caractéristiques sont les suivantes :

  • ** Traitement basé sur la stratégie** : Traitement efficace des fichiers sans fichiers temporaires
  • Code sur la configuration : configuration basée sur JavaScript pour une flexibilité maximale
  • Rich Plugin Ecosystem: Des milliers de plugins pour chaque tâche imaginable
  • Traitement parallèle: Exécuter les tâches simultanément pour des constructions plus rapides
  • Watch et Live Reload: Reconstruction automatique et mise à jour du navigateur
  • Incremental Builds: Traitement uniquement des fichiers modifiés pour la vitesse
  • Manipulation d'erreur: Gestion d'erreur robuste pour éviter les défaillances de construction
  • Extensible: Facile à créer des plugins et des tâches personnalisés

En tirant parti de l'architecture en streaming de Gulp et de l'écosystème de plugin étendu, vous pouvez créer des processus de construction efficaces et durables qui s'étendent avec la complexité de votre projet.