webpack二:webpack配置

webpack 是什么邪铲?

中文網(wǎng)站:https://webpack.docschina.org

本質(zhì)上,webpack 是一個(gè)現(xiàn)代 JavaScript 應(yīng)用程序的靜態(tài)模塊打包器(module bundler)。當(dāng) webpack 處理應(yīng)用程序時(shí)掂之,它會(huì)遞歸地構(gòu)建一個(gè)依賴關(guān)系圖(dependency graph)店诗,其中包含應(yīng)用程序需要的每個(gè)模塊,然后將所有這些模塊打包成一個(gè)或多個(gè) bundle盏混。

安裝

 npm install -D webpack webpack-cli
 npm install -D webpack@4 webpack-cli@3

webpack-cli : 提供 webpack 命令蔚鸥、工具

webpack : webpack 代碼

使用

方法一:
./node_modules/.bin/webpack

// 查看版本
./node_modules/.bin/webpack -v
方法二:

編輯 package.jsonscripts 來(lái)簡(jiǎn)化輸入

// package.json
{
    ...,
    "scripts": {
        "start": "webpack"  // scripts 中可以定位到 ./node_modules/.bin/ 目錄下
    }
}
//scripts 中使用 test、start许赃、restart止喷、stop 命名的時(shí)候,可以在調(diào)用的時(shí)候省略 run图焰,即直接 npm start
npm start
方法三:

通過(guò) npx 也可以幫助我們定位命令到 ./node_modules/.bin/ 目錄下

注:npm5.2+ 增加启盛,如果沒(méi)有,可以使用 npm i -g npx 來(lái)安裝

npx webpack

打包模塊

默認(rèn)打包

跟上一個(gè)入口文件路徑webpack 會(huì)從指定的入口文件開(kāi)始分析所有需要依賴的文件技羔,然后把打包成一個(gè)完整文件僵闯。

會(huì)使用 webpack 默認(rèn)的配置對(duì)模塊文件進(jìn)行打包,并把打包后的文件輸出到默認(rèn)創(chuàng)建的 ./dist 目錄下藤滥,打包后的文件名稱默認(rèn)為 main.js鳖粟。

npx webpack ./js/index.js

打包配置

webpack 命令在運(yùn)行的時(shí)候,默認(rèn)會(huì)讀取運(yùn)行命令所在的目錄下的 webpack.config.js 文件拙绊。

也可以通過(guò) —config 選項(xiàng)來(lái)指定配置文件路徑:

webpack --config ./configs/my_webpack.config.js
module.exports = {
  ...   //配置項(xiàng)
}

mode

模式 : "production" | "development" | "none"

不同的模式下向图,webpack設(shè)置了不同的默認(rèn)配置,打包的時(shí)候進(jìn)行一些對(duì)應(yīng)的優(yōu)化标沪。

module.exports = {
  mode: 'production'
}

entry

指定打包?口?文件榄攀,有三種不同的形式

一個(gè)入口、輸出一個(gè)打包文件

module.exports = {
  entry: './src/index.js'
}

多個(gè)入口金句、輸出一個(gè)打包文件

module.exports = {
  entry: [
    './src/index1.js',
    './src/index2.js',
  ]
}

多個(gè)入口檩赢、輸出多打包文件,文件名為對(duì)象的key值违寞。

module.exports = {
  entry: {
    'index1': "./src/index1.js",
    'index2': "./src/index2.js"
  }
}

output

默認(rèn)放在dist目錄下贞瞒,可以通過(guò)output修改打包后的文件位置

module.exports = {
  ...,
  output: {
    //path必須是絕對(duì)路徑偶房,__dirname當(dāng)前目錄
    path: path.resolve(__dirname, "./build"),
    filename: "bundle.js", //單文件出口可以指定固定文件名
    //多文件出口,name從entry的key取
    //filename: "[name].js"
    }
}

WebpackDevServer

啟動(dòng)服務(wù)以后军浆,webpack 不在會(huì)把打包后的文件生成到硬盤(pán)真實(shí)目錄中棕洋,而是直接存在了內(nèi)存中(同時(shí)虛擬了一個(gè)目錄路徑)

npm install --save-dev webpack-dev-server

啟動(dòng)命令:

npx webpack-dev-server

或者,package.json 中添加 scripts

...,
"scripts": {
  "server": "webpack-dev-server"
}

webpack五可以使用webpack server

...,
"scripts": {
  "server": "webpack server"
}

修改 webpack.config.js

module.exports = {
  ...,
  devServer: {
    // 自動(dòng)開(kāi)啟瀏覽器
    open: true,
    // 端口
    port: 8081
    }
}

Proxy

后端代碼
const Koa = require('koa');
const KoaRouter = require('koa-router');
const app = new Koa();
const router = new KoaRouter();

