webpack配置


一、全面理解webpack
1、什么是 webpack?
webpack是近期最火的一款模塊加載器兼打包工具,它能把各種資源,例如JS(含JSX)、coffee、樣式(含less/sass)、圖片等都作為模塊來使用和處理,它能有Grunt或Gulp所有基本功能。webpack的官網是  https://webpack.github.io/ ,文檔地址是 https://webpack.github.io/docs,官網對webpack的定義是MODULE BUNDLER,他的目的就是把有依賴關系的各種文件打包成一系列的靜態資源。 請看下圖:
2、webpack 的優勢
其優勢主要可以歸類為如下幾個:
  1. webpack 是以 commonJS 的形式來書寫腳本滴,但對 AMD/CMD 的支持也很全面,方便舊項目進行代碼遷移。
  2. 支持很多模塊加載器的調用,可以使模塊加載器靈活定制,比如babel-loader加載器,該加載器能使我們使用ES6的語法來編寫代碼;less-loader加載器,可以將less編譯成css文件;
  3. 開發便捷,能替代部分 grunt/gulp 的工作,比如打包、壓縮混淆、圖片轉base64等。
  4. 可以通過配置打包成多個文件,有效的利用瀏覽器的緩存功能提升性能。
3、wepback它的目標是是什么?
webpack它能將依賴的模塊轉化成可以代表這些包的靜態文件
  • 將依賴的模塊分片化,並且按需加載
  • 解決大型項目初始化加載慢的問題
  • 每一個靜態文件都可以看成一個模塊
  • 可以整合第三方庫
  • 能夠在大型項目中運用
  • 可以自定義切割模塊的方式

4、webpack較之其他類似工具有什么不同?

  • 有同步和異步兩種不同的加載方式
  • Loader,加載器可以將其他資源整合到JS文件中,通過這種方式,可以講所有的源文件形成一個模塊
  • 優秀的語法分析能力,支持 CommonJs AMD 規范
  • 有豐富的開源插件庫,可以根據自己的需求自定義webpack的配置

5、webpack為什么要將所有資源放在一個文件里面?

我們知道,對於瀏覽器來說,加載的資源越少,響應的速度也就越快,所以有時候我們為了優化瀏覽器的性能,會盡可能的將資源合並到一個主文件app.js里面。但是這導致的很大的缺點:

  • 當你的項目十分龐大的時候,不同的頁面不能做到按需加載,而是將所有的資源一並加載,耗費時間長,性能降低。
  • 會導致依賴庫之間關系的混亂,特別是大型項目時,會變得難以維護和跟蹤。比如:哪些文件是需要A模塊加載完后才能執行的?哪些頁面會受到多個樣式表同時影響的? 等許多問題。

而webpack可以很好的解決以上缺點,因為它是一個十分聰明的模塊打包系統,當你正確配置后,它會比你想象中的更強大,更優秀。

二、開啟wbpack之旅
安裝步驟如下:

1、生成package.json文件;

先裝好node和npm,因為webpack是一個基於node的項目。然后首先我們需要在根目錄下生成package.json文件,需要進入項目文件內根目錄下執行如下命令:npm init

如上通過一問一答的方式后會在根目錄下生成package.json文件,如下所示:

2 . 通過全局安裝webpack
執行命令如下:npm install -g webpack 如下所示:
在c盤下會生成node_modules文件夾中會包含webpack,此時此刻我們可以使用webpack命令了;
在常規項目中把webpack依賴加入到package.json
npm init npm install webpack --save
更詳盡的安裝方法個可以參考 webpack安裝
3. 配置webpack
每個目錄下都必須有一個webpack.config.js,它的作用就好比Gulpfile.js、或者 Gruntfile.js,就是一個項目配置,告訴webpack需要做什么。
首先先貼上一個比較完整的webpack.config.js的代碼,再詳細介紹:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//詳細的webpack.config.js結構分析:
var  path = require( 'path' );
var  webpack = require( 'webpack' );
var  HtmlWebpackPlugin = require( 'html-webpack-plugin' );
var  TransferWebpackPlugin = require( 'transfer-webpack-plugin' );
 
module.exports = {
     devtool:  'source-map' , //由於打包后的代碼是合並以后的代碼,不利於排錯和定位,只需要在config中添加,這樣出錯以后就會采用source-map的形式直接顯示你出錯代碼的位置。
     //noParse:[/jquery/],//表示跳過jquery,不對其進行編譯,這樣可以提高打包的速度
     //頁面入口文件配置
     entry: {
         page1:  "./src/index.js" ,
         //page2: ["./src/index.js", "./src/main.js"],支持數組形式,將加載數組中的所有模塊,但以最后一個模塊作為輸出
     },
     //入口文件輸出配置
     output: {
         path:  "dist/js/page" ,
         filename:  "[name].bundle.js" , // page1.bundle.js 和 page2.bundle.js,並存放到 ./dist/js/page 文件夾下。
         publicPath:  "/dist/"     //網站運行時的訪問路徑。
     },
     resolveLoader: {
         //指定默認的loader路徑,否則依賴走到上游會找不到loader
         root: path. join (__dirname,  'node_modules' ),
         alias: { //給自己寫的loader設置別名
             "seajs-loader" : path.resolve( __dirname,  "./web_modules/seajs-loader.js"  )
         }
     },
     //新建一個開發服務器,並且當代碼更新的時候自動刷新瀏覽器。
     devServer: {
         historyApiFallback:  true ,
         noInfo:  true ,
         hot:  true ,
         inline:  true ,
         progress:  true ,
         port:9090  //端口你可以自定義
     },
     module: {
         // module.loaders 是最關鍵的一塊配置。它告知 webpack每一種文件都需要使用什么加載器來處理:
         loaders: [
         { test: /\.css$/, loader:  'style-loader!css-loader'  }, //.css 文件使用 style-loader 和 css-loader 來處理.
         //{ test: /\.css$/, loader: 'style!css' },其他寫法1、"-loader"其實是可以省略不寫的,多個loader之間用“!”連接起來。
         //{ test: /\.css$/, loaders: ["style", "css"] },其他寫法2、用loaders數組形式;
         //.scss 文件使用 style-loader、css-loader 和 sass-loader 來編譯處理。
         //在chrome中我們通過sourcemap可以直接調試less、sass源文件文件
         { test: /\.scss$/, loader:  'style!css!sass?sourceMap' },
         { test: /\.less$/, loader:  'style!css!less?sourceMap' }, //.less 文件使用 style-loader、css-loader 和 less-loader 來編譯處理
         //.js 文件使用babel-loader來編譯處理,設置exclude用來排除node_modules這個文件夾中的代碼
         { test: /\.js$/, loader:  'babel!jsx' ,exclude: /node_modules/ }, 
         { test: /\.jsx$/, loader:  "jsx-loader?harmony"  }, //.jsx 文件使用 jsx-loader 來編譯處理
         { test: /\.json$/,loader:  'json' },
         //{ test: /\.(png|jpg|jpeg|gif)$/, loader: 'url-loader?limit=8192'}, //圖片文件使用 url-loader 來處理,小於8kb的直接轉為base64
         {test: /\.(png|jpg|gif|svg)$/,loader:  'url' ,
             query: {limit: 10000,name:  '[name].[ext]?[hash]' } //設置圖片名稱擴展名
         },
         { test: /\.jade$/, loader:  "jade-loader"  }, //.jade 文件使用 jade-loader 來編譯處理
         { test: /\.ejs$/, loader:  "ejs-loader"  }, //.ejs 文件使用 ejs-loader 來編譯處理
         { test: /\.handlebars$/, loader:  "handlebars-loader"  }, //.handlebars 文件使用handlebars-loader來編譯處理handlebars模板文件
         { test: /\.dot$/, loader:  "dot-loader"  }, //.dot 文件使用 dot-loader 來編譯處理dot模板文件
         { test: /\.vue$/, loader:  "vue-loader"  }, //.vue 文件使用 vue-loader 來編譯處理
         { test: /\.coffee$/, loader:  'coffee-loader'  }, //.coffee 文件使用 coffee-loader 來編譯處理
         { test: /\.html$/,loader:  'vue-html' },
         { test: /\.woff$/,loader:  "url?limit=10000&minetype=application/font-woff" },
         { test: /\.ttf$/,loader:  "file" },
         { test: /\.eot$/,loader:  "file" },
         { test: /\.svg$/,loader:  "file" }
         ]
     },
     //分內置插件和外置插件
     plugins: [
         //使用了一個 CommonsChunkPlugin 的插件,它用於提取多個入口文件的公共腳本部分,然后生成一個common.js來方便多頁面之間進行復用。
         new  webpack.optimize.CommonsChunkPlugin( 'common.js' ),
         new  webpack.optimize.UglifyJsPlugin({ //壓縮文件
           compressor: {
             warnings:  false , //supresses warnings, usually from module minification
           },
           except: [ '$super' '$' 'exports' 'require' ]     //排除關鍵字(可選)
         }),
         new  webpack.DefinePlugin({ // definePlugin 接收字符串插入到代碼當中, 所以你需要的話可以寫上 JS 的字符串
              __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV ||  'true' )),
              __PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE ||  'false' ))
         }),
         new  webpack.ProvidePlugin({ //把一個全局變量插入到所有的代碼中,支持jQuery plugin的使用;使用ProvidePlugin加載使用頻率高的模塊
              //provide $, jQuery and window.jQuery to every script
              $:  "jquery" ,
              jQuery:  "jquery" ,
              "window.jQuery" "jquery"
          }),
         new  webpack.NoErrorsPlugin(),  //允許錯誤不打斷程序
         new  TransferWebpackPlugin([  //把指定文件夾下的文件復制到指定的目錄
           { from 'www' }
         ], path.resolve(__dirname, "src" )),
         new  HtmlwebpackPlugin({ //用於生產符合要求的html文件;
            title:  'Hello World app' ,
            filename:  'assets/admin.html'
         })
     ],
     //其它解決方案配置
     resolve: {
         root:  'E:/github/flux-example/src' //絕對路徑, 查找module的話從這里開始查找(可選)
         extensions: [ '' '.js' '.html' '.css' '.scss' ],  //自動擴展文件后綴名,意味着我們require模塊可以省略不寫后綴名
         alias: {                             //模塊別名定義,方便后續直接引用別名,無須多寫長長的地址//后續直接 require('AppStore') 即可
             AppStore :  'js/stores/AppStores.js' ,
             ActionType :  'js/actions/ActionType.js' ,
             AppAction :  'js/actions/AppAction.js'
         },
         modulesDirectories: [ //取相對路徑,所以比起 root ,所以會多很多路徑。查找module(可選)
              'node_modules' ,
              'bower_components' ,
              'lib' ,
              'src'
         ]
     }
     
};
 
