webpack3實戰(5)打包一個多頁、jQuery、圖片轉base6四、壓縮混淆、異步模塊加載的項目

前注:

文檔全文請查看 根目錄的文檔說明javascript

若是能夠,請給本項目加【Star】和【Fork】持續關注。css

有疑義請點擊這裏,發【Issues】。html

實戰項目示例目錄
前端

 

0、使用說明

安裝:java

npm install

運行(注,這裏不像以前用的 test ,而是改用了 build):jquery

npm run build

 

一、需求列表

基本需求:webpack

  1. 引入jQuery(或其餘相似庫,之因此用 jQuery 是每一個前端開發者都理應會 jQuery);
  2. 使用 less 做爲 css 預處理器;
  3. 標準模塊化開發;
  4. 有異步加載的模塊;
  5. 使用 es六、es7 語法;
  6. 寫一個登陸頁面做爲DEMO,再寫一個登陸後的示例頁面做爲跳轉後頁面;
  7. 可適用於多頁項目;
  8. css 文件與 圖片 文件脫離(即更改 css 文件路徑不影響其對圖片的引用)

打包要求:git

  1. 啓用 hash 命名,以應對緩存問題;
  2. css 自動添加兼容性前綴;
  3. 將圖片統一放到同一個文件夾下,方便管理;
  4. 將共同引入的模塊單獨打包出來,用於緩存,減小每次重複加載的代碼量;
  5. 代碼進行醜化壓縮;

 

二、涉及到的知識

  1. 入口:設置入口文件;
  2. 出口:設置打包後的文件夾以及文件命名;
  3. babel-loader:用於將es六、es7等語法,轉換爲es5語法;
  4. css-loader:用於處理css文件(主要是處理圖片的url);
  5. style-loader:將轉換後的css文件以 style 標籤形式插入 html 中;
  6. postcss-loader:通常用於添加兼容性屬性前綴;
  7. less-loader:以 less 語法來寫 css ;
  8. url-loader:用於將圖片小於必定大小的文件,轉爲 base64 字符串;
  9. file-loaderurl-loader 不能轉換 base64字符串 的文件,被這個處理(主要用於設置打包後圖片路徑,以及CDN等);
  10. html-withimg-loader:用於加載html模板;
  11. html-webpack-plugin :用於將已有 html 文件做爲模板,生成打包後的 html 文件;
  12. clean-webpack-plugin:用於每次打包前清理dist文件夾
  13. CommonsChunkPlugin:提取 chunks 之間共享的通用模塊

 

三、技術難點

 

3.一、多頁面

多頁模式是一個難點。es6

且不考慮共同模塊(這裏主要指的是html模板,而不是js的模塊),光是單獨每一個入口 js 文件須要搭配一個相對應的 html 文件,就已是一件很麻煩的事情了。github

對於這個問題,須要藉助使用 html-webpack-plugin 來實現。

因爲以前木有 html-webpack-plugin 的相關內容,這裏只講思路和代碼。

第一:多入口則多個html文件

也是核心內容,html-webpack-plugin 只負責生成一個 html 文件。

而多入口顯然須要生成多個 html 文件,所以 有多少個入口,就須要在 webpack 的 plugins 裏添加多少個 html-webpack-plugin 的實例。

同時,咱們還要更改 webpack 的 entry 入口,entry 的值應該是根據入口數量自動生成的對象。

第二:chunks特性實現按需加載

經過配置 html-webpack-plugin 的 options.chunks ,可讓咱們實現讓 login.html 只加載 login/index.js,而 userInfo.html 只加載 userInfo/index.js(注:因爲以 entry 的 key 做爲尋找出口文件的根據,所以打包後帶 hash 的文件名不影響匹配);

注意,這個實現的機制,是經過 options.chunk 的值,去匹配 webpack.config.js的 entry 對象的 key

由於一個入口文件對應一個出口文件,因此這裏會去拿入口文件對應的出口文件,將其加到 html 文件裏。

第三:template自定義做爲模板的 html 文件

options.template 能夠自定義該實例以哪一個 html 文件做爲模板。

第四:filename

options.filename 能夠自定義生成的 html 文件輸出爲何樣的文件名。

第五:管理多入口

已知:

一個 html-webpack-plugin 實例具備如下功能:

  1. 生成一個 html 文件(一);
  2. 決定本身引入哪一個 js 文件(二)(記得,webpack只負責打包js文件,不負責生成 html 文件。生成實例是依靠這個 plugins);
  3. 決定本身以哪一個 html 文件做爲模板(三);
  4. 決定本身打包後的目錄和文件名(四);