router.get('/info', async ctx => {
    ctx.body = {
        username: 'zMouse',
    }
})
app.use( router.routes() );
app.listen(8787);
前端代碼
//會(huì)產(chǎn)生跨域請(qǐng)求
axios({
  url: 'http://localhost:8787/info'
}).then(res => {
  console.log('res',res.data);
})
//webpack配置后代碼
axios({
  url: 'http://localhost:8787/api/info'
}).then(res => {
  console.log('res',res.data);
})
module.exports = {
    ...,
    devServer: {
        proxy: {
            '/api': {
                target: 'http://localhost:8787',
                pathRewrite: {
                    '^/api': ''
                }
            }
        }
    }
}

Hot Module Replacement

實(shí)現(xiàn)不刷新頁(yè)面乒融,只更新變化的部分

開(kāi)啟 HMR 以后掰盘,當(dāng)代碼發(fā)生變化,webpack 即會(huì)進(jìn)行編譯簇抵,并通過(guò) websocket 通知客戶端(瀏覽器)庆杜,我們需要監(jiān)聽(tīng)處理來(lái)自 webpack 的通知,然后通過(guò) HMR 提供的 API 來(lái)完成我們的局部更新邏輯

module.exports = {
  ...,
  devServer: {
    // 開(kāi)啟熱更新,如果沒(méi)寫(xiě)moudle.hot會(huì)回退為`live reload`
    hot:true,
    // 即使 HMR 不生效,也不去刷新整個(gè)頁(yè)面(選擇開(kāi)啟)
    hotOnly:true,
    }
}

一個(gè)js代碼熱更新示例:

當(dāng) fn1.js 模塊代碼發(fā)生變化的時(shí)候阿迈,把最新的 fn1 函數(shù)綁定到 box1.onclick 上

//fn1.js
export default function() {
    console.log('start1!');
}
import fn1 from './fn1.js';
box1.onclick = fn1;

if (module.hot) {//如果開(kāi)啟 HMR
    module.hot.accept('./fn1.js', function() {
      // 更新邏輯
      box1.onclick = fn1;
    })
}

HMR 以模塊為單位,當(dāng)模塊代碼發(fā)生修改的時(shí)候断盛,通知客戶端進(jìn)行對(duì)應(yīng)的更新,而客戶端則根據(jù)具體的模塊來(lái)更新我們的頁(yè)面邏輯

當(dāng)前一些常用的更新邏輯都有了現(xiàn)成的插件

css熱更新

樣式熱更新愉舔,style-loader 中就已經(jīng)集成實(shí)現(xiàn)

react 熱更新

react 腳手架中已經(jīng)集成

https://github.com/gaearon/react-hot-loader

vue 熱更新

vue 腳手架中已經(jīng)集成

https://github.com/vuejs/vue-loader

sourceMap

https://webpack.docschina.org/configuration/devtool/#devtool

webpack 會(huì)打包合并甚至是壓縮混淆代碼钢猛,所生成的代碼運(yùn)行在瀏覽器時(shí)不利于我們的調(diào)試和定位錯(cuò)誤,

sourceMap是 記錄了編譯后代碼與源代碼的映射關(guān)系的文件

通過(guò) webpackdevtool 選項(xiàng)來(lái)開(kāi)啟 sourceMap轩缤。

module.exports = {
  mode: 'production',
  devtool: 'source-map',
  ...
}

編譯后會(huì)為每一個(gè)編譯文件生成一個(gè)對(duì)應(yīng)的 .map 文件命迈,同時(shí)在編譯文件中添加一段對(duì)應(yīng)的注釋,和對(duì)應(yīng)的 map 文件關(guān)聯(lián)

...
//# sourceMappingURL=main.js.map
...
/*# sourceMappingURL=main.css.map*/

配置推薦:

devtool:"eval-cheap-module-source-map",// 開(kāi)發(fā)環(huán)境
devtool:"source-map"||false,   // 生產(chǎn)環(huán)境

Code Spliting

將代碼分割到多個(gè)不同的bundle(打包后)文件中火的,可以通過(guò)按需加載等方式對(duì)資源進(jìn)行加載

入口起點(diǎn)

通過(guò)設(shè)置多個(gè)入口文件的方式實(shí)現(xiàn)最簡(jiǎn)單的代碼分割

entry: {
  index: "./src/index.js",
  list: "./src/list.js",
},
output: {
  path: resolve(__dirname, "../dist"),
  // 多入口文件的filename不能寫(xiě)死名稱壶愤,需要通過(guò)[name]配置
  filename: "js/[name].js",
}

防止重復(fù)

如果只按上述配置,若index和list都使用了axios馏鹤,都會(huì)把a(bǔ)xios代碼打包其中征椒。

可以通過(guò)設(shè)置dependOn配置多個(gè)模塊之間的共享文件,將共享的axios代碼提取成一個(gè)單獨(dú)文件湃累。

entry: {
  index: {
    import: "./src/index.js",
    dependOn: "axios",
  },
  list: {
    import: "./src/list.js",
    dependOn: "axios",
  },
  axios: "axios",
},
//需要設(shè)置runtimeChunk為single勃救,在所有生成 chunk 之間共享運(yùn)行時(shí)文件,否則axios會(huì)生成兩個(gè)實(shí)例
optimization: {
  runtimeChunk: 'single',
},

SplitChunksPlugin

將公共的依賴模塊提取到已有的入口chunk文件或新的chunk文件當(dāng)中

entry: {
  index: "./src/index.js",
  list: "./src/list.js",
},
optimization: {
  splitChunks: {
    // async表示只從異步加載得模塊(動(dòng)態(tài)加載import())里面進(jìn)行拆分
    // initial表示只從入口模塊進(jìn)行拆分
    // all表示以上兩者都包括
    chunks: "all",
  },
}

動(dòng)態(tài)導(dǎo)入

通過(guò)import()動(dòng)態(tài)導(dǎo)入模塊治力,可以通過(guò)內(nèi)聯(lián)注釋對(duì)chunk進(jìn)行一些配置

模塊方法 | webpack 中文文檔 (docschina.org)

import(/* webpackChunkName: 'data', webpackPreload: true*/ './data')
    .then(data => {
        console.log(data);
    })

Prefetch/Preload

通過(guò)內(nèi)聯(lián)注釋webpackPrefetchwebpackPreload兩種資源提示告知瀏覽器對(duì)資源進(jìn)行不同的加載處理

const data = import(/* webpackChunkName: 'data', webpackPreload: true */ './data.js')
const data = import(/* webpackChunkName: 'data', webpackPrefetch: true */ './data.js')

與 prefetch 指令相比蒙秒,preload 指令有許多不同之處:

preload chunk 會(huì)在父 chunk 加載時(shí),以并行方式開(kāi)始加載宵统。prefetch chunk 會(huì)在父 chunk 加載結(jié)束后開(kāi)始加載税肪。
preload chunk 具有中等優(yōu)先級(jí),并立即下載。prefetch chunk 在瀏覽器閑置時(shí)下載益兄。
preload chunk 會(huì)在父 chunk 中立即請(qǐng)求,用于當(dāng)下時(shí)刻箭券。prefetch chunk 會(huì)用于未來(lái)的某個(gè)時(shí)刻净捅。

外部擴(kuò)展

通過(guò)externals配置在輸出的bundle中排除某些依賴,這些依賴將會(huì)在用戶環(huán)境中所包含辩块。

externals: 
  lodash: '_'
},

tree shaking

將上下文中的dead-code移除蛔六,就像搖樹(shù)上的枯葉使其掉落一樣

optimization: {
  usedExports: true,
}

配置合并

npm install webpack-merge -D
const merge = require("webpack-merge") 
const commonConfig = require("./webpack.common.js") 
const devConfig = { ... }
module.exports = merge(commonConfig,devConfig)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市废亭,隨后出現(xiàn)的幾起案子国章,更是在濱河造成了極大的恐慌,老刑警劉巖豆村,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件液兽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡掌动,警方通過(guò)查閱死者的電腦和手機(jī)四啰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)粗恢,“玉大人柑晒,你說(shuō)我怎么就攤上這事【焐洌” “怎么了匙赞?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)妖碉。 經(jīng)常有香客問(wèn)我涌庭,道長(zhǎng),這世上最難降的妖魔是什么嗅绸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任脾猛,我火速辦了婚禮,結(jié)果婚禮上鱼鸠,老公的妹妹穿的比我還像新娘猛拴。我一直安慰自己,他們只是感情好蚀狰,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布愉昆。 她就那樣靜靜地躺著,像睡著了一般麻蹋。 火紅的嫁衣襯著肌膚如雪跛溉。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音芳室,去河邊找鬼专肪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛堪侯,可吹牛的內(nèi)容都是我干的嚎尤。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼伍宦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼芽死!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起次洼,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤关贵,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后卖毁,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體揖曾,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年势篡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了翩肌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡禁悠,死狀恐怖念祭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碍侦,我是刑警寧澤粱坤,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站瓷产,受9級(jí)特大地震影響站玄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜濒旦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一株旷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧尔邓,春花似錦晾剖、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至灯节,卻和暖如春循头,著一層夾襖步出監(jiān)牢的瞬間绵估,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工卡骂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留国裳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓偿警,卻偏偏與公主長(zhǎng)得像躏救,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子螟蒸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361