初識webpack4.x(一)

系列文章


webpack4.x已經(jīng)發(fā)布很久了,借此機會來好好的學(xué)習(xí)一下webpack的使用

  • 首先是需要初始化package文件,我們新建一個文件夾并且命令行窗口定位到該文件夾,輸入npm init -y 回車;需要注意的是這里默認了一路yes它會以文件夾名稱來做項目名稱,那么就要求文件夾名不能為中文、npm的包名,如果文件夾下面有readme.md文件的話則會默認將其添加到項目描述中。
  • 現(xiàn)在開始安裝webpack,執(zhí)行命令 npm i webpack webpack-cli webpack-dev-server -D 這里是安裝了,webpack本體,webpack腳手架,webpack熱更新服務(wù),因為在webpack4.0中是將webpack和webpack-cli分開了,其實在之前他們是在一起的,至于熱更新呢,敲代碼每次js變更和html變更都需要手動去刷新頁面,非常煩,那么我們就把這個煩人的操作丟給熱更新來了,節(jié)約時間也防止打斷思路。
    項目目錄
    • 那么現(xiàn)在我們需要手動初始化一下我們的項目文件夾(如圖所示),需要創(chuàng)建一個src,dist這兩個文件夾,src文件夾用來放置源碼而dist則是放置webpack打包好的文件。(當然,你也可以使用自己的命名規(guī)則,只需要修改對應(yīng)的入口和輸出就好啦)再新建一個名為 webpack.config.js 一定要是這個名字哦,這是webpack識別外部配置文件的一個算是入口吧。現(xiàn)在我們開始來擼代碼!
    const path = require("path")
    module.exports = {
    // 更改webpack尋找模塊對應(yīng)的文件
    resolve:{
        // 此設(shè)置是決定了webpack如何去按照什么順序去搜索文件
        extensions: ['.js', '.json'],
        // 相當實用,它會通過別名將原路徑設(shè)置成一個新的路徑
        alias:{
    
        }
    },
    // 第一段:入口
    // 這里可以看到我寫的就是向webpack導(dǎo)入src文件夾下的index.js文件
    entry: "./src/index.js",
    // 第二段:輸出
    output: {
        // 設(shè)置輸出的文件夾
        // 此處就是輸出到了之前創(chuàng)建的dist文件夾中啦~
        path: path.join(__dirname, 'dist'),
        // name是entry名字默認為main,而hash則是打包后文件內(nèi)容計算出來的hash值
        // hash后面的冒號加數(shù)字是代表生成的hash位數(shù)
        filename: '[name].[hash:8].js'
    },
    // 第三段:webpack使用的loader
    module: {
        rules: []
    },
    // 第四段:webpack插件
    plugins: [],
    // 第五段:配置webpack熱更新服務(wù)
    devServer: {
        contentBase: './dist',
        // 此處localhost則默認是本機,如果不是請修改為127.0.0.1
        // 如果是設(shè)置為0.0.0.0呢則可以本機和局域網(wǎng)訪問了
        // 但是由于啟用了自動彈窗,他會默認打開0.0.0.0:端口號
        // 所以本機瀏覽,還請手動敲127.0.0.1:端口號。
        host: 'localhost',
        // 開啟端口
        port: 8080,
        // 是否啟動gzip
        compress: true,
        // 是否自動打開瀏覽器預(yù)覽,這個和在命令中使用--open效果相同
        // 由于下面的命令已經(jīng)寫了,所以這里就將其注釋掉,你也可以在這里設(shè)置之后,命令中不再寫,看個人喜好
        // open:true
    
        }
    }
    
    • 在這里我們可以看到它可以分成五段,代碼中已經(jīng)有了一部分注釋,請結(jié)合注釋上的字,進行后續(xù)的觀看。
  • 現(xiàn)在我們可以運行起來了嗎?當然不可以,配置好了這個文件僅僅是第一步,我們還需要去配置一下 package.json 這個文件,現(xiàn)在打開 package.json ,找到scripts,這個對象里面默認應(yīng)該是有一個test的才對,我們刪掉他,然后把這些敲進去 "dev": "webpack-dev-server --open --mode development","build": "webpack --mode development" ,你注意到了,dev和build后面跟隨的命令是不一樣的,現(xiàn)在我來解釋一下:
    在dev中,這個命令是啟動了webpack熱更新服務(wù)器,其中帶了open和mode兩個參數(shù),open代表當webpack處理完成之后自動打開默認瀏覽器預(yù)覽 ( 同時可以和上文中直接再devSserver中使用open:"true",是一樣的效果 ) ,mode這個參數(shù)是webpack中必須要求的,是聲明當前的代碼環(huán)境,development當然就是開發(fā)環(huán)境啦,而相對的生產(chǎn)環(huán)境就是 production 了,至于這兩者有什么區(qū)別,我們以后再說,現(xiàn)在只需要知道就好了;而build呢,它就是很熟悉的編譯了,這個命令會將你的指定文件編譯完成并丟進上面你指定的文件夾中(也就是dist文件夾)我們就可以在命令行里去執(zhí)行npm run devnpm run build者兩個命令,就可以執(zhí)行它們啦。
  • 現(xiàn)在只是有一個js而已,網(wǎng)頁怎么能少了html和css呢,現(xiàn)在我們隆重介紹兩個webpack插件和加載器,它們是:html-webpack-plugin,clean-webpack-plugin,css-loader,style-loader,既然不是webpack自帶的,當然要進行安裝了,執(zhí)行命令 npm i html-webpack-plugin clean-webpack-plugin css-loader style-loader -D 。
    • 現(xiàn)在需要介紹一下插件,首先是末尾都帶了plugin的,這類是需要寫在 plugins數(shù)組中,找到了嗎?也就是上面代碼的第四段下面的位置,這些plugin都是需要引入,比如: const CleanWebpackPlugin = require("clean-webpack-plugin") 這樣寫在代碼頂端;(2019-06-11訂正更新,clean-webpack-plugin的3.0版本中需要const {CleanWebpackPlugin} = require("clean-webpack-plugin")這樣引入,然后在使用的時候無需任何參數(shù),默認會清空你的dist文件夾,至于想自定義清空文件夾位置,請自行查看插件github地址)當然你寫在plugin上面也沒問題啦,我們需要注意一下格式嘛,導(dǎo)入的時候都放在代碼的頂部,一目了然。在數(shù)組中我們需要這樣寫
    plugins: [
        new HtmlWebpackPlugin({
                // 以什么html為模板
                template: './src/index.html',
                // 生成的html名稱是什么
                filename: 'index.html',
                // 修改掉網(wǎng)頁的顯示名稱
                title: "這是標題",
                // minfy是對html進行壓縮,removeAttributeQuotes是為了去掉屬性的雙引號
                minify: {
                    removeAttributeQuotes: true
                },
                // 在引入的js時候加入查詢字符串避免緩存
                hash: true,
            }),
        // 在重新打包的時候自動清空輸出文件夾,保持輸出文件夾中的文件時最新的
        new CleanWebpackPlugin({}),
    ],
    
    • 每一個插件都需要new一下,如果有參數(shù)的話就是類似HtmlWebpackPlugin這個插件這樣寫啦,好了現(xiàn)在需要根據(jù)插件中的配置進行一些文件上的創(chuàng)建,現(xiàn)在我們需要去src文件中創(chuàng)建一個html文件,內(nèi)容是這樣的
    <!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><%= htmlWebpackPlugin.options.title %></title>
    </head>
    <body>
        <div id="app"></div>
    </body>
    </html>
    
    • 可能就會有小可愛會問了,<%= htmlWebpackPlugin.options.title %>這句代碼是什么意思,其實,這個是一個模板,記得前面我們在插件中設(shè)置了title了嗎?這里就是將那個title賦值過來,現(xiàn)在我們試一下運行dev命令看看是不是頁面就直接出來了,是白板沒關(guān)系,因為你的html本身就沒有寫任何內(nèi)容嘛~除了那個頁面名稱,看一看一定是你設(shè)置的名稱。
    • 現(xiàn)在我們需要引入js和css主要是css我們需要用到兩個loader,也就是之前安裝的末尾帶了loader字樣,loader顧名思義是加載器其作用就是通過一定的規(guī)則將非js文件處理成標準的js文件加載或者是將js文件加載進去,但是loader和plugin不同的是,loader不需要引入,只需要安裝就好,那么他們的位置則是在配置文件的第三段,module對象中的rules數(shù)組中。

    rules的使用是這樣的,test代表的是需要處理的文件,支持正則表達式和直接導(dǎo)入的形式,而下面的loader則是有三種寫法, use,loader,use+loader,其中use和loader是一樣的,而use+loader則不同,這種寫法一般是配置loader中所需要的一些參數(shù),當然你使用問好銜接可以的,webpack提供了很多中用法;在下面這段代碼中就提供了很多例子供大家參考

      module: {
         rules: [
             {
                 // 使用正則匹配文件
                 test: /\.css$/,
                 // 規(guī)定使用什么加載器處理這個文件
                 // 其中,css-loader用于解析css文件中的url路徑
                 // style-loader用于將css文件變成style標簽插入到header中
                 // 多個loader的話,需要從右往左寫,轉(zhuǎn)換的時候是從右往左處理
                 loader: ["style-loader", "css-loader"]
                 // 同時也可以寫成
                 // loader:'style-loader!css-loader'
             },
             // expose-loader雖然可以將某些變量掛載至windows上,但是需要每一個都要在這里掛載非常的不方便
             // 如果非要掛載依賴,針對一些老項目,可以嘗試這樣去配置
             {
                 test: require.resolve('jquery'),
                 // 此處是loader寫法,問好后面則是需要暴漏的全局變量,為$符號
                 use: {
                     loader: 'expose-loader',
                     options: '$'
                 }
                 // 這里的這loader也可以寫成
                 // loader:'expose-loader?$'
             }
         ]
     },
    
    • 是不是對這個 expose-loader 比較好奇?他的作用是什么?是這樣的,很多老的項目均使用了jq而我們既然使用了webpack就不好在index.html模板位置使用script標簽進行載入,除去因為cdn加速或者其他的什么必須使用script標簽,我們要讓webpack對我們的項目有100%的掌控,這樣一來可以統(tǒng)一混淆代碼,二來減少奇奇怪怪的bug,其實這里是涉及到了nodejs模塊化的一個理解,由于在webpack中,它會將代碼分成很多個塊,而每個代碼塊之間并不能相互訪問對方的變量及方法,這就造成了一個非常尷尬的場景,沒法使用jq等這些js庫了,所以這個loader就為我們提供了一個入口,它會將我們給他的庫文件暴漏至全局,當然這些庫必須先符合CommonJS規(guī)范才可以,不會的小可愛需要自己去學(xué)習(xí)ES5以上的知識哦!只是這樣還不夠,我們需要在index.js中去引入,例如這樣:const $ = require('jquery') 然后就可以盡情使用jq啦。

    但是在很多時候,特別是多入口的時候,我們并不希望有些變量被暴漏到window下,除去jq這樣的庫還有一些其他我們私有的公共處理方式在使用下面的多入口加載之后,我們還需要使用webpack自己的注入插件 ProvidePlugin,怎么用呢?代碼如下(當然同樣也要滿足CommonJS規(guī)范):

      // 首先修改alias中的東西
      resolve:{
          // 此設(shè)置是決定了webpack如何去按照什么順序去搜索文件
          extensions: ['.js', '.json'],
          // 相當實用,它會通過別名將原路徑設(shè)置成一個新的路徑
          alias:{
              // 假設(shè)現(xiàn)在在src中我添加了一個base.js公共js
              // 且其中有一個tese函數(shù)
              // 不用擔(dān)心為什么沒有文件后綴,在上面已經(jīng)說明了
               base:path.join(__dirname,'src/base')
          }
      },
      plugins:[
      // 由于webpack生成的代碼塊作用域并不是全局的
      // 所以需要使用此插件用來自動向模塊內(nèi)部注入需要使用到的來自其他代碼塊的變量
          new webpack.ProvidePlugin({
              // 這個的意思是向模塊內(nèi)部提供一個來自base的對外暴漏的方法,在這里
              // funcB是webpack讓你設(shè)置的一個自定義調(diào)用名稱
              // 在這里的話,它會將base中對外暴漏的任何東西都掛載到funcB這個對象中
              funcB:"base",
          })
      ]
    

    那么如何調(diào)用呢,假設(shè)我要在index.js中去使用,那么我們就可以直接在index.js中使用 funcB.test(123) 這樣就可以直接調(diào)用到base中的函數(shù)了。

  • 配置至此,webpack就已經(jīng)可以完全的為你服務(wù)了,現(xiàn)在我們來談一談關(guān)于入口處的一些事情,因為我們不可能只有一個html,js,css對吧,但是在例子中似乎只介紹了引入單個js文件,現(xiàn)在我們開始解鎖多入口模式(不推薦),當我們把entry后面的字符串改為一個數(shù)組或者是一個對象的時候,沒錯此時解鎖了多入口模式,大概是這樣的代碼:
    // 入口位置可以為一個數(shù)組
     entry: ["./src/index.js","./src/base.js"],
    // 還可以放入一個對象,放入一個對象之后,就變成了多入口模式
    // 首先通過每個入口(entry),從各個入口出發(fā)找到依賴模塊(module),生成chunk(代碼塊)
    // 最后會將chunk寫到文件系統(tǒng)中(Assets)
     entry:{
         index:"./src/index.js",
         base:"./src/base.js",
    },

以上代碼展示了,entry分別為數(shù)組,對象時應(yīng)該如何引入入口文件,此處需要注意的是,當沒有寫路徑而直接寫了名稱的時候,例如jquery,這個是使用npm進行安裝,直接安裝到項目的node_modules文件夾內(nèi),才可以被webpack正確的識別并且引入;只是引入了沒有作用的,記得我們用過的 html-webpack-plugin 剩下的工作就交給他來處理了,我們先為其添加一個參數(shù)名為chunks這個參數(shù)是一個數(shù)組,然后將每個入口一一放入其中就像這樣:

    new HtmlWebpackPlugin({
            // 此處是規(guī)定產(chǎn)出html的時候引入那些代碼塊
            // 一般是在入口處為多個文件時使用需要在此處加入,無需順序
            chunks:['index','base']
        }),

記住哦,這只是在之前的基礎(chǔ)上添加了這個屬性而已,而不是重新new一個,別犯傻!這樣就將這些代碼塊都綁定到了index.html中了,然后你就要問了,如果是多個html對應(yīng)多個js的時候怎么辦呢,emm。。。。那就像這樣:

let pages = ['', '']
pages = pages.map( page => new HtmlWebpackPlugin({
    template: './src/index.html',
    filename: `${page}.html`,
    title: `${page}`,
    hash: true,
    chunks: [`${page}`],
    minify: {
        removeAttributeQuotes: true
    },

}))

當然,如果你想使用不同的模板,也可以自行定制,這就不屬于webpack的范疇了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。