webpack入坑之路

Hi ~ 許久沒(méi)更新的小簡(jiǎn)書(shū),自從換了新工作,日夜掉發(fā)式的瘋狂加班,一個(gè)半月的時(shí)間學(xué)到了不少東西,趁熱記錄一波吧~


程序員病.png

一個(gè)月前,接到了一個(gè)需求,并且長(zhǎng)期需要維護(hù)多個(gè)無(wú)關(guān)的活動(dòng)頁(yè)或者場(chǎng)景頁(yè),自以為簡(jiǎn)單的我樂(lè)呵呵的接了需求,心中已經(jīng)想好“用react來(lái)搭一個(gè)多頁(yè)面應(yīng)用就夠符合需求啦~”,事實(shí)證明,我還是too young too simple ,sometimes naive...

自拍照.png

實(shí)際開(kāi)發(fā)工作中,react多頁(yè)面應(yīng)用的腳手架GitHub上有很多,自己也可以根據(jù)官方的react腳手架就可以愉快的擼起來(lái),但是目前遇到的比較頭疼的問(wèn)題是,怎么讓我的react應(yīng)用代碼壓縮模塊打包,這個(gè)時(shí)候就很有必要好好研究下webpack的使用了。

此次分享主要是針對(duì)多頁(yè)面的webpack4打包。

So,咱們來(lái)聊一下,什么是webpack?

官網(wǎng)webpack圖

官網(wǎng)上的webpack相信所有前端開(kāi)發(fā)童鞋都見(jiàn)過(guò),webpack做的事情,就是將我們的js應(yīng)用的各個(gè)文件按照模塊打包成多個(gè)bundle,是一個(gè)靜態(tài)模塊的打包器。

webpack做的事情,就是分析項(xiàng)目結(jié)構(gòu),找到j(luò)s模塊以及一些不能直接運(yùn)行的語(yǔ)言,并將其打包成合適的格式給瀏覽器執(zhí)行。

安裝webpack

npm install webpack-cli 

了解webpack前需要知道webpack的四大核心概念,entry、output、loader、plugins。

Entry(入口)

entry是webpack的起點(diǎn)指示,告訴webpack從哪里開(kāi)始入手打包任務(wù),用來(lái)指定入口,默認(rèn)值是./src。

如果是做單頁(yè)面程序,單個(gè)入口。

//單個(gè)入口的寫(xiě)法  entry: string|Array<string>
entry:{
  main:'../src/component/my.js'
}
entry:'../src/component/my.js'
//如果傳數(shù)組形式,是注入多個(gè)入口以及多個(gè)依賴(lài)文件。

如果是做多個(gè)頁(yè)面,多個(gè)入口。

//多個(gè)入口的寫(xiě)法,所有的文件會(huì)被打包到dist文件中。
entry:{
  app:['./a.js','./b.js','./c.js']
}
//最終輸出 dist/a.js   /  dist/b.js   dist/c.js

當(dāng)webpack在解析代碼時(shí),每遇到import或者require引入的依賴(lài),最終會(huì)被打包在最終構(gòu)建結(jié)果中。打包的最終結(jié)果只會(huì)引入該模塊引入的依賴(lài)。

output(輸出)

打包完后輸出的位置

output: {
    filename: 'vendor.js',
    path: '/home/index'
  }

loader(加載器)

實(shí)際上webpack只能打包js文件,其他資源例如css和html是需要加載器來(lái)將資源轉(zhuǎn)化,加載進(jìn)來(lái)。

舉個(gè)栗子,如果項(xiàng)目中使用了sass的樣式語(yǔ)法,是無(wú)法被瀏覽器所識(shí)別的,因此需要引用loader,將sass轉(zhuǎn)義成能被識(shí)別的css語(yǔ)法閱讀。

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

在該項(xiàng)目中,react用的是jsx的語(yǔ)法,同樣無(wú)法被瀏覽器所識(shí)別,需要引用babel將jsx語(yǔ)法轉(zhuǎn)義成正常的js運(yùn)行。

module:{
  rules:[
     {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: [
              "@babel/preset-env",//可以根據(jù)配置的目標(biāo)瀏覽器或者運(yùn)行環(huán)境來(lái)自動(dòng)將2015+的代碼轉(zhuǎn)為es5
              "@babel/preset-react",
              { "plugins": ["@babel/plugin-proposal-class-properties"] }//這句可以在項(xiàng)目中使用箭頭函數(shù)
            ],
          }
        },
  ]
}

loader的職責(zé)是單一的,一個(gè)loader相當(dāng)于一個(gè)翻譯官,只做翻譯某種語(yǔ)言,需要關(guān)心輸入和輸出。
一個(gè)項(xiàng)目里有多個(gè)翻譯官,在調(diào)用多個(gè) Loader 去轉(zhuǎn)換一個(gè)文件時(shí),每個(gè) Loader 會(huì)鏈?zhǔn)降捻樞驁?zhí)行, 第一個(gè) Loader 將會(huì)拿到需處理的原內(nèi)容,上一個(gè) Loader 處理后的結(jié)果會(huì)傳給下一個(gè)接著處理,最后的 Loader 將處理后的最終結(jié)果返回給 Webpack。

plugins(插件)

常用的插件有

  • webpack-dev-server
  • copy-webpack-plugin
  • uglifyjs-webpack-plugin
  • webpack-spritesmith
  • clean-webpack-plugin
  • html-webpack-plugin
    ...還有好多好多

webpack-dev-server
非常常見(jiàn),用于啟動(dòng)本地開(kāi)發(fā)模式,本身是一個(gè)express服務(wù)器,封裝了webpack-hot-middleware,實(shí)現(xiàn)了熱更新。

devServer:{
  host:'0.0.0.0' || 'localhost',
  post:9000,//打開(kāi)的端口
  open:true,//自動(dòng)打開(kāi)
  contentBase:path.join(_dirname,'src')//不設(shè)置的話(huà),默認(rèn)是當(dāng)前執(zhí)行的目錄,一般是項(xiàng)目根目錄,會(huì)在項(xiàng)目根目錄查找index.html文件。
}

copy-webpack-plugin
在webpack相中拷貝文件或文件夾的方法。

new CopyWebpackPlugin({
  from:'.....',//需要拷貝的源目標(biāo)文件
  to:'',//拷貝后存放的文件位置
})

uglifyjs-webpack-plugin
用來(lái)壓縮優(yōu)化js文件,webpack4+以上的版本可使用。
webpack4之前的版本是通過(guò)webpack.optimize.commonsChuckPlugin來(lái)壓縮js

module.exports={
  optimization:{
    minimizer:true,//默認(rèn)為true,效果就是壓縮js代碼
    splitChuncks:{
      chunks:'async',//'async':分割異步打包的代碼,'all':同時(shí)分割同步和異步代碼
      cacheGroups:{//默認(rèn)的規(guī)則不會(huì)打包,需要單獨(dú)定義
        vendors:{
          test:/[\\/]node_modules[\\/]/,
          name:'vendors'
        },
        commons:{
          test:/commons\.js/,
          name:'commons'
        }
      }
      
    }  
  }  
}

webpack-spritesmith
把零散的小圖生成一張雪碧圖,減少http請(qǐng)求

new SpritesmithPlugin({
      // 目標(biāo)小圖標(biāo)
      src: {
        cwd: `src/assets/images/sprites`,
        glob: '*.png'
      },
      // 輸出雪碧圖文件及樣式文件7
      target: {
        image: `dist/static/images/sprite-[hash].png`,
        css: [
          [
            `dist/static/css/sprite.css`, {
              formatOpts: {
                cssSelector: (groupName) => `.icon-${groupName.name}` // 修改生成的sprite css中類(lèi)名定義
              }
            }
          ]
        ]
      },
      // 樣式文件中調(diào)用雪碧圖地址寫(xiě)法
      apiOptions: {
        cssImageRef: '../images/sprite-[hash].png'
      },
      spritesmithOptions: {
        algorithm: 'top-down'
      }
    })

clean-webpack-plugin
用來(lái)清除文件

// 刪除文件 保留新文件
new CleanWebpackPlugin(['dist']),

html-webpack-plugin
為入口文件html加載js依賴(lài),動(dòng)態(tài)添加編譯后的hash值文件,防止引用緩存文件的問(wèn)題。

const HtmlWebpackPlugin = require('html-webpack-plugin')
  plugins: [
    new HtmlWebpackPlugin({ // 打包輸出HTML
      minify: { // 壓縮HTML文件
        removeComments: true, // 移除HTML中的注釋
        collapseWhitespace: true, // 刪除空白符與換行符
        minifyCSS: true// 壓縮內(nèi)聯(lián)css
      },
      filename: 'a.html',
      template: 'a.html'
    }),
    new HtmlWebpackPlugin({ // 打包輸出HTML
      minify: { // 壓縮HTML文件
        removeComments: true, // 移除HTML中的注釋
        collapseWhitespace: true, // 刪除空白符與換行符
        minifyCSS: true// 壓縮內(nèi)聯(lián)css
      },
      filename: 'b.html',
      template: 'b.html'
    }),
  ]

項(xiàng)目是多頁(yè)的情況下,傳入的html入口文件設(shè)置多個(gè)即可。
可以寫(xiě)一個(gè)提取html的函數(shù),批量獲取,組合成數(shù)組形式。

resolve配置

webpack在啟動(dòng)后會(huì)從配置的入口模塊出發(fā)去找尋所有依賴(lài)的模塊,resolve配置webpack如何找尋模塊所對(duì)應(yīng)的文件。
alias
resolve.alias配置項(xiàng)通過(guò)設(shè)置其他名字來(lái)將原路徑映射成新的路徑

resolve:{
  extensions: ['.js', '.json','.css'],//導(dǎo)入的語(yǔ)句中如果沒(méi)帶文件后綴名,webpack會(huì)自動(dòng)帶上后綴名去嘗試文件是否存在,用于配置在嘗試過(guò)程中用到的后綴列表。
  alias:{
    'api':utils.resolve('/src/common/api/'),//通過(guò)api關(guān)鍵字替換'/src/common/api/'
  }
}

總結(jié)

歸結(jié)webpack在實(shí)際項(xiàng)目中做了哪些事情?
1、webpack從context設(shè)置的文件位置開(kāi)始找尋
2、尋找entry里的所有文件名
3、在js文件編譯過(guò)程中,遇到 import | require 引入的依賴(lài)文件,然后在依賴(lài)文件遞歸找尋所有依賴(lài),最終打包在最終編譯生成的文件。
4、webpack把所有生成的文件都輸出到output.path路徑中,以output.filename對(duì)應(yīng)命名的模塊來(lái)命名。

webpack之所以強(qiáng)大,是在于插件各式各樣,總能滿(mǎn)足你的需求。webpack4的新api大大的提高了Code Splitting 的體驗(yàn),以上講的內(nèi)容還是淺顯了點(diǎn),具體的一些細(xì)節(jié)還是需要靠同志們自己愉快的擼起來(lái),只有實(shí)操才是檢驗(yàn)?zāi)芰Φ奈ㄒ煌緩絶


婊砸.png

最后,po上項(xiàng)目中的webpack相關(guān)依賴(lài)的版本情況

{
 "@babel/core": "^7.1.2",
    "@babel/plugin-proposal-class-properties": "^7.2.1",
    "@babel/plugin-transform-runtime": "^7.3.4",
    "@babel/preset-env": "^7.1.0",
    "@babel/preset-react": "^7.0.0",
    "@babel/runtime": "^7.3.4",
    "babel-loader": "^8.0.4",
    "babel-preset-env": "^1.7.0",
    "clean-webpack-plugin": "^2.0.0",
    "copy-webpack-plugin": "^5.0.3",
    "css-loader": "^1.0.0",
    "file-loader": "^2.0.0",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "image-webpack-loader": "^5.0.0",
    "jsx-loader": "^0.13.2",
    "postcss-loader": "^3.0.0",
    "sass-loader": "^7.1.0",
    "script-loader": "^0.7.2",
    "style-loader": "^0.23.0",
    "uglifyjs-webpack-plugin": "^2.0.1",
    "url-loader": "^1.1.2",
    "webpack": "^4.20.2",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.9",
    "webpack-spritesmith": "^0.5.4",
    "clean-webpack-plugin": "^2.0.0",
    "copy-webpack-plugin": "^5.0.3",
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容