應用層打包——Webpack

應用層打包工具——webpack

一開始學webpack其實有點逼不得已,做爲一個奉行保守主義的人,對於新東西都會有一種觀望的心態,這不是重點,我不會告訴你實際上是由於我懶,真的是由於Gulp在簡單的項目上已經足夠好用。css

Gulp自己只是一個框架,經過安裝各類插件,能夠實現從監聽-打包-合併-壓縮-編譯一系列流程,管道的概念在使用的過程當中跟它的前身Grunt比起來簡直舒服太多。(其實我也沒怎麼用過grunt……真的不是我懶,是由於出生太晚,我開始接觸這類工具時Gulp已經流行起來了)html

然而,在開始實踐組件化開發以後,發現一個有點邪乎的事情:gulp很難處理較爲複雜的依賴關係,各組件之間相互引入,寫配置文件時會寫得萬念俱灰。常常哭得把我家狗狗嚇出房間……前端

即使是一個最簡單的項目,也須要作出以下的路徑配置:webpack

image_1ba4d13c41k95suss3vtn0spj9.png-13kB

而且,React、Vue、Angular2,這三大MVVM框架都將webpack做爲官方推薦的打包工具,雖然仍是有點懷念Gulp,但不得不追隨神的指引——去跳Webpack的坑。web

webpack最先只是做爲一個打包工具出現,也就是隻操做js代碼,但因爲它智能尋找依賴的特色,很快插件數量就直追而上,就功能而言,如今基本可以徹底取代Gulp,加上基於Express框架開發的webpack-dev-server,讓它有了比Gulp家的browser-sync更讚的熱模塊替換功能,browser-sync在監聽到代碼修改後會重載代碼並刷新頁面,而Webpack的熱模塊替換能夠作到在不刷新頁面的狀況下替換代碼。gulp

你沒有聽錯,是在不刷新頁面的狀況下替換代碼sass

上面說的Webpack能夠智能查找依賴,是指:不管有多少個組件導入,它會本身尋找到對應的組件並打包在一塊兒,不須要使用者操心。服務器

若是是Gulp,則須要像上面那樣配置一大串路徑而且挨個注入監聽才行。(怎麼注入監聽,下面會有例子)框架

Gulp最得意的莫過於管道式的工做方式,但webpack垂手可得地就作到了,而且書寫起來更簡潔明瞭,例如一個最普通的sass打包函數,gulp首先要導入sass編譯模塊,配置好輸入路徑和輸出路徑,還須要將這個函數注入到監聽的服務裏:webpack-dev-server

var sass = require('sass');

gulp.task('sass', function() {
    return gulp.src('./src/*.scss')
        .pipe(sass())
        .pipe(gulp.dest("dist/"));
});

其實這很清晰明瞭,但有個前提,就是你須要知道哪些CSS是你的應用真正用到的,若是項目龐大,那就不得不硬着頭皮去維護一個無聊的依賴文件列表,或是乾脆包含一整個目錄的文件。

舉個栗子說清楚一些:假設你在開發時須要用到一張圖片,若是開發完成後你忘記把這張圖片從開發目錄中刪除,那恭喜你,即使這張圖片沒有被任何代碼引用,也照樣會成功打包進入到生產環境中。

這樣一來,頗有可能引入一些冗餘的代碼或者一些靜態文件,並且只能寄託命運讓你在某一天醍醐灌頂忽然發現這張圖片並無被引用。

形成這種隱患的緣由是:Gulp是根據路徑打包的,無論這個文件有沒有用到,只要它的位置在Gulp的處理序列內,它就會處理!而Webpack的巧妙在於,被用到的它纔打包,沒用到的則是視而不見!這就是按需打包的概念。

此外,還有一處事關體驗的地方,Gulp一旦檢測到報錯信息,就會退出,也就是你寫css代碼的時候多打了個分號,儘管眼睛看見了,然而身體的反射神經遲鈍,手不聽使喚按了保存,世界就毀滅了!你只能嘆息一聲,乖乖把分號刪掉,而後回到終端(控制檯)重啓Gulp服務。

猜猜是誰已經作過無數次這種事……

而Webpack會顯示報錯信息,可是不會宕機,等你修正了錯誤以後,它會從新編譯。有追求的工具就應該這樣!!!

上面列出了Gulp處理sass的代碼量,相對來講,webpack就簡單多了:

{
  test: /\.scss$/,
  use: 'style!css!sass'
}

// 不過這麼寫的話,css最終會被打包到js文件裏,若是想將css單獨打包出來,還須要安裝插件,最終寫成下面這樣

const ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = {
    module: {
        ...
        rules: [
            {
                test: /\.scss$/,
                use: ExtractTextPlugin.extract({
                    fallbackLoader: 'style-loader',
                    loader: 'css-loader!sass-loader'
                })
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin('./[name].css')
    ]
};

悲催,這好像比Gulp的代碼量更多……

不!!以上看到的都是表面現象!!

不信來份真的比較一下!

Gulp先來!

var gulp        = require('gulp');
var browserSync = require('browser-sync').create();
var sass        = require('gulp-sass');
var prefix      = require('gulp-autoprefixer');
var cssmin      = require('gulp-clean-css');
var htmlmin     = require('gulp-htmlmin');
var imagemin    = require('gulp-imagemin');
var jsmin       = require('gulp-uglify');
var rename      = require('gulp-rename');
var reload      = browserSync.reload;

var Asset = {       // 配置監聽路徑
    html: './src/html/*.html',
    js: './src/js/*.js',
    sass: './src/sass/*.scss',
    img: './src/images/*'
}

// 啓動靜態服務器
gulp.task('server', function() {
    browserSync.init({
        server: "."
    });
});

gulp.task('html', function() {      // html代碼的處理模塊
  gulp.src(Asset.html)
    .pipe(htmlmin({collapseWhitespace: true}))
    .pipe(gulp.dest('dist/'));
});

gulp.task('img', function() {       // 圖片的處理模塊,負責壓縮圖片什麼的
    return gulp.src(Asset.img)
        .pipe(imagemin({optimizationLevel: 7}))
        .pipe(gulp.dest('dist/images/'));
});

gulp.task('js', function() {        // js的處理模塊
  return gulp.src(Asset.js)
    .pipe(jsmin())
    .pipe(rename({suffix: '.min'}))
    .pipe(gulp.dest('dist/'));
});

gulp.task('sass', function() {      // sass處理模塊
    return gulp.src(Asset.sass)
        .pipe(sass())
        .pipe(prefix())
        .pipe(rename({suffix: '.min'}))
        .pipe(cssmin())
        .pipe(gulp.dest("dist/"))
        .pipe(reload({stream: true}));
});
gulp.task('watch', function() {     // 監聽服務
    gulp.watch(Asset.sass, ['sass'], reload);
    gulp.watch(Asset.js, ['js'], reload);
    gulp.watch(Asset.html, ['html'], reload);
    gulp.watch(Asset.img, ['img'], reload);
    gulp.watch("*").on('change', reload);
    gulp.watch("./dist/**/*.*").on('change', reload);
});

// 啓動
gulp.task('default', ['sass', 'img', 'html', 'js', 'server', 'watch']);

那些中括號裏面的東東就是注入

image_1ba4ggm2nct1glb1biotec15cv9.png-43kB

這裏說的注入跟Angular的依賴注入概念基本同樣!注入這個概念理解起來可能比較困難,換一個詞,應該叫反轉,概念是這樣的:通常的函數形參個數都……

呃……不跑題哈~

而後是Webpack選手

const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    context: __dirname + '/src',
    entry: {
        index: './js/index.js'
    },
    output: {
        filename: '[name].bundle.js',
        path: __dirname + '/dist'
    },
    module: {
        rules: [
            {
                test: /\.scss$/,
                use: ExtractTextPlugin.extract({
                    fallbackLoader: 'style-loader',
                    loader: 'css-loader!sass-loader'
                })
            },

            {
              test: /\.html$/,
              use: 'html-withimg-loader'
            },
            {
              test: /\.(png|jpg)$/,
              use: 'url-loader?limit=8192&name=images/[name].[ext]'
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin('./[name].css'),
        new HtmlWebpackPlugin({
            template: './html/index.html',
            filename: './index.html',
            chunks: ['index']
        })
    ]
};

以上兩份配置文件完成的是差很少的工做,代碼量……

呃……其實也就是半斤八兩,別天真了,成熟一點:少寫幾行代碼並不能體現出什麼優越性……

那麼從這裏開始,態度要轉彎了……

上面說了,文件較多的時候,配置Gulp的各類路徑會萬念俱灰,那麼……配置Webpack的時候會比萬念俱灰更加萬念俱灰,跟webpack相比,Gulp卻是顯得挺傻瓜。其實,單純比較代碼量的話,Webpack配置文件的代碼量確實是少些,然而Webpack太過於博大精深,要理解它須要付出很多努力。

學了Webpack是否是就能召喚神龍?

No!!經由Webpack打包出來的代碼可讀性不好,儘管不多人會閒着沒事去讀打包後的代碼,但前端近幾年迭代太快,有人詬病就會有人創新,號稱下一代打包工具的Rollup已經在崛起,它進一步升級了「按需打包」的概念,只是各種插件尚不成熟,所以就目前來看,將Webpack用做應用層的打包仍是最合適的。

等我跳了Rollup的坑再來跟各位介紹~

相關文章
相關標籤/搜索