webpack總結


一、Webpack 是什么?

webpack是一款模塊加載器兼打包工具,它能把各種資源,例如JS(含JSX)、coffee、樣式(含less/sass)、圖片等都作為模塊來使用和處理。 簡單說就是模塊加載器,通過使用Webpack,能夠像Node.js一樣處理依賴關系,然后解析出模塊之間的依賴,將代碼打包。

二、為什么需要打包?

  • 像sass,JSX等代碼雖然極大的提高了開發效率,但是本身並不被瀏覽器所識別,需要我們對其進行編譯和打包,變成瀏覽器識別的代碼

  • 模塊化(讓我們可以把復雜的代碼細化為小的文件)

  • 優化加載速度(壓縮和合並代碼來提高加載速度,壓縮可以減少文件體積,代碼合並可以減少http請求)

  • 使用新的開發模式

三、webpack主要特性

  • 同時支持CommonJS和AMD模塊(對於新項目,推薦直接使用CommonJS);

  • 串聯式模塊加載器以及插件機制,讓其具有更好的靈活性和擴展性,例如提供對CoffeeScript、ES6的支持;

  • 可以基於配置或者智能分析打包成多個文件,實現公共模塊或者按需加載;

  • 支持對CSS,圖片等資源進行打包,從而無需借助Grunt或Gulp(browserify只能打包JS文件);

  • 開發時在內存中完成打包,性能更快,完全可以支持開發過程的實時打包需求;

  • source map有很好的支持。

四、配置(webpack.config.js文件)

var webpack = require('webpack');
var path = require('path');
var SpritesmithPlugin = require('webpack-spritesmith');
module.exports = {
    // context: __dirname + '\\app', //上下文
    entry: path.resolve(__dirname, 'app/index.js'), //入口文件
    output: { //輸出文件
        path: path.resolve(__dirname, 'app/build/script'),
        filename: 'bundle.js'
    },
    module: {
        loaders: [ //加載器
            {test: /\.html$/, loader: 'raw'},
            // {test: /\.css$/, loader: 'style!css!postcss'},
            {test: /\.css$/, loader: 'style!css'},
            // {test: /\.(png|jpg|ttf)$/, loader: 'url?limit=8192'}
            {test: /\.(png|jpg|ttf)$/, loader: 'file!url?limit=8192'}
        ]
    },
    // postcss: function () {
    // return [autoprefixer];
    // },
    plugins: [ //插件
        new webpack.BannerPlugin('This file is created by shiddong.'),
        new SpritesmithPlugin({
            src: {
                cwd: path.resolve(__dirname, 'app/images/'),
                glob: '*.png'
            },
            target: {
               image: path.resolve(__dirname, 'app/build/images/sprite.png'),
               css: path.resolve(__dirname, 'app/build/css/sprite.css') //產生的樣式文件,圖片的樣式類名是 icon-圖片名
            },
           apiOptions: {
               cssImageRef: '../images/sprite.png'
           },
           spritesmithOptions: {
               algorithm: 'top-down'
           }
       })
    ]
};

 

五、webpack.config.js 配置詳解

(1)entry

入口文件,可以傳字符串,那說明入口文件只有一個;也可以傳數組或對象,指定多個入口文件。

有兩種語法:

<1> 先require path,再利用reslove方法對路徑進行解析。

var path = require('path');
entry: path.resolve(__dirname, 'app/index.js'), //入口文件

<2> 先定義好上下文路徑,那么entry中的路徑直接在這個路徑下開始

context: __dirname + '\\app', //上下文
entry: './index.js', //入口文件

注:webpack中引入的path是nodejs內置的package,用來處理路徑 —— 參考菜鳥教程node.js工具模塊。

當entry是數組的時候,里面同樣包含入口js文件,另外一個參數可以是用來配置webpack提供的一個靜態資源服務器,webpack-dev-server。webpack-dev-server會監控項目中每一個文件的變化,實時的進行構建,並且自動刷新頁面:

entry: [
    'webpack/hot/only-dev-server',
    './js/app.js'
]

當entry是個對象的時候,我們可以將不同的文件構建成不同的文件,按需使用。每一個鍵值對,就是一個入口文件。

 

