1. 程式人生 > >webpack 4.x一起學習(二)

webpack 4.x一起學習(二)

接著上一塊https://juejin.im/post/5be29710e51d457e90193cf3

模組:CSS檔案打包

Webpack在生產環境中有一個重要的作用就是減少http的請求數,就是把多個檔案打包到一個js裡,這樣請求數就可以減少好多。在學習CSS打包之前,需要先對webpack.config.js裡的Loaders配置項進行了解。

Loaders(以下所有的配置都是基於3版本的 如果過程中有bug 會進行改進)

Loaders是Webpack最重要的功能之一,他也是Webpack如此盛行的原因。通過使用不同的Loader,Webpack可以的指令碼和工具,從而對不同的檔案格式進行特定處理。

簡單的舉幾個Loaders使用例子:

可以把SASS檔案的寫法轉換成CSS,而不在使用其他轉換工具。
可以把ES6或者ES7的程式碼,轉換成大多瀏覽器相容的JS程式碼。
可以把React中的JSX轉換成JavaScript程式碼。

注意:所有的Loaders都需要在npm中單獨進行安裝,並在webpack.config.js裡進行配置。下面我們對Loaders的配置型簡單梳理一下。

test:用於匹配處理檔案的副檔名的表示式,這個選項是必須進行配置的;
use:loader名稱,就是你要使用模組的名稱,這個選項也必須進行配置,否則報錯;
include/exclude:手動新增必須處理的檔案(資料夾)或遮蔽不需要處理的檔案(資料夾)(可選);
query:為loaders提供額外的設定選項(可選)。

打包CSS檔案

建立index.css檔案 ./src/css/index.css

要打包CSS你必須先要有個CSS檔案,在/src目錄下,我們建立一個css資料夾,在資料夾裡建立index.css檔案。程式碼內容如下

    body{
        background-color: red;  可以跟我不一樣 完全為了測試
        color: white;
    }

CSS檔案建立好後,需要引入到入口檔案中,才可以打包到,這裡我們引入到entry.js中。

/src/entery.js中在首行加入程式碼:
import css from './css/index.css';

也就是在entry.js中頂部匯入

    import  css from './css/index.css';

    document.getElementById('title').innerHTML='Hello Webpack';

CSS和引入做好後,我們就需要使用loader來解析CSS檔案了,這裡我們需要兩個解析用的loader,分別是style-loader和css-loader

首先我們先使用npm 安裝(有些腳手架生成的webpack 會自動安裝這些簡單的載入器)

npm install style-loader css-loader --save-dev 一步到位

安裝好之後檢視一下package.json

兩個loader都下載安裝好後,我們就可以配置我們loaders了。

loaders配置:

修改webpack.config.js中module屬性中的配置程式碼如下:

webpack.config.js

    const path = require('path')
    module.exports={
        mode: 'development',
        //入口檔案的配置項
        entry:{
            //裡面的entery是可以隨便寫的
            entry:'./src/entry.js',
        },
        //出口檔案的配置項
        output:{
            //打包的路徑文職
            path:path.resolve(__dirname,'dist'),
            //打包的檔名稱
            filename:'bundle.js'
                    },
        //模組:例如解讀CSS,圖片如何轉換,壓縮
        module:{
            rules: [  =>以前此處是loaders 現在是rules
                {
                test: /\.css$/, =>正則 這個好理解
                use: [ 'style-loader', 'css-loader' ] =>使用css 與 style loader 來載入匹配到的css檔案
                }
            ]
        },
        //外掛,用於生產模版和各項功能
        plugins:[],
        //配置webpack開發服務功能
        devServer:{              
            host:'localhost',   //伺服器的ip地址
            port:1573,  //埠
        }
    }

webpack一下,之前我們在js中引入了css 執行一下html ok 有樣式了

友情提示:小夥伴們在測試的時候,可能會遇到找不到模組的 這種error 建議重新新建配置 重新npm外掛 剛才我就莫名其妙找不到模組了 重新安裝了一下就可以了

loader的三種寫法:

有些小夥伴看到別人的CSS打包的寫法和我的寫法不太一樣,是不是我寫錯了,loader還有幾種寫法,這裡我們就看兩種另外的寫法。

使用use

    module:{
        rules:[
            {
                test:/\.css$/,
                use:['style-loader','css-loader']
            }
        ]
    },

把use換成loader。

    module:{
        rules:[
            {
                test:/\.css$/,
                loader:['style-loader','css-loader']
            }
        ]
    },

第三種寫法:用use+loader的寫法:

    module:{
        rules:[
            {
                test:/\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader"
                    }
                ]
            }
        ]
    },

沒有全測 也不知道哪裡需要修改 小夥伴可以自行測試一下

接下來我們來試著壓縮一下js

在Webpack中可以很輕鬆的實現JS程式碼的壓縮,它是通過外掛的方式實現的,這裡我們就先來引入一個uglifyjs-webpack-plugin(JS壓縮外掛,簡稱uglify)。

注意:雖然uglifyjs是外掛,但是webpack版本里預設已經整合,不需要再次安裝。

    const path = require('path')
    const webpack =require('webpack')  =>注意這裡我們引入了webpack
    module.exports={
        mode: 'development',
        //入口檔案的配置項
        entry:{
            //裡面的entery是可以隨便寫的
            entry:'./src/entry.js',
        },
        //出口檔案的配置項
        output:{
            //打包的路徑文職
            path:path.resolve(__dirname,'dist'),
            //打包的檔名稱
            filename:'bundle.js'
                    },
        //模組:例如解讀CSS,圖片如何轉換,壓縮
        module:{
            rules: [
                {
                test: /\.css$/,
                use: [ 'style-loader', 'css-loader' ]
                }
            ]
        },
        //外掛,用於生產模版和各項功能
        plugins:[
            new webpack.optimize.UglifyJsPlugin() =>因為是webpack整合的 所以要在上方引入webpack
        ]            
     
    }

此時我們webpack一下 你會發現 報錯(報錯的內容就不截圖了)

在webpack4.0版本中已經廢棄了之前 UglifyJsPlugin的用法,用的是optimization.minimize

重新配置一下webpack

    const path = require('path') 
                                                     刪除了webpack模組引入

    const UglifyJsPlugin=require('uglifyjs-webpack-plugin');=>需要 npm 手動安裝
    module.exports={
        mode: 'development',
        //入口檔案的配置項
        entry:{
            //裡面的entery是可以隨便寫的
            entry:'./src/entry.js',
        },
        //出口檔案的配置項
        output:{
            //打包的路徑文職
            path:path.resolve(__dirname,'dist'),
            //打包的檔名稱
            filename:'bundle.js'
                    },
        //模組:例如解讀CSS,圖片如何轉換,壓縮
        module:{
            rules: [
                {
                test: /\.css$/,
                use: [ 'style-loader', 'css-loader' ]
                }
            ]
        },
        //外掛,用於生產模版和各項功能
        plugins:[
            
        ],
        
        optimization: {
            minimizer: [
                new UglifyJsPlugin({
                    uglifyOptions: {
                        compress: false
                    }
                })
            ]
        },
        
     
    }

這裡需要注意一下 webpack打包也是分模式的 預設是mode ‘production(生產環境)’

如果我們沒在config.js中標明webpack 的mode 直接webpack是會有警告的

就是說我們打包的命令完整應該是 webpack --mode production/development

預設是production 此方法打包檔案會小很多 注意一下即可

production 其實預設自帶了uglifyjs-webpack-plugin 外掛 已經不需要使用

也就是我們在production 狀態下 其實可以不需要配置 直接 webpack --mode development 即可

接下來我還是設定預設 production 環境下測試 方便點

外掛配置:HTML檔案的釋出

webpack 構建專案時, 通過指定的入口檔案,會將所有的js css 等以依賴模組的形式打包成一個或多個的指令碼檔案,通常情況下,指令碼檔案會附屬於html 檔案執行,這時候需要將 打包好的指令碼檔案,注入到html 中, html-webpack-plugin 外掛的目的是, 以一個html 為模板, 將打包好的指令碼注入到模板中, 相關的配置如下

先安裝 html-webpack-plugin
npm i html-webpack-plugin -D

安裝好之後 我們在plugins中配置

    const path = require('path')
    const htmlPlugin = require('html-webpack-plugin');  =>引入模組
    module.exports={

        //入口檔案的配置項
        entry:{
            //裡面的entery是可以隨便寫的
            entry:'./src/entry.js',
        },
        //出口檔案的配置項
        output:{
            //打包的路徑文職
            path:path.resolve(__dirname,'dist'),
            //打包的檔名稱
            filename:'bundle.js'
        },
        //模組:例如解讀CSS,圖片如何轉換,壓縮
        module:{
            rules: [
                {
                test: /\.css$/,
                use: [ 'style-loader', 'css-loader' ]
                }
            ]
        },
        //外掛,用於生產模版和各項功能
        plugins:[
            new htmlPlugin({   =>這是一般情況下的配置  打包html 
                minify:{
                    removeAttributeQuotes:true
                },
                hash:true,
                template:'./src/index.html'
            })
        ],                                 
    }

minify:是對html檔案進行壓縮
hash:為了開發中js有快取效果,所以加入hash,這樣可以有效避免快取JS。
template:是要打包的html模版路徑和檔名稱。

此時我們webpack --mode production

此時dist下生成了 index.html js是上面的命令生成的 這就是我們常見的狀態了 熟悉vue的小夥伴都知道 npm run build就會生成這倆檔案 此時我們直接開index.html 也是有效果的 如果需要改名的話可以再配置一個引數 filename:‘filename.html’ 一定要加字尾

圖片邁坑:CSS中的圖片處理

在學習Webapck過程中你可能遇到的第一個坑就是CSS中的圖片處理。很多webpack新手都在圖片的坑中無法自拔(有的小夥伴在開發環境中是可以找到圖片的,但是一打包後就找不到圖片了,有的小夥伴是不知道如何正確引入html或者css中的圖片,導致程式出錯)

圖片寫入css 我們先找張圖片先 http://img1.imgtn.bdimg.com/it/u=198855387,108109132&fm=26&gp=0.jpg

注意一定要本地圖片啊 剛才偷懶使用網路圖片發現居然成功了 不能成功 一定要失敗的

index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>webpack</title>
    </head>
    <body>
        <div id="tupian"></div>
        <script src="./../dist/bundle.js"></script>
    </body>
    </html>

index.css css還是在js中引入

#tupian{
background-image: url('./../image/1.jpg');
width:466px;
height:453px;
 }

我們這時候 通過webpack --mode production 是會失敗的 失敗的原因就是缺少loader的解析

對於圖片我們也需要安裝兩loader

安裝file-loader和url-loade
npm install --save-dev file-loader url-loader

file-loader:解決引用路徑的問題,拿background樣式用url引入背景圖來說,我們都知道,webpack最終會將各個模組打包成一個檔案,因此我們樣式中的url路徑是相對入口html頁面的,而不是相對於原始css檔案所在的路徑的。這就會導致圖片引入失敗。這個問題是用file-loader解決的,file-loader可以解析專案中的url引入(不僅限於css),根據我們的配置,將圖片拷貝到相應的路徑,再根據我們的配置,修改打包後文件引用路徑,使之指向正確的檔案。

url-loader:如果圖片較多,會發很多http請求,會降低頁面效能。這個問題可以通過url-loader解決。url-loader會將引入的圖片編碼,生成dataURl。相當於把圖片資料翻譯成一串字元。再把這串字元打包到檔案中,最終只需要引入這個檔案就能訪問圖片了。當然,如果圖片較大,編碼會消耗效能。因此url-loader提供了一個limit引數,小於limit位元組的檔案會被轉為DataURl,大於limit的還會使用file-loader進行copy。

安裝好之後我們來配置webpack 直接在module中配置loader

    const path = require('path')
    const htmlPlugin = require('html-webpack-plugin');
    module.exports={

        //入口檔案的配置項
        entry:{
            //裡面的entery是可以隨便寫的
            entry:'./src/entry.js',
        },
        //出口檔案的配置項
        output:{
            //打包的路徑文職
            path:path.resolve(__dirname,'dist'),
            //打包的檔名稱
            filename:'bundle.js'
        },
        //模組:例如解讀CSS,圖片如何轉換,壓縮
        module:{
            rules: [
                {
                test: /\.css$/,  => css的loader
                use: [ 'style-loader', 'css-loader' ]  =>這邊順帶提一下 其實webpack的loader是從右往左看
                                                 =>也就是 先使用css loader  再使用style loader  
                },
                {
                    test:/\.(png|jpg|gif)/ , =>圖片的loader
                    use:[{
                        loader:'url-loader',
                        options:{
                            limit:500000   =>不認識limit的小夥伴可以自行百度一下  類似我們的流量 哈哈  好吧其實就是指500000B
                        }
                    }]
                 }
            ]
        },
        //外掛,用於生產模版和各項功能
        plugins:[
            new htmlPlugin({
                minify:{
                    removeAttributeQuotes:true
                },
                hash:true,
                template:'./src/index.html'
            })
        ],
            
    }

接下來我們webpack --mode production 即可 成功生成

為什麼只使用了url-loader

有的小夥伴會發現我們並沒有在webpack.config.js中使用file-loader,但是依然打包成功了。我們需要了解file-loader和url-loader的關係。url-loader和file-loader是什麼關係呢?簡答地說,url-loader封裝了file-loader。url-loader不依賴於file-loader,即使用url-loader時,只需要安裝url-loader即可,不需要安裝file-loader,因為url-loader內建了file-loader。通過上面的介紹,我們可以看到,url-loader工作分兩種情況:

1.檔案大小小於limit引數,url-loader將會把檔案轉為DataURL(Base64格式);

2.檔案大小大於limit,url-loader會呼叫file-loader進行處理,引數也會直接傳給file-loader。

也就是說,其實我們只安裝一個url-loader就可以了。但是為了以後的操作方便,我們這裡就順便安裝上file-loader。

###圖片邁坑:CSS分離與圖片路徑處理

CSS分離:extract-text-webpack-plugin

有些簡單的互動頁面中,你的JavasScript頁面程式碼會非常少,而大部分程式碼都在CSS中,這時候專案組長會要求把CSS單獨提取出來,方便以後更改。遇到這個需求你不要驚慌,已經有大神為我們準備好了物件的外掛(plugin)

這個外掛就可以完美的解決我們提取CSS的需求,但是webpack官方其實並不建議這樣作,他們認為CSS就應該打包到JavasScript當中以減少http的請求數。但現實中的需求往往不是我們前端能控制的,有些需求是我們不能控制的,分離CSS就是這樣一個既合理由不合理的需求,說白了,還是得聽老大的 ,如果小姐姐讓你這樣你做不做呢?

npm install --save-dev extract-text-webpack-plugin

安裝好了自然要用 我們直接在webpack上方 引入 const extractTextPlugin = require("extract-text-webpack-plugin")

引入之後 我們只需在webpack中new 使用 並且還要配置關於css的載入器

      const path = require('path')
      const htmlPlugin = require('html-webpack-plugin');
      const extractTextPlugin = require("extract-text-webpack-plugin")
      module.exports={
        //入口檔案的配置項
        entry:{
            //裡面的entery是可以隨便寫的
            entry:'./src/entry.js',
        },
        //出口檔案的配置項
        output:{
            //打包的路徑位置
            path:path.resolve(__dirname,'dist'),
            //打包的檔名稱
            filename:'bundle.js'
        },
        //模組:例如解讀CSS,圖片如何轉換,壓縮
        module:{
            rules: [
                {
                // test: /\.css$/,
                // use: [ 'style-loader', 'css-loader' ]
                test: /\.css$/,
                use: extractTextPlugin.extract({
                  fallback: "style-loader",
                  use: "css-loader"
                })
                },
                {
                    test:/\.(png|jpg|gif)/ ,
                    use:[{
                        loader:'url-loader',
                        options:{
                            limit:500000
                        }
                    }]
                 }
            ]
        },
        //外掛,用於生產模版和各項功能
        plugins:[
            new htmlPlugin({
                minify:{
                    removeAttributeQuotes:true
                },
                hash:true,
                template:'./src/index.html'
            }),
            new extractTextPlugin("/css/index.css") =>注意外掛的使用   (此處是生成的檔案位置  前面配置了path 預設都是dist檔案下的)
        ],

    }

此時我們webpack一下 是有錯誤的 因為extract-text-webpack-plugin 不支援4版本以上的
我們既然學習4版本的webpack肯定不能降級 好 我們升級
npm install --save-dev [email protected]

安裝好之後 其餘不變 再次 webpack一下 因為此時生成打包了三個檔案 我給截圖一下

這樣就成功分離了 本來是起初我們匯入js中的 此時成功生成了index.css 並且裡面的url是base64形式的,但是我們此時瀏覽dist下的html是沒有東西的 因為我們路徑有問題 這裡是指圖片路徑 不是檔案路徑

圖片路徑問題

利用extract-text-webpack-plugin外掛很輕鬆的就把CSS檔案分離了出來,但是CSS路徑並不正確,很多小夥伴就在這裡搞個幾天還是沒有頭緒,網上也給出了很多的解決方案,我覺的最好的解決方案是使用publicPath解決

publicPath:是在webpack.config.js檔案的output選項中,主要作用就是處理靜態檔案路徑的。

此處增加一個知識 webpack-dev-server 本來是不想配置後面給大家簡單提一下,畢竟單獨測試webpack的真的不多,很多時候都是看webpack或者腳手架生成直接修改

測試publicPath的時候 沒設定伺服器狀態老報錯 使用live-server也不好配置 所以簡單提一下webpack-dev-server的配置

npm install webpack-dev-server –save-dev 先安裝

在webpack.config.js 中配置

        plugins:[
            new htmlPlugin({
                minify:{
                    removeAttributeQuotes:true
                },
                hash:true,
                template:'./src/index.html'
            }),
            new extractTextPlugin("/css/index.css")
        ],
        devServer:{  =>注意 與plugins同級
            //設定基本目錄結構
            contentBase:path.join(__dirname,'dist'),
            //伺服器的IP地址,可以使用IP也可以使用localhost
           //  不知道自己IP的可以 開啟cmd 輸入ipconfig 檢視
            host:'localhost',
            //服務端壓縮是否開啟
            compress:true,
            //配置服務埠號
            port:1717
        }

在packge.json的 scripts 中輸入"dev": "webpack-dev-server --open"

我們啟動webpack-dev-server的時候只需要npm run dev 即可

啟動webpack-dev-server之後 會啟動熱更新 當我們改變內容儲存的時候會自動進行webpack命令打包 實時更新內容

別忘了我們主要的目的 ,解決圖片路徑問題 使用publicPath

主要看output模組

    const path = require('path')
    const htmlPlugin = require('html-webpack-plugin');
    const extractTextPlugin = require("extract-text-webpack-plugin")
    module.exports={
       // mode:'development',
        //入口檔案的配置項
        entry:{
            //裡面的entery是可以隨便寫的
            entry:'./src/entry.js',
        },
        //出口檔案的配置項
        output:{
            //打包的路徑文職
            path:path.resolve(__dirname,'dist'),
            //打包的檔名稱
            filename:'bundle.js',
            publicPath:'localhost:1717'  
        },
        //模組:例如解讀CSS,圖片如何轉換,壓縮
        module:{
            rules: [
                {
                // test: /\.css$/,
                // use: [ 'style-loader', 'css-loader' ]
                test: /\.css$/,
                use: extractTextPlugin.extract({
                  fallback: "style-loader",
                  use: "css-loader"
                })
                },
                {
                    test:/\.(png|jpg|gif)/ ,
                    use:[{
                        loader:'url-loader',
                        options:{
                            limit:500000
                        }
                    }]
                 }
            ]
        },
        //外掛,用於生產模版和各項功能
        plugins:[
            new htmlPlugin({
                minify:{
                    removeAttributeQuotes:true
                },
                hash:true,
                template:'./src/index.html'
            }),
            new extractTextPlugin("/css/index.css")
        ],
        devServer:{
            //設定基本目錄結構
            contentBase:path.resolve(__dirname,'dist'),
            //伺服器的IP地址,可以使用IP也可以使用localhost
            host:'localhost',
            //服務端壓縮是否開啟
            compress:true,
            //配置服務埠號
            port:1717
        }

    }

接著我們打包之後 即可顯示圖片了