咱們經過webpack打包後,一個入口 js 文件會對應一個出口 js 文件;

而每一個入口 js 文件,都對應一個 html 模板文件;

所以每一個 html 模板文件,都知道本身對應哪一個出口 js 文件;

因此以上是實現多入口的原理。

代碼:

多入口管理文件:

config/entry.json

[
    {
        "url": "login", "title": "登陸" }, { "url": "userInfo", "title": "用戶詳細信息" } ]

webpack配置文件:

webpack.config.js:

首先,配置 entry

const entryJSON = require('../config/entry.json'); // 入口管理 let entry = {} entryJSON.map(page => { entry[page.url] = path.resolve(__dirname, `../src/page/${page.url}/index.js`) })

其次,配置 plugins

// 在上面已經引用了 entryJSON const path = require('path') // 由於多入口,因此要多個HtmlWebpackPlugin,每一個只能管一個入口 let plugins = entryJSON.map(page => { return new HtmlWebpackPlugin({ filename: path.resolve(__dirname, `../dist/${page.url}.html`), template: path.resolve(__dirname, `../src/page/${page.url}/index.html`), chunks: [page.url], // 實現多入口的核心,決定本身加載哪一個js文件,這裏的 page.url 指的是 entry 對象的 key 所對應的入口打包出來的js文件 hash: true, // 爲靜態資源生成hash值 minify: false, // 壓縮,若是啓用這個的話,須要使用html-minifier,否則會直接報錯 xhtml: true, // 自閉標籤 }) })

最後,webpack 自己的配置:

module.exports = { // 入口文件 entry: entry, // 出口文件 output: { path: __dirname + '/../dist', // 文件名,將打包好的導出爲bundle.js filename: '[name].[hash:8].js' }, // 省略中間的配置 // 將插件添加到webpack中 plugins: plugins }

文件目錄(已省略無關文件):

├─build
│  └─webpack.config.js ├─dist └─src └─page ├─login │ ├─index.js │ ├─index.html │ └─login.less └─userInfo ├─index.js └─index.html

 

3.二、文件分類管理

如何將頁面整齊的分類,也是很重要的。不合理的規劃,會增長項目的維護難度。

項目目錄以下分類:

├─build     webpack 的配置文件,例如 webpack.config.js ├─config 跟 webpack 有關的配置文件,例如 postcss-loader 的配置文件,以及多入口管理文件 ├─dist 打包的目標文件夾,存放 html 文件 │ └─img 打包後的圖片文件夾 └─src 資源文件夾 ├─common 全局配置,或者公共方法,放在此文件夾,例如 less-loader 的全局變量 ├─img 圖片資源文件夾,這些是共用的圖片 ├─less less 文件夾,共用的less文件 ├─page 每一個頁面,在page裏會有一個文件夾,裏面放置入口 js 文件,源 html 文件,以及不會被複用的 html template文件。 ├─template html 模板文件夾(經過js引入模板,這裏的可能被複用) └─static 靜態資源文件夾,這裏放使用靜態路徑的資源

雖然還不夠精細,但應對小型項目是足夠了的。

 

3.三、別名

別名的優點不少,好比:

一、css/less 代碼,能夠和圖片分離:

只要 webpack 配置和圖片的位置不變。

那麼使用別名,就能夠隨意移動 less 文件。

沒必要擔憂由於移動 less 文件,而形成的 less 文件與 圖片 文件的相對路徑改變,致使找不到圖片而出錯。

二、方便總體移動圖片

假如本來圖片放在src/img文件夾下,如今你忽然想把圖片放在src/image文件夾下。

若是不使用別名,你須要一個一個去修改圖片的路徑;

而使用別名,只須要改一下別名的路徑就好了。

css-loader 支持獨立於 webpack 的別名的設置,教程參照:css-loader

這裏基於【3.2】的文件分類管理,附上關於別名的控制代碼:

{
    loader: 'css-loader', options: { root: path.resolve(__dirname, '../src/static'), // url裏,以 / 開頭的路徑,去找src/static文件夾 minimize: true, // 壓縮css代碼 // sourceMap: true, // sourceMap,默認關閉 alias: { '@': path.resolve(__dirname, '../src/img') // '~@/logo.png' 這種寫法,會去找src/img/logo.png這個文件 } } },

其他代碼已省略,若是有須要,請查看 DEMO 中的 build/webpack.config.js 文件。

 

3.四、安裝jQuery

方案:

因爲npm上並無最新的 jQuery,目前來講, 1.7.4 是最新的版本。

因此能夠從下面這個CDN直接下載 jQuery 來使用,版本是 1.12.4

https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js

而後在js文件的開始位置,經過require引入(注意,不能經過 import 引入)

const $ = require('../../common/jquery.min')

webpack會幫你作剩下的事情,你只須要愉快的使用 jQuery 就行了。

 

3.五、提取 chunks 之間共享的通用模塊

在 3.4 中,咱們引入了 jQeury,方法簡單易行,但又一個缺點,那就是會致使代碼重複打包的問題。

即 jQuery 會被打包進每個引入他的入口 js 文件中,每一個頁面都須要重複下載一份將jQuery代碼打包到其中的 js 文件(極可能兩個 js 文件只有 20kb 是本身的代碼,卻有 90kb 是 jQuery 代碼)。

咱們指望:

  1. 訪問第一個頁面時,預期加載 foo.js 和 jQuery.js;
  2. 訪問第二個頁面時,預期加載 bar.js 和 jQuery.js;
  3. 當訪問第二個頁面時,發現已經在第一個頁面下載過 jQuery.js 了,所以將不須要再下載 jQuery 代碼,只須要下載 bar.js 就能夠了;

方案改進:

爲了實現這個目標,毫無疑問,咱們須要將 jQuery.js 文件單獨打包,或者說,每個在多個模塊中共享的模塊,都會被單獨打包。

有幾種作法,但實測後都很差用,鑑於 jQuery 會在每一個頁面都適用,所以綜合考慮後,我採用如下方案來初步實現個人目標。

最後我採用了 webpack 自帶的插件:webpack.optimize.CommonsChunkPlugin來實現,他能夠將在多個文件中引入的 模塊,單獨打包。

關於這個插件能夠先參考官方文檔:[CommonsChunkPlugin: 
提取 chunks 之間共享的通用模塊](https://doc.webpack-china.org/plugins/commons-chunk-plugin/)

爲了實現咱們的目的,咱們須要作兩件事:

一、使用這個插件,以下配置:

const webpack = require('webpack') new webpack.optimize.CommonsChunkPlugin({ name: "foo", // 這個對應的是 entry 的 key minChunks: 2 })

這個的效果是將至少有 2 個 chunk 引入的公共代碼,打包到 foo 這個 chunk 中。

二、咱們須要引入這個打包後的 chunk ,方法是經過 html-webpack-plugin 這個插件引入。

// 無關配置已經省略 new HtmlWebpackPlugin({ chunks: [page.url, 'foo'], // 這裏的foo,就是經過CommonsChunkPlugin生成的chunk })

無需修改源代碼,此時咱們能夠執行npm run build查看打包後的效果:

foo.d78e8f4193f50cc42a49.js // 199 KB(這裏包含jQuery以及公共代碼) login.d2819f642c5927565e7b.js // 15 KB userInfo.1610748fb3346bcd0c47.js // 4 KB 0.fe5c2c427675e10b0d3a.js // 2 KB

注:

若是頁面不少的話,那麼極可能某些公共組建被大量chunk所共享,而某些chunk又被少許chunk所共享。

所以可能須要特殊配置 minChunks 這個屬性,具體請查看官方文檔。

 

3.六、每次打包前,清理dist文件夾

須要藉助 clean-webpack-plugin 這個插件。

使用這個插件後,能夠在每次打包前清理掉整個文件夾。

基於本項目來講,清除的時候配置的時候須要這樣配置:

new CleanWebpackPlugin(path.resolve(__dirname, '../dist'), { root: path.resolve(__dirname, '../'), // 設置root verbose: true })

緣由在於,這個插件會認爲webpack.config.js所在的目錄爲項目的根目錄。

只使用第一個參數的話,會報錯移除目標的目錄位置不對:

clean-webpack-plugin: (略)【實戰5】打包一個具備常見功能的多頁項目\dist is outside of the project root. Skipping...

而添加了第二個參數的設置後,就能夠正常使用了。

注:

他的效果是直接刪除文件夾,所以千萬別寫錯目錄了,若是刪除了你正常的文件夾,那麼……就只能哭啦。

 

3.七、使用 html 模板

因爲咱們極可能在 html 中使用 <img> 標籤,

而 html-webpack-plugin 這個插件,只能用於將某個 html 文件做爲打包後的源 html 文件,

不會將其 <img> 標籤中的 src屬性轉爲打包後的圖片路徑,同時也不會將引入的圖片進行打包。

所以咱們須要將 html 內容單獨拆出來,page 文件夾裏的源文件只負責做爲 html 模板而已。

爲了使用 html 模板,咱們須要專門引入一個插件:

html-withimg-loader:用於解析 html 文件。

使用方法很簡單:

  1. 配置loader(參照 webpack.config.js);
  2. import 導入 html 模板文件(例如 login.html);

導入的時候,是一個字符串,而且圖片的 url 已經被解析了。而後咱們將其引入源 html 文件中(好比page/login.html),再寫各類邏輯就好了。

注:

務必記得先把 html 模板插入頁面中,再寫他的相關邏輯。

 

3.八、代碼的醜化壓縮

使用插件 UglifyjsWebpackPlugin ,文檔參照 (UglifyjsWebpackPlugin)[https://doc.webpack-china.org/plugins/uglifyjs-webpack-plugin]

壓縮前:

0.fe5c2c427675e10b0d3a.js // 2 KB foo.a5e497953a435f418876.js // 199 KB login.9698d39e5b8f6c381649.js // 15 KB userInfo.f5a705ffcb43780bb3d6.js // 4 KB

醜化壓縮後:

0.fe5c2c427675e10b0d3a.js // 1 KB foo.a5e497953a435f418876.js // 120 KB login.9698d39e5b8f6c381649.js // 10 KB userInfo.f5a705ffcb43780bb3d6.js // 2 KB

 

四、分析

從新列出全部需求:

基本需求:

  1. 引入jQuery(或其餘相似庫,之因此用 jQuery 是每一個前端開發者都理應會 jQuery);
  2. 使用 less 做爲 css 預處理器;
  3. 標準模塊化開發;
  4. 有異步加載的模塊;
  5. 使用 es六、es7 語法;
  6. 寫一個登陸頁面做爲DEMO,再寫一個登陸後的示例頁面做爲跳轉後頁面;
  7. 可適用於多頁項目;
  8. css 文件與 圖片 文件脫離(即更改 css 文件路徑不影響其對圖片的引用)

打包要求:

  1. 啓用 hash 命名,以應對緩存問題;
  2. css 自動添加兼容性前綴;
  3. 將圖片統一放到同一個文件夾下,方便管理;
  4. 將共同引入的模塊單獨打包出來,用於緩存,減小每次重複加載的代碼量;
  5. 代碼進行醜化壓縮;

需求的實現:

基本需求:

需求的實現過程
需求 實現方法
引入jQuery 1. 經過 require() 引入,並經過 CommonsChunkPlugin 實現單獨打包;
使用 less 做爲 css 預處理器 1. 使用 less-loader 來處理 .less 文件;
標準模塊化開發 1. 使用 import 和 require 語法來進行模塊化開發;
有異步加載的模塊 1. 經過 require([], callback) 來實現模塊的異步加載
使用 es六、es7 語法 1. 使用 babel 來轉義
寫一個登陸頁面做爲DEMO,再寫一個登陸後的示例頁面做爲跳轉後頁面 1. 登陸頁:page/login
2. 跳轉後頁面:page/userInfo
可適用於多頁項目 1. config/entry.json 用於配置多頁入口;
2. html-withimg-loader 來生成多頁模板;
3. 最後在webpack.config.js裏配置 entry 和 plugins
css 文件與 圖片 文件脫離(即更改 css 文件路徑不影響其對圖片的引用) 經過 css-loader 的別名實現

打包需求:

 

需求的實現過程
需求 實現方法
啓用 hash 命名,以應對緩存問題 配置 output 的 filename 屬性,加 [chunkhash] 便可
css 自動添加兼容性前綴 使用 post-loader 的 autoprefixer
將圖片統一放到同一個文件夾下,方便管理 配置 url-loader (實質是 file-loader )的 outputPath
將共同引入的模塊單獨打包出來,用於緩存,減小每次重複加載的代碼量 使用插件 CommonsChunkPlugin 來實現
代碼進行醜化壓縮 使用插件 UglifyjsWebpackPlugin 來實現
相關文章
相關標籤/搜索