備注:當然也有其他的辦法,如express框架,在index.html同路徑建立一個server.js,然后運行 node server.js即可。

// express 是一個基於Node.js 平台的web應用開發框架 —— 快速、極簡、開放
var port = 8000,
express = require('express'),
app = express();
app.use('/', express.static(__dirname));
app.listen(port);
console.log('Now serving http://localhost:' + port + '/index.html');

(2)output

生成打包文件的配置,可以指定path(路徑),當有多個入口文件時,還可以使用[name]、[hash]、[chunkhash]等值,來對應替換為入口的文件的配置。

output: { //輸出構建后的文件
    path: path.resolve(__dirname, 'app/build/script'),
    filename: 'bundle.js'
}


當entry中定義構建多個文件時,filename可以對應的更改為[name].js用於定義不同文件構建后的名字。

entry: {
    index: 'index.js'
},
output: {
    path: './js',
    filename: '[name].bundle.js' // [name] 會由entry中的鍵(這里是index)替換
}

(3)module

定義了對模塊的處理邏輯,在webpack中,所有的資源都被當做模塊。對於不同文件類型的資源,都有對應的loader。
模塊的加載相關配置定義在module.loaders中。


loaders: 加載器配置,通過正則表達式去匹配不同后綴的文件名,然后給它們定義不同的加載器。它可以轉換項目中的資源文件,比如說給css文件定義串聯的兩個加載器(!用來定義級聯關系),順序是從右向左使用:

module: {
    loaders: [
        { test: /\.js?$/, loaders: ['react-hot', 'babel'], exclude: /node_modules/ },
        { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'},
        { test: /\.css$/, loader: "style!css" },
        { test: /\.less/, loader: 'style-loader!css-loader!less-loader'}
    ]
}


其中,exclude: /node_modules/,
exclude,include手動添加屏蔽不需要處理的文件(文件夾)或必須處理的文件(文件夾)

比較常用的loader:

css-loader: 將樣式打包成字符串。
style-loader:將樣式字符串添加到頁面的style標簽中 

還可以添加用來定義png、jpg這樣的圖片資源在大於8k時正常打包,小於8k時自動處理為base64圖片的加載器:

{ test: /\.(png|jpg)$/,loader: 'url-loader?limit=8192'}

其中,? 表示加載器支持通過查詢字符串的方式接受參數。

給css和less還有圖片添加了loader之后,我們不僅可以像在node中那樣require js文件了,我們還可以require css、less甚至圖片文件:

require('./bootstrap.css');
require('./myapp.less');
var img = document.createElement('img');
img.src = require('./glyph.png');

這樣require來的文件會內聯到 js bundle中。如果我們需要保留require的寫法又想把css文件單獨拿出來,可以使用[extract-text-webpack-plugin]插件。

(4)plugins

插件,它可以干很多很多的事情,非常強大,官方提供了很多插件,第三方也可以寫插件。對於用到的插件,只需要將插件new出來放到數組中即可。

<1> BannerPlugin 內置插件來實踐插件的配置和運行,這個插件的作用是給輸出的文件頭部添加注釋信息。
<2> ProvidePlugin 插件的作用是自動加載jquery模塊,也就是說將jquery變成了全局的模塊,當然我們需要在index.html中使用script標簽導入。


[原因:由於jquery沒有模塊化的概念,也沒有適配webpack,所以我們使用jquery時,需要在index.html中導入,然后使用 ProvidePlugin 插件使其自動加載。]

plugins: [
    new webpack.BannerPlugin('This file is created by shiddong.'),
    // 此插件會自動加載jquery,解決jquery無法引用的問題
    new webpack.ProvidePlugin({
        $: "jquery",
        jQuery: "jquery",
        window.jQuery: "jquery"
    })
]

(5)導入使用

只需要在index.html中導入bundle.js,<script src="bundle.js">script>,不需要在index.html中導入js文件了,只需要使用 require 導入模塊就行,webpack會自己解決它們之間的依賴。

<1> 依賴第三方庫可以將其下載到node-modules中,然后導入相應的模塊:

//require('angular')導入的是 node_modules 中的angular模塊
require("angular"); //var angular = require('angular');
require("bootstrap");
var demoApp = angular.module('demoApp', []);

 

<2> 或者類似於導入本地的js文件,可以建立一個 common.js 文件,然后導入 angular 和 bootstrap。然后在使用的時候直接require('./common')

(6)處理圖片

loaders: [
    {
      test: /\.(png|jpg)$/,
      loader: 'url-loader?limit=8192'
    }
  ]

其中,

<1> test 屬性代表可以匹配的圖片類型,除了 png、jpg 之外也可以添加 gif 等,以豎線隔開即開。
<2> loader 后面 limit 字段代表圖片打包限制,這個限制並不是說超過了就不能打包,而是指當圖片大小小於限制時會自動轉成 base64 碼引用。上例中大於8192字節的圖片正常打包,小於8192字節的圖片以 base64 的方式引用。

//Option 1,使用 ?
{ test: /\.png$/,
   loader: 'url-loader?limit=1024'
}
//Option 2,使用query屬性
{ test: /\.png$/,
  loader: 'url-loader',
  query: {limit=1024}
}

<3> url-loader 后面除了 limit 字段,還可以通過 name 字段來指定圖片打包的目錄與文件名:

loaders: [
    {
      test: /\.(png|jpg)$/,
      loader: 'url-loader?limit=8192&name=images/[hash:8].[name].[ext]'
    }
  ]

name 字段指定了在打包根目錄(output.path)下生成名為 images 的文件夾,並在原圖片名前加上8位 hash 值。

(7)生成雪碧圖

var path = require('path');
var SpritesmithPlugin = require('webpack-spritesmith'); //安裝雪碧圖依賴模塊:webpack-spritesmith
module.exports = {
    entry: path.resolve(__dirname, 'app/main.js'),
    output: {
        path: path.resolve(__dirname, 'build'),
        filename: 'bundle.js'
    },
    plugins: [
        new SpritesmithPlugin({
            src: {
                cwd: path.resolve(__dirname, 'app/images/'),
                glob: '*.png'
            },
            target: {
                image: path.resolve(__dirname, 'build/images/sprite.png'),
                css: path.resolve(__dirname, 'build/css/sprite.css') //產生的樣式文件,圖片的樣式類名是 icon-圖片名
            },
            apiOptions: {
                cssImageRef: '../images/sprite.png'
            },
            spritesmithOptions: {
                algorithm: 'top-down'
            }
        })
    ]
};

鏈接:https://zhuanlan.zhihu.com/p/23873229


其他:

(8)resolve

定義解析模塊路徑時的配置,最常用的就是extensions,可以用來指定模塊的后綴,這樣在引入模塊是就不需要寫后綴了,會自動補全。
webpack在構建包的時候會按目錄的進行文件的查找,resolve屬性中的extensions數組中用於配置程序可以自行補全哪些文件后綴:

resolve:{
    extensions:['', '.js', '.json']
}

然后我們想要加載一個js文件時,只要require('common')就可以加載common.js文件了。

(9)externals

當我們想在項目中require一些其他的類庫或者API,而又不想讓這些類庫的源碼被構建到運行時文件中,這在實際開發中很有必要。此時我們就可以通過配置externals參數來解決這個問題:

externals: {
    "jquery": "jQuery"
}

這樣我們就可以放心的在項目中使用這些API了:var jQuery = require(“jquery”);

(10)context

當我們在require一個模塊的時候,如果在require中包含變量,像這樣:

require("./mods/" + name + ".js");

那么在編譯的時候我們是不能知道具體的模塊的。但這個時候,webpack也會為我們做些分析工作:
    1.分析目錄:'./mods';
    2.提取正則表達式:'/^.*.js$/';


於是這個時候為了更好地配合webpack進行編譯,我們可以給它指明路徑,像在cake-webpack-config中所做的那樣(我們在這里先忽略abcoption的作用):

var currentBase = process.cwd();
var context = abcOptions.options.context ? abcOptions.options.context :
path.isAbsolute(entryDir) ? entryDir : path.join(currentBase, entryDir);

 

六、按需加載

傳統的模塊打包工具(module bundlers)最終將所有的模塊編譯生成一個龐大的bundle.js文件。但是在真實的app里邊,“bundle.js”文件可能有10M到15M之大可能會導致應用一直處於加載中狀態。因此Webpack使用許多特性來分割代碼然后生成多個“bundle”文件,而且異步加載部分代碼以實現按需加載。

七、執行打包

如果通過npm install -g webpack方式安裝webpack的話,可以通過命令行直接執行打包命令,比如:
$ webpack –config webpack.config.js
這樣就會讀取當前目錄下的webpack.config.js作為配置文件執行打包操作。默認查找webpack.config.js,所以我們在這里只需要執行webpack 命令即可。

八、常用webpack命令

在開發環境構建一次
webpack
構建並生成源代碼映射文件
webpack -d
在生成環境構建,壓縮、混淆代碼,並移除無用代碼
webpack -p
快速增量構建,可以和其他選項一起使用
webpack –watch
progress 顯示打包過程中的進度,colors打包信息帶有顏色顯示
webpack –progress –colors

九、理解文件路徑

require(‘lodash’) // 從模塊目錄查找
require(‘./file’) // 按相對路徑查找
CSS 及圖片的引用
require(‘./bootstrap.css’);
require(‘./myapp.less’);
var img = document.createElement(‘img’);
img.src = require(‘./weibo.png’);

十、其他插件功能

OccurenceOrderPlugin:給經常使用的模塊分配最小長度的id,這樣可以減少文件大小。
HotModuleReplacementPlugin:是熱替換,熱替換和dev-server的hot有什么區別?不用刷新頁面,可用於生產環境。
NoErrorsPlugin:在打包時不會因為錯誤而中斷
ProvidePlugin: 定義一些在import時能自動引入的變量,如定義了 $: 'jquery' 后,可以在文件中直接使用$,webpack可以自動幫你加上 var $ = require('jquery')。
DllPlugin: 將一些模塊預編譯,類似windows里的dll,可以在項目中直接使用,無需再構建。注意要在output中指定 library ,並在DllPlugin中指定與其一致的 name ,在有多個入口時可以使用 [name] 和 [hash] 來區分,因為這個參數是要賦值到global上的,所以這里使用 [hash] 不容易出現變量名沖突的情況。
DllReferencePlugin: 引用之前打包好的dll文件,注意下context參數,這個應該根據manifest.json文件中的引用情況來賦值,如果引用的都是npm安裝的庫,這里就填項目根目錄就好了。
DefinePlugin: 可以定義編譯時的全局變量,有很多庫(React, Vue等)會根據 NODE_ENV 這個變量來判斷當前環境。為了盡可能減少包大小,在生產環境中要定義其為 JSON.stringify(“production”)
optimize.UglifyJsPlugin: 配置壓縮代碼。
optimize.DedupePlugin: 可以減少重復文件數。
ExtractTextPlugin: 可以將所有css文件打包到一個css文件中。

 

十一、參考資料

1、webpack參考鏈接 
http://webpackdoc.com

2、Webpack入門(其文章底部有些鏈接可以參考)———— 基本概念、webpack.config.js配置詳解
http://blog.csdn.net/liujie19901217/article/details/51026943

3、入門 Webpack,看這篇就夠了(很好,工作方式對比清晰、參數的表格清晰)******
https://segmentfault.com/a/1190000006178770#articleHeader8

4、[譯] 通過 Webpack 實現 AngularJS 的延遲加載  ******
https://toutiao.io/posts/46gvgm/preview

5、30分鍾手把手教你學webpack實戰(內容比較全面、詳細)******
http://www.cnblogs.com/tugenhua0707/p/4793265.html

6、Webpack + Angular的組件化實踐
https://segmentfault.com/a/1190000003915443

7、為何webpack風靡全球?三大主流模塊打包工具對比
http://www.techug.com/webpack-requirejs-browserify

webpack: code spliting / loader/plugin

8、前端構建工具漫談,fis3、webpack、rollup.js 
https://zhuanlan.zhihu.com/p/20933749

9、輕松入門webpack——官方文檔解讀
http://shuaihua.cc/article/webpack/webpack.php

10、關於雪碧圖的詳細介紹
https://zhuanlan.zhihu.com/p/23873229?utm_source=tuicool&utm_medium=referral

11、boi剖析 - 基於webpack的css sprites實現方案
http://www.cnblogs.com/ihardcoder/p/6053231.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM