Gulp&Webpack搭建屬於自己的特性化前端腳手架

relsoul發表於2018-02-05

前言

之前看了很多教程,比如vue的腳手架,gulp的腳手架和大牛自己寫的腳手架。發現沒有什麼是銀彈能夠滿足公司業務的需要又能夠開發的爽。所以結合公司業務的特性,自己動手用gulp和webpack寫了一套適合我司的腳手架。

使用範圍

  • 專題等靜態頁面多
  • 後臺主導邏輯業務,前端主導互動等
  • 需要整合es6,scss,eslint等

上面只列出了三點。其實適用範圍還有挺多。

技術棧

  • webpack^3
  • gulp-webpack^1.5
  • gulp-pug^3.3
  • gulp^3.9
  • eslint^4
  • eslint-config-alloy^1.4
  • babel^6.5
  • gulp-postcss^6.2
  • autoprefixer^6.4
  • browser-sync^2.1
  • gulp-sass^2.3

當然還有一些就不一一列出了,這裡只列出幾個主要的模組 下面來解釋一下上述模組對應的功能。s

webpack

我個人是比較討厭webpack做除了js以外的事情,包括打包css,copy等。 我不否認webpack的強大,但是我還是更希望術業有專攻,webpack只負責js相關的事情就好。 所以webpack負責的範圍為 es6->es5,eslint的檢測,js的sourcemap檔案的生成。

babel

這個沒什麼好說的,babel也提供了cli的形式,但這裡整合進了webpack當中。

gulp-sourcemaps&gulp-sass&gulp-postcss&autoprefixer

這些都是用來處理sass的相關,比如 sass的編譯,css的瀏覽器相容性處理,css的sourcemap對應。

browser-sync

webpack也提供了靜態伺服器並且支援增量重新整理,但是這裡我選擇使用browser-sync提供了靜態伺服器。 browser-sync可以快速的搭建起一個靜態伺服器並且支援api級別的介面重新整理。所以我可以很方便的去自動或者手動呼叫重新整理頁面功能

eslint&eslint-config-alloy

這裡使用的是騰訊alloy團隊的eslint檢測配置,個人比較喜歡此方案。

gulp

最後說說gulp,所有的模組都是由gulp來主導並且粘合的。為什麼這麼說。 因為所有的模組都不知道啥時候去呼叫啥時候去做該做的事情,那麼這裡就用到了gulp.watch和gulp.src。 簡單來個例子

/**
 *
 * 監聽檔案
 *
 */
gulp.task("watch", () => {
    let bs = browserSync.init({
        server: {
            baseDir: "./",
            directory: true,
        },
        open: false,
        ui: {
            port: 3008,
            weinre: {
                port: 3009
            }
        },
        port: devConf.gulp.webPort?devConf.gulp.webPort:3012,
        ghostMode: false
    });
    gulp.watch(["dev/jade-html/**/*.pug", "dev/jade-component/**/*.pug"], ["compile:pug"]);
    gulp.watch(["dev/js/**/*.js"], ["compile:js"]);
    gulp.watch(["dev/sass/**/*.scss"], ["compile:sass"]);
    gulp.watch(["dev/img/**/*.*", "dev/lib/**/*.*"], ["copy"]);
});
複製程式碼

比較簡單,大意就是監聽某些檔案變動的時候執行對應的task。

使用問題

  1. gulp-webpack編譯每次都是重新編譯

gulp-webpack每次呼叫webpack都需要重新編譯,所以時間會很長很長很長。其實還好 個人測試中,webpack增量編譯時間為1s的話,gulp-webpack編譯時間為2s-3s左右。如果對時間不是特別敏感的可以忽略。 當然這個問題還是有解決方案的,也是之前看的某篇文章提出的 使用proxy機制, webpack的增量編譯重新整理調動browserSync的重新整理。 這樣一來可以做到同步重新整理 並且不適用gulp-webpack來重新編譯轉而使用webpack的增量編譯和靜態伺服器功能。當然具體怎麼實現還沒有研究 但是可以得出的結論就是 不難。

  1. pug,sass檔案過多每次都編譯出額外的檔案

這個什麼意思呢?看程式碼說話

gulp.task("compile:sass", (event) => {
    return gulp.src('dev/sass/output/**/*.scss')
    //.pipe(changed("dist/css")) disabled changed sass需要全部編譯..
        .pipe(sourcemaps.init())
        .pipe(sass(sassOptions).on("error", sass.logError))
        .pipe(gulpif(extBase64File,base64({
            maxImageSize: 15*1024, // bytes 15KB
        })))
        .pipe(postcss([autoprefixer()]))
        .pipe(sourcemaps.write("./"))
        .pipe(gulp.dest("dist/css"))
        .pipe(gulp.dest(copyCssPath))
        .on("finish", () => {
            browserReload()
        })
});
複製程式碼

這裡如果編譯的話 每次都會把output下面所有的scss檔案編譯出來,同理 編譯pug的時候也是一樣會把某個資料夾下面的所有pug全部編譯出來。當然解決辦法也很簡單

配置檔案,沒錯,再使用額外的配置檔案,比如

const devConf=require("./dev-conf");
let compilePugFile= devConf.gulp.compilePugFile?devConf.gulp.compilePugFile:["dev/jade-html/**/*.pug"];
let compileSassFile= devConf.gulp.compileSassFile?devConf.gulp.compileSassFile:["dev/sass/output/**/*.scss"];
let copyJsPath=devConf.gulp.copyJsPath?devConf.gulp.copyJsPath:`/public/dist/js`;
let copyCssPath=devConf.gulp.copyCssPath?devConf.gulp.copyCssPath:`/public/dist/css`;
let copyImgPath=devConf.gulp.copyImgPath?devConf.gulp.copyImgPath:`/public/img`;
複製程式碼

使用額外的配置檔案來做到按需編譯和載入

  1. prod和dev如何區分。

這個其實很簡單 可以使用npm run 也可以使用gulp的多個任務方式

gulp.task('default::production',['set-env::production','watch']);

/**
 * 設定環境變數
 */
gulp.task('set-env::production',()=>{
    webpackEnv='production';
    return Promise.resolve(true);
});
複製程式碼

需要dev模式那麼直接 gulp就好 需要生產模式就 gulp default::production 這裡的設定變數可以通過process.env來設定,這樣就可以在全域性拿到引數了。

    process.env.NODE_ENV = 'dev'||'prod';
複製程式碼
  1. 報錯退出機制

gulp的每次報錯都會導致gulp退出,比如呼叫gulp-webpack編譯js的時候 某個js錯誤導致整個gulp退出, 當然解決辦法也很簡單

const plumber = require('gulp-plumber');
const webpackFile=require("./webpack.config.js");
gulp.task("compile:js", () => {
    return gulp.src("dev/js/main.js")
        .pipe(plumber({errorHandler:function () {
                
            }}))
        .pipe(webpack(webpackFile({env:webpackEnv})))
        .pipe(gulp.dest("dist/js/"))
        .pipe(gulp.dest(copyJsPath))
        .on("finish", () => {
            browserReload()
        })
});

複製程式碼

使用gulp-plumber便可以解決問題了, 因為webpack自帶錯誤提示功能 所以不需要gulp-plumber再次報錯, 這裡就把errorHandler給定義了空函式不做處理。

改進

基本上說到這裡整個方案就差不多了。 這一套方案的好處就是 html,css,js分離並且互不影響。 html,css,js都使用了代替品來方便開發 比如html使用了pug(說pug不好的同學,你們有巢狀過10層以上的html嗎?),css使用了sass,js使用了es6,並且三者可以快速替換和代替 比如 我哪天不想使用pug了 那麼可以快速使用ejs等其他模板 只需要改改gulp的task, 哪天我想使用vue了 那麼只需要改改webpack的配置檔案,並且增加gulp.watch範圍就可以了。 是不是聽著很強大?難道就沒什麼弊端麼?

答案是....沒有...哈哈哈哈 有點狂。 不過其實還是有很多問題的,比如webpack的效能,在檔案量大的話 其實會編譯的比較久,會影響開發效率,這個問題在後期是不可忽視的。 耦合過大也是個問題,所有的編譯都是依靠檔案目錄來做分配的,如果某個目錄變了那麼很多東西都需要修改重來。 等等... 不過後面再慢慢改進吧,畢竟從一開始自己搭建腳手架到現在公司中穩定使用也經歷了重構—>改版->抽離->放棄(???什麼鬼)。

這裡給出一個vue2.0的demo

相關文章