if  (process.env.NODE_ENV ===  'production' ) {
   module.exports.devtool =  '#source-map'
   // http://vue-loader.vuejs.org/en/workflow/production.html
   module.exports.plugins = (module.exports.plugins || []).concat([
     new  webpack.DefinePlugin({
       'process.env' : {
         NODE_ENV:  '"production"'
       }
     }),
     new  webpack.optimize.UglifyJsPlugin({
       compress: {
         warnings:  false
       }
     }),
     //為組件分配ID,通過這個插件webpack可以分析和優先考慮使用最多的模塊,並為它們分配最小的ID
     new  webpack.optimize.OccurenceOrderPlugin()
   ])
}

plugins中包含很多的內置插件和外部插件,它們都有各自的功能,用來處理相關的文件,這里只是羅列了部分,具體用法請看webpack入門和實戰(二):全面理解和運用plugins和loader

就像我在前面提到的,webpack.config.js的寫法和在Node里的寫法相同,我們主要看的就是文件中的module.exports里面的內容
  • entry 是指入口文件的配置項,它是一個數組的原因是webpack允許多個入口點。
  • output是指輸出文件的配置項
    • path - 表示輸出文件的路徑
    • filename - 表示輸出文件的文件名
  • plugins 顧名思義,使用插件可以給webpack添加更多的功能,使webpack更加的靈活和強大,webpack有兩種類型的插件:
    • webpack內置的插件
// 首先要先安裝webpack模塊
var webpack = require("webpack");
module.exports = {
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false,
      },
    })
};
    •  webpack外置插件
//npm install component-webpack-plugin 先要在安裝該模版
var ComponentPlugin = require("component-webpack-plugin");
module.exports = {
    plugins: [
        new ComponentPlugin()
    ]
}

更多的插件以及插件的用法,大家可以到webpack的插件上查看。

  • module 配置處理文件的選項
  • loaders 一個含有wepback中能處理不同文件的加載器的數組
  • test 用來匹配相對應文件的正則表達式
  • loaders 告訴webpack要利用哪種加載器來處理test所匹配的文件
  • loaders 的安裝方法
        $ npm install xxx-loader --save-dev
  • resolve:其它解決方案配置;
    • resolve.root,絕對路徑, 查找module的話從這里開始查找(可選)
    • resolve.modulesDirectories,取相對路徑,所以比起 root ,所以會多 parse 很多路徑。查找module(可選)
    • resolve.extensions,自動擴展文件后綴名,意味着我們require模塊可以省略不寫后綴名
    • resolve.alias,模塊別名定義,方便后續直接引用別名,無須多寫長長的地址
三、利用webpack實現在頁面上合理使用打包過后的js文件和圖片
示例如下:
webpack_test目錄結構如下:
最終完成版的目錄結構為:
 index.html代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo1</title>
</head>
<body>
    <div id="content"></div>
    <img src="./build/img/demo.png">
    <script src="./build/js/index.js"></script>
</body>
</html>

index.js代碼如下:

require('./index.css');

index.css代碼如下:

#content{
    width:121px;
    height:140px;
    background-color: red;
}
demo.png自己隨便找一張即可;
根據webpack.config.js的配置情況,操作步驟如下:
  • 全局安裝webpack,npm install webpack -g
  • 進入到webpack_test目錄下,初始化生成package.json文件,npm init
  • 需要安裝的loader有css-loader、style-loader、url-loader,webpack, npm install css-loader style-loader url-loader webpack--save-dev
  • 執行webpack,生成打包過后的build/js/index.js,build/img/demo.png
  • 在index.html中引入即可

效果如下:

 源碼地址為: http://download.csdn.net/detail/wdlhao/9612173,有需要的同學可以自行下載練習;
 四、理解webpack支持commonJS和AMD/CMD兩種模塊機制進行打包
  1.AMD/CMD模式:
     AMD 規范在這里: https://github.com/amdjs/amdjs-api/wiki/AMD,CMD 規范在這里: https://github.com/seajs/seajs/issues/242
  • AMD(Asynchronous Module Definition) 是 RequireJS 在推廣過程中對模塊定義的規范化產出。(即RequireJS模塊規范)
RequireJS是一個工具庫,主要用於客戶端的模塊管理。它可以讓客戶端的代碼分成一個個模塊,實現異步或動態加載,從而提高代碼的性能和可維護性。它的模塊管理遵守 AMD規范(Asynchronous Module Definition)。RequireJS的基本思想是,通過define方法,將代碼定義為模塊;通過require方法,實現代碼的模塊加載。首先,將require.js嵌入網頁,然后就能在網頁中進行模塊化編程了。<script data-main="scripts/main" src="scripts/require.js"></script>上面代碼的data-main屬性不可省略,用於指定主代碼所在的腳本文件,在上例中為scripts子目錄下的main.js文件。用戶自定義的代碼就放在這個main.js文件中。
  • CMD(Common Module Definition )是 SeaJS 在推廣過程中對模塊定義的規范化產出。(即SeaJS模塊規范)
SeaJS是一個遵循CMD規范的JavaScript模塊加載框架,可以實現JavaScript的模塊化開發及加載機制。
  • CommonJS Modules/2.0 規范,是 BravoJS 在推廣過程中對模塊定義的規范化產出。
CommonJS API定義很多普通應用程序(主要指非瀏覽器的應用)使用的API,從而填補了這個空白。它的終極目標是提供一個類似Python,Ruby和Java標准庫。這樣的話,開發者可以使用CommonJS API編寫應用程序,然后這些應用可以運行在不同的JavaScript解釋器和不同的主機環境中。在兼容CommonJS的系統中,你可以實用JavaScript程序開發:
  • 服務器端JavaScript應用程序
  • 命令行工具
  • 圖形界面應用程序
  • 混合應用程序(如,Titanium或Adobe AIR)

還有不少⋯⋯這些規范的目的都是為了 JavaScript 的模塊化開發,特別是在瀏覽器端的。目前這些規范的實現都能達成瀏覽器端模塊化開發的目的。

 2、AMD/CMD模式區別

2.1從官方推薦的寫法上面得出:

CMD ----- 依賴就近

Js代碼 
//CMD 
define(function(require,exports,module){ 
   var a = require('./a'); 
   a.doSomthing(); 
});

AMD ----- 依賴前置

Js代碼 
//AMD 
define(['./a','./b'],function(a,b){ 
//...... 
a.doSomthing(); 
//...... 
b.doSomthing(); 
})

當然AMD也支持CMD的寫法。

2.2、執行順序上:

    • CMD是延遲執行,推崇的是as lazy as possible
    • AMD是提前執行,requireJS從2.0開始可以延遲執行
2.3、api設計角度:
    • CMD的API推崇職責單一,沒有全局的require
    • AMD的API默認是一個當多個用:比如require有全局的和局部的


免責聲明!

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



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