Gulp + Webpack or JUST Webpack?

后端 未结 5 1199
难免孤独
难免孤独 2021-01-29 17:11

I see people using gulp with webpack. But then I read webpack can replace gulp? I\'m completely confused here...can someone explain?

UPDATE

in the end I starte

5条回答
  •  旧时难觅i
    2021-01-29 17:46

    NPM scripts can do the same as gulp, but in about 50x less code. In fact, with no code at all, only command line arguments.

    For example, the use case you described where you want to have different code for different environments.

    With Webpack + NPM Scripts, it's this easy:

    "prebuild:dev": "npm run clean:wwwroot",
    "build:dev": "cross-env NODE_ENV=development webpack --config config/webpack.development.js --hot --profile --progress --colors --display-cached",
    "postbuild:dev": "npm run copy:index.html && npm run rename:index.html",
    
    "prebuild:production": "npm run clean:wwwroot",
    "build:production": "cross-env NODE_ENV=production webpack --config config/webpack.production.js --profile --progress --colors --display-cached --bail",
    "postbuild:production": "npm run copy:index.html && npm run rename:index.html",
    
    "clean:wwwroot": "rimraf -- wwwroot/*",
    "copy:index.html": "ncp wwwroot/index.html Views/Shared",
    "rename:index.html": "cd ../PowerShell && elevate.exe -c renamer --find \"index.html\" --replace \"_Layout.cshtml\" \"../MyProject/Views/Shared/*\"",
    

    Now you simply maintain two webpack config scripts, one for development mode, webpack.development.js, and one for production mode, webpack.production.js. I also utilize a webpack.common.js which houses webpack config shared on all environments, and use webpackMerge to merge them.

    Because of the coolness of NPM scripts, it allows for easy chaining, similar to how gulp does Streams/pipes.

    In the example above, to build for developement, you simply go to your command line and execute npm run build:dev.

    1. NPM would first run prebuild:dev,
    2. Then build:dev,
    3. And finally postbuild:dev.

    The pre and post prefixes tell NPM which order to execute in.

    If you notice, with Webpack + NPM scripts, you can run a native programs, such as rimraf, instead of a gulp-wrapper for a native program such as gulp-rimraf. You can also run native Windows .exe files as I did here with elevate.exe or native *nix files on Linux or Mac.

    Try doing the same thing with gulp. You'll have to wait for someone to come along and write a gulp-wrapper for the native program you want to use. In addition, you'll likely need to write convoluted code like this: (taken straight from angular2-seed repo)

    Gulp Development code

    import * as gulp from 'gulp';
    import * as gulpLoadPlugins from 'gulp-load-plugins';
    import * as merge from 'merge-stream';
    import * as util from 'gulp-util';
    import { join/*, sep, relative*/ } from 'path';
    
    import { APP_DEST, APP_SRC, /*PROJECT_ROOT, */TOOLS_DIR, TYPED_COMPILE_INTERVAL } from '../../config';
    import { makeTsProject, templateLocals } from '../../utils';
    
    const plugins = gulpLoadPlugins();
    
    let typedBuildCounter = TYPED_COMPILE_INTERVAL; // Always start with the typed build.
    
    /**
     * Executes the build process, transpiling the TypeScript files (except the spec and e2e-spec files) for the development
     * environment.
     */
    export = () => {
      let tsProject: any;
      let typings = gulp.src([
        'typings/index.d.ts',
        TOOLS_DIR + '/manual_typings/**/*.d.ts'
      ]);
      let src = [
        join(APP_SRC, '**/*.ts'),
        '!' + join(APP_SRC, '**/*.spec.ts'),
        '!' + join(APP_SRC, '**/*.e2e-spec.ts')
      ];
    
      let projectFiles = gulp.src(src);
      let result: any;
      let isFullCompile = true;
    
      // Only do a typed build every X builds, otherwise do a typeless build to speed things up
      if (typedBuildCounter < TYPED_COMPILE_INTERVAL) {
        isFullCompile = false;
        tsProject = makeTsProject({isolatedModules: true});
        projectFiles = projectFiles.pipe(plugins.cached());
        util.log('Performing typeless TypeScript compile.');
      } else {
        tsProject = makeTsProject();
        projectFiles = merge(typings, projectFiles);
      }
    
      result = projectFiles
        .pipe(plugins.plumber())
        .pipe(plugins.sourcemaps.init())
        .pipe(plugins.typescript(tsProject))
        .on('error', () => {
          typedBuildCounter = TYPED_COMPILE_INTERVAL;
        });
    
      if (isFullCompile) {
        typedBuildCounter = 0;
      } else {
        typedBuildCounter++;
      }
    
      return result.js
        .pipe(plugins.sourcemaps.write())
    // Use for debugging with Webstorm/IntelliJ
    // https://github.com/mgechev/angular2-seed/issues/1220
    //    .pipe(plugins.sourcemaps.write('.', {
    //      includeContent: false,
    //      sourceRoot: (file: any) =>
    //        relative(file.path, PROJECT_ROOT + '/' + APP_SRC).replace(sep, '/') + '/' + APP_SRC
    //    }))
        .pipe(plugins.template(templateLocals()))
        .pipe(gulp.dest(APP_DEST));
    };
    

    Gulp Production code

    import * as gulp from 'gulp';
    import * as gulpLoadPlugins from 'gulp-load-plugins';
    import { join } from 'path';
    
    import { TMP_DIR, TOOLS_DIR } from '../../config';
    import { makeTsProject, templateLocals } from '../../utils';
    
    const plugins = gulpLoadPlugins();
    
    const INLINE_OPTIONS = {
      base: TMP_DIR,
      useRelativePaths: true,
      removeLineBreaks: true
    };
    
    /**
     * Executes the build process, transpiling the TypeScript files for the production environment.
     */
    
    export = () => {
      let tsProject = makeTsProject();
      let src = [
        'typings/index.d.ts',
        TOOLS_DIR + '/manual_typings/**/*.d.ts',
        join(TMP_DIR, '**/*.ts')
      ];
      let result = gulp.src(src)
        .pipe(plugins.plumber())
        .pipe(plugins.inlineNg2Template(INLINE_OPTIONS))
        .pipe(plugins.typescript(tsProject))
        .once('error', function () {
          this.once('finish', () => process.exit(1));
        });
    
    
      return result.js
        .pipe(plugins.template(templateLocals()))
        .pipe(gulp.dest(TMP_DIR));
    };
    

    The actual gulp code is much more complicated that this, as this is only 2 of the several dozen gulp files in the repo.

    So, which one is easier to you?

    In my opinion, NPM scripts far surpasses gulp and grunt, in both effectiveness and ease of use, and all front-end developers should consider using it in their workflow because it is a major time saver.

    UPDATE

    There is one scenario I've encountered where I wanted to use Gulp in combination with NPM scripts and Webpack.

    When I need to do remote debugging on an iPad or Android device for example, I need to start up extra servers. In the past I ran all the servers as separate processes, from within IntelliJ IDEA (Or Webstorm) that is easy with the "Compound" Run Configuration. But if I need to stop and restart them, it was tedious to have to close 5 different server tabs, plus the output was spread across the different windows.

    One of the benefits of gulp is that is can chain all the output from separate independent processes into one console window, which becomes the parent of all the child servers.

    So I created a very simple gulp task that just runs my NPM scripts or the commands directly, so all the output appears in one window, and I can easily end all 5 servers at once by closing the gulp task window.

    Gulp.js

    /**
     * Gulp / Node utilities
     */
    var gulp = require('gulp-help')(require('gulp'));
    var utils = require('gulp-util');
    var log = utils.log;
    var con = utils.colors;
    
    /**
     * Basic workflow plugins
     */
    var shell = require('gulp-shell'); // run command line from shell
    var browserSync = require('browser-sync');
    
    /**
     * Performance testing plugins
     */
    var ngrok = require('ngrok');
    
    // Variables
    var serverToProxy1 = "localhost:5000";
    var finalPort1 = 8000;
    
    
    // When the user enters "gulp" on the command line, the default task will automatically be called. This default task below, will run all other tasks automatically.
    
    // Default task
    gulp.task('default', function (cb) {
       console.log('Starting dev servers!...');
       gulp.start(
          'devserver:jit',
          'nodemon',
          'browsersync',
          'ios_webkit_debug_proxy'
          'ngrok-url',
          // 'vorlon',
          // 'remotedebug_ios_webkit_adapter'
       );
    });
    
    gulp.task('nodemon', shell.task('cd ../backend-nodejs && npm run nodemon'));
    gulp.task('devserver:jit', shell.task('npm run devserver:jit'));
    gulp.task('ios_webkit_debug_proxy', shell.task('npm run ios-webkit-debug-proxy'));
    gulp.task('browsersync', shell.task(`browser-sync start --proxy ${serverToProxy1} --port ${finalPort1} --no-open`));
    gulp.task('ngrok-url', function (cb) {
       return ngrok.connect(finalPort1, function (err, url) {
          site = url;
          log(con.cyan('ngrok'), '- serving your site from', con.yellow(site));
          cb();
       });
    });
    // gulp.task('vorlon', shell.task('vorlon'));
    // gulp.task('remotedebug_ios_webkit_adapter', shell.task('remotedebug_ios_webkit_adapter'));
    

    Still quite a bit of code just to run 5 tasks, in my opinion, but it works for the purpose. One caveate is that gulp-shell doesn't seem to run some commands correctly, such as ios-webkit-debug-proxy. So I had to create an NPM Script that just executes the same command, and then it works.

    So I primarily use NPM Scripts for all my tasks, but occasionally when I need to run a bunch of servers at once, I'll fire up my Gulp task to help out. Pick the right tool for the right job.

    UPDATE 2

    I now use a script called concurrently which does the same thing as the gulp task above. It runs multiple CLI scripts in parallel and pipes them all to the same console window, and its very simple to use. Once again, no code required (well, the code is inside the node_module for concurrently, but you don't have to concern yourself with that)

    // NOTE: If you need to run a command with spaces in it, you need to use 
    // double quotes, and they must be escaped (at least on windows).
    // It doesn't seem to work with single quotes.
    
    "run:all": "concurrently \"npm run devserver\" nodemon browsersync ios_webkit_debug_proxy ngrok-url"
    

    This runs all 5 scripts in parallel piped out to one terminal. Awesome! So that this point, I rarely use gulp, since there are so many cli scripts to do the same tasks with no code.

    I suggest you read these articles which compare them in depth.

    • How to Use NPM as a Build Tool
    • Why we should stop using Grunt & Gulp
    • Why I Left Gulp and Grunt for NPM Scripts

提交回复
热议问题