使用 Gulp+Webpack 構建前端項目

使用構建工具的原因

自從 nodejs 誕生以來,很多前端工作都可以在本地進行,其中就包括 JS 調試和工作流等。最開始應用工作流的插件叫 Grunt,因爲起步早,因此插件多,內容豐富,但是執行速度比較慢。後來就出了 Gulp,和 Grunt 類似,不過由於 Gulp 利用了 nodejs 的流(stream),因此效率十分給力,唯一的缺點就是插件沒有 Grunt 多,不過發展到今天,插件也逐漸多起來了。大家有可能還聽說過 Webpack,最近幾年非常熱門,但是 Webpack 的亮點主要是模塊打包,可以和 Gulp 配合使用。

使用 Gulp 不僅能對資源進行優化,而且在開發過程中能夠通過配置自動完成很多重複的任務,讓我們可以專注於代碼,提高工作效率;而使用 Webpack,可以把衆多模塊打包成一個文件,減少網絡請求次數。儘管 Gulp 和 Webpack 的許多功能可以互相代替,但是它們各自的核心功能還是不同的。

用 Gulp 完成的工作:

  • 模塊化
  • 編譯 sass
  • 合併優化壓縮 css
  • 校驗壓縮 js
  • 優化圖片
  • 添加文件指紋(md5)
  • 瀏覽器實時刷新

用 Webpack 完成的工作:

  • 打包所有 js 文件

安裝配置 Gulp 和 Webpack

首先安裝好最新的 nodejs(10.0.0)和 npm(6.0.0)。然後全局安裝 gulp,由於我用的 ES6 的語法,因此還安裝了 Babel:

  • 第一步:項目中新建以下目錄結構
dist
src
├──layout/
├──sass/
├──img/
├──js/
└──index.html
.babelrc
package.json
gulpfile.babel.js
  • 第二步:完成 package.json
{
  "name": "gulp-build",
  "version": "1.0.0",
  "description": "Gulp.js",
  "private": true,
  "scripts": { // 提供 npm 腳本用於編譯
    "start": "gulp",
    "watch": "gulp watch",
    "build": "gulp build --production"
  }
}
  • 第三步:完成 .babelrc
{
  "presets": ["env"], // 使用 babel 默認的轉換規則
  "plugins": []
}
  • 第四步:完成 gulpfile.babel.js
/**
 * Gulp Build File
 * Version: 2.0.0
 * User: NickHopps
 */

import gulp          from 'gulp';
import plugins       from 'gulp-load-plugins';
import yargs         from 'yargs';
import browser       from 'browser-sync';
import named         from 'vinyl-named';
import webpackStream from 'webpack-stream';
import webpack       from 'webpack'

const $ = plugins({
  rename: {
    'gulp-rev-append': 'rev',
    'gulp-file-include': 'fileinclude'
  }
});

const PORT = 8000;

const PRODUCTION = !!(yargs.argv.production);

const PATHS = {
  pages: {
    src: 'src/*.html',
    dist: 'dist/'
  },
  styles: {
    vendor: ['node_modules/foundation-sites/scss', 'node_modules/bootstrap/scss/'],
    src: 'src/sass/**/*.scss',
    dist: 'dist/css/'
  },
  scripts: {
    src: 'src/js/**/*.js',
    dist: 'dist/js/'
  },
  images: {
    src: 'src/img/**/*.{jpg,jpeg,png}',
    dist: 'dist/img/'
  }
};

const WPCONFIG = {
  mode: PRODUCTION ? 'production' : 'development',
  module: {
    rules: [{
      test: /.js$/,
      use: [{
        loader: 'babel-loader'
      }]
    }]
  },
  devtool: '#source-map'
};

/* Task to build files */
gulp.task('build', gulp.series(clean, gulp.parallel(html, image, sass, javascript)));

/* Default Task */
gulp.task('default', gulp.series('build', server, watch));

/* Task to watch */
gulp.task('watch', gulp.series(server, watch));

function html() {
  return gulp.src(PATHS.pages.src)
    .pipe($.fileinclude())
    .pipe($.cached('html'))
    .pipe($.rev())
    .pipe(gulp.dest(PATHS.pages.dist));
}

function image() {
  return gulp.src(PATHS.images.src)
    .pipe($.cached('image'))
    .pipe($.if(PRODUCTION, $.imagemin({progressive: true})))
    .pipe(gulp.dest(PATHS.images.dist));
}

function sass() {
  return gulp.src(PATHS.styles.src)
    .pipe($.plumber({errorHandler: $.notify.onError('Error: <%= error.message %>')}))
    .pipe($.sourcemaps.init())
    .pipe($.sass({includePaths: PATHS.styles.vendor}))
    .pipe($.cached('sass'))
    .pipe($.autoprefixer('last 2 version'))
    .pipe($.if(PRODUCTION, $.cssnano()))
    .pipe($.if(PRODUCTION, $.rename({suffix: '.min'})))
    .pipe($.sourcemaps.write(''))
    .pipe(gulp.dest(PATHS.styles.dist))
    .pipe(browser.reload({ stream: true }));
}

function javascript() {
  return gulp.src(PATHS.scripts.src)
    .pipe(named())
    .pipe($.cached('script'))
    .pipe(webpackStream(WPCONFIG, webpack))
    .pipe($.if(PRODUCTION, $.rename({suffix: '.min'})))
    .pipe(gulp.dest(PATHS.scripts.dist));
}

function clean() {
  return gulp.src(`${PATHS.pages.dist}/*`)
    .pipe($.clean());
}

function server(done) {
  browser.init({
    server: PATHS.pages.dist,
    port: PORT
  });
  done();
}

function watch() {
  gulp.watch('src/**/*.html').on('all', gulp.series(html, browser.reload));
  gulp.watch('src/img/**/*.{jpg,jpeg,png}').on('all', gulp.series(image, browser.reload));
  gulp.watch('src/sass/**/*.scss').on('all', sass);
  gulp.watch('src/js/**/*.js').on('all', gulp.series(javascript, browser.reload));
}
  • 第四步:安裝項目開發依賴
npm i -D babel-core babel-loader babel-preset-env browser-sync gulp gulp autoprefixer gulp-babel gulp-cached gulp-clean gulp-cssnano gulp-file-include gulp-if gulp-imagemin gulp-load-plugins gulp-notify gulp-plumber gulp-rename gulp rev-append gulp-sass gulp-sourcemaps vinyl-named webpack webpack-stream yargs

使用的各個包及其功能

babel-core        : babel 的核心部分
babel-loader      : babel 提供給外部的加載器
babel-preset-env  : babel 的 env 規則
browser-sync      : 提供瀏覽器實時更新
gulp              : gulp 主程序
gulp-autoprefixer : gulp 的 autoprefixer 插件
gulp-babel        : gulp 的 babel 插件
gulp-cached       : 緩存 gulp 的文件流
gulp-clean        : 清理文件
gulp-cssnano      : 壓縮 CSS
gulp-file-include : 在 HTML 中使用 include
gulp-if           : 提供 if 判斷功能
gulp-imagemin     : 壓縮圖片
gulp-load-plugins : 加載 gulp 插件
gulp-notify       : 彈窗提醒
gulp-plumber      : 處理 gulp 的錯誤流
gulp-rename       : 重命名
gulp-rev-append   : 給文件添加 MD5
gulp-sass         : sass 編譯插件
gulp-sourcemaps   : 生成 sourcemap
vinyl-named       : 給 vinyl 文件命名
webpack           : webpack 主程序
webpack-stream    : 把 webpack 轉成流供 gulp 處理
yargs             : 提供命令參數功能

使用 Gulp 和 Webpack 構建項目

創建好自己的項目文件之後,可運行下列命令構建:

npm start # 相當於執行 gulp
npm run watch # 相當於執行 gulp watch
npm run build # 相當於執行 gulp build --production
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章