摘要:馬上要出了,完全手寫(xiě)一個(gè)優(yōu)化后的腳手架是不可或缺的技能。每個(gè)依賴(lài)項(xiàng)隨即被處理,最后輸出到稱(chēng)之為的文件中,我們將在下一章節(jié)詳細(xì)討論這個(gè)過(guò)程。的事件流機(jī)制保證了插件的有序性,使得整個(gè)系統(tǒng)擴(kuò)展性很好。
webpack馬上要出5了,完全手寫(xiě)一個(gè)優(yōu)化后的腳手架是不可或缺的技能。
本文書(shū)寫(xiě)時(shí)間 2019年5月9日 , webpack版本 4.30.0最新版本
本人所有代碼均手寫(xiě),親自試驗(yàn)過(guò)可以運(yùn)行達(dá)到優(yōu)化效果。
歡迎關(guān)注我的專(zhuān)欄 《前端進(jìn)階》 以后都是高贊高質(zhì)量文章
要轉(zhuǎn)載必須聯(lián)系本人經(jīng)過(guò)同意才可轉(zhuǎn)載 謝謝!
杜絕5分鐘的技術(shù),我們先深入原理再寫(xiě)配置,那會(huì)簡(jiǎn)單很多。
我這套代碼,在開(kāi)發(fā)環(huán)境中性能不是完美的,但是構(gòu)建速度打包生產(chǎn)環(huán)境代碼是極快的,請(qǐng)你一定要去看我的git倉(cāng)庫(kù),現(xiàn)在已經(jīng)加入了項(xiàng)目實(shí)踐,也在里面,可以的話給個(gè)star哦實(shí)現(xiàn)需求:
識(shí)別JSX文件
tree shaking 搖樹(shù)優(yōu)化 刪除掉無(wú)用代碼
識(shí)別 async / await 和 箭頭函數(shù)
PWA功能,熱刷新,安裝后立即接管瀏覽器 離線后仍讓可以訪問(wèn)網(wǎng)站 還可以在手機(jī)上添加網(wǎng)站到桌面使用
preload 預(yù)加載資源 prefetch按需請(qǐng)求資源
CSS模塊化,不怕命名沖突
小圖片的base64處理
文件后綴省掉jsx js json等
實(shí)現(xiàn)React懶加載,按需加載 , 代碼分割 并且支持服務(wù)端渲染
支持less sass stylus等預(yù)處理
code spliting 優(yōu)化首屏加載時(shí)間 不讓一個(gè)文件體積過(guò)大
加入dns-prefetch和preload預(yù)請(qǐng)求必要的資源,加快首屏渲染。
加入prerender,極大加快首屏渲染速度。
提取公共代碼,打包成一個(gè)chunk
每個(gè)chunk有對(duì)應(yīng)的chunkhash,每個(gè)文件有對(duì)應(yīng)的contenthash,方便瀏覽器區(qū)別緩存
圖片壓縮
CSS壓縮
增加CSS前綴 兼容各種瀏覽器
對(duì)于各種不同文件打包輸出指定文件夾下
緩存babel的編譯結(jié)果,加快編譯速度
每個(gè)入口文件,對(duì)應(yīng)一個(gè)chunk,打包出來(lái)后對(duì)應(yīng)一個(gè)文件 也是code spliting
刪除HTML文件的注釋等無(wú)用內(nèi)容
每次編譯刪除舊的打包代碼
將CSS文件多帶帶抽取出來(lái)
讓babel不僅緩存編譯結(jié)果,還在第一次編譯后開(kāi)啟多線程編譯,極大加快構(gòu)建速度
等等....
webpack中文官網(wǎng)的標(biāo)語(yǔ)是 :讓一切都變得簡(jiǎn)單
概念: 本質(zhì)上,webpack 是一個(gè)現(xiàn)代 JavaScript 應(yīng)用程序的靜態(tài)模塊打包器(module bundler)。當(dāng) webpack 處理應(yīng)用程序時(shí),它會(huì)遞歸地構(gòu)建一個(gè)依賴(lài)關(guān)系圖(dependency graph),其中包含應(yīng)用程序需要的每個(gè)模塊,然后將所有這些模塊打包成一個(gè)或多個(gè) bundle。 webpack v4.0.0 開(kāi)始,可以不用引入一個(gè)配置文件。然而,webpack 仍然還是高度可配置的。在開(kāi)始前你需要先理解四個(gè)核心概念:入口(entry)
輸出(output)
loader
插件(plugins)
本文旨在給出這些概念的高度概述,同時(shí)提供具體概念的詳盡相關(guān)用例。
讓我們一起來(lái)復(fù)習(xí)一下最基礎(chǔ)的Webpack知識(shí),如果你是高手,那么請(qǐng)直接忽略這些往下看吧....
入口
入口起點(diǎn)`(entry point)指示 webpack 應(yīng)該使用哪個(gè)模塊,來(lái)作為構(gòu)建其內(nèi)部依賴(lài)圖的開(kāi)始。進(jìn)入入口起點(diǎn)后,webpack 會(huì)找出有哪些模塊和庫(kù)是入口起點(diǎn)(直接和間接)依賴(lài)的。
每個(gè)依賴(lài)項(xiàng)隨即被處理,最后輸出到稱(chēng)之為 bundles 的文件中,我們將在下一章節(jié)詳細(xì)討論這個(gè)過(guò)程。
可以通過(guò)在 webpack 配置中配置 entry 屬性,來(lái)指定一個(gè)入口起點(diǎn)(或多個(gè)入口起點(diǎn))。默認(rèn)值為 ./src。
接下來(lái)我們看一個(gè) entry 配置的最簡(jiǎn)單例子:
webpack.config.js module.exports = { entry: "./path/to/my/entry/file.js" };
入口可以是一個(gè)對(duì)象,也可以是一個(gè)純數(shù)組
entry: { app: ["./src/index.js", "./src/index.html"], vendor: ["react"] }, entry: ["./src/index.js", "./src/index.html"],
有人可能會(huì)說(shuō),入口怎么放HTML文件,因?yàn)殚_(kāi)發(fā)模式下熱更新如果不設(shè)置入口為HTML,那么更改了HTML文件內(nèi)容,是不會(huì)刷新頁(yè)面的,需要手動(dòng)刷新,所以這里給了入口HTML文件,一個(gè)細(xì)節(jié)。
出口(output)
output 屬性告訴 webpack 在哪里輸出它所創(chuàng)建的 bundles,以及如何命名這些文件,默認(rèn)值為 ./dist?;旧希麄€(gè)應(yīng)用程序結(jié)構(gòu),都會(huì)被編譯到你指定的輸出路徑的文件夾中。你可以通過(guò)在配置中指定一個(gè) output 字段,來(lái)配置這些處理過(guò)程:
webpack.config.js const path = require("path"); module.exports = { entry: "./path/to/my/entry/file.js", output: { path: path.resolve(__dirname, "dist"), filename: "my-first-webpack.bundle.js" } };
在上面的示例中,我們通過(guò) output.filename 和 output.path 屬性,來(lái)告訴 webpack bundle 的名稱(chēng),以及我們想要 bundle 生成(emit)到哪里??赡苣阆胍私庠诖a最上面導(dǎo)入的 path 模塊是什么,它是一個(gè) Node.js 核心模塊,用于操作文件路徑。
loader
loader 讓 webpack 能夠去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以將所有類(lèi)型的文件轉(zhuǎn)換為 webpack 能夠處理的有效模塊,然后你就可以利用 webpack 的打包能力,對(duì)它們進(jìn)行處理。
本質(zhì)上,webpack loader 將所有類(lèi)型的文件,轉(zhuǎn)換為應(yīng)用程序的依賴(lài)圖(和最終的 bundle)可以直接引用的模塊。
注意,loader 能夠 import 導(dǎo)入任何類(lèi)型的模塊(例如 .css 文件),這是 webpack 特有的功能,其他打包程序或任務(wù)執(zhí)行器的可能并不支持。我們認(rèn)為這種語(yǔ)言擴(kuò)展是有很必要的,因?yàn)檫@可以使開(kāi)發(fā)人員創(chuàng)建出更準(zhǔn)確的依賴(lài)關(guān)系圖。
在更高層面,在 webpack 的配置中 loader 有兩個(gè)目標(biāo):
test 屬性,用于標(biāo)識(shí)出應(yīng)該被對(duì)應(yīng)的 loader 進(jìn)行轉(zhuǎn)換的某個(gè)或某些文件。
use 屬性,表示進(jìn)行轉(zhuǎn)換時(shí),應(yīng)該使用哪個(gè) loader。
webpack.config.js const path = require("path"); const config = { output: { filename: "my-first-webpack.bundle.js" }, module: { rules: [ { test: /.txt$/, use: "raw-loader" } ] } }; module.exports = config;
以上配置中,對(duì)一個(gè)多帶帶的 module 對(duì)象定義了 rules 屬性,里面包含兩個(gè)必須屬性:test 和 use。這告訴 webpack 編譯器(compiler) 如下信息:
“嘿,webpack 編譯器,當(dāng)你碰到「在 require()/import 語(yǔ)句中被解析為 ".txt" 的路徑」時(shí),在你對(duì)它打包之前,先使用 raw-loader轉(zhuǎn)換一下。”
重要的是要記得,在 webpack 配置中定義 loader 時(shí),要定義在 module.rules 中,而不是 rules。然而,在定義錯(cuò)誤時(shí) webpack 會(huì)給出嚴(yán)重的警告。為了使你受益于此,如果沒(méi)有按照正確方式去做,webpack 會(huì)“給出嚴(yán)重的警告”
loader 還有更多我們尚未提到的具體配置屬性。
這里引用這位作者的優(yōu)質(zhì)文章內(nèi)容,手寫(xiě)一個(gè)loader和plugin 手寫(xiě)一個(gè)loader和plugin
高潮來(lái)了 ,webpack的編譯原理 ,為什么要先學(xué)學(xué)習(xí)原理? 因?yàn)槟闫鸫a得知道你寫(xiě)的是干什么的!
webpack打包原理
識(shí)別入口文件
通過(guò)逐層識(shí)別模塊依賴(lài)。(Commonjs、amd或者es6的import,webpack都會(huì)對(duì)其進(jìn)行分析。來(lái)獲取代碼的依賴(lài))
webpack做的就是分析代碼。轉(zhuǎn)換代碼,編譯代碼,輸出代碼
最終形成打包后的代碼
這些都是webpack的一些基礎(chǔ)知識(shí),對(duì)于理解webpack的工作機(jī)制很有幫助。
什么是loader?
loader是文件加載器,能夠加載資源文件,并對(duì)這些文件進(jìn)行一些處理,諸如編譯、壓縮等,最終一起打包到指定的文件中
處理一個(gè)文件可以使用多個(gè)loader,loader的執(zhí)行順序是和本身的順序是相反的,即最后一個(gè)loader最先執(zhí)行,第一個(gè)loader最后執(zhí)行。
第一個(gè)執(zhí)行的loader接收源文件內(nèi)容作為參數(shù),其他loader接收前一個(gè)執(zhí)行的loader的返回值作為參數(shù)。最后執(zhí)行的loader會(huì)返回此模塊的JavaScript源碼
在使用多個(gè)loader處理文件時(shí),如果要修改outputPath輸出目錄,那么請(qǐng)?jiān)谧钌厦娴?b>loader中options設(shè)置
什么是plugin?
在 Webpack 運(yùn)行的生命周期中會(huì)廣播出許多事件,Plugin 可以監(jiān)聽(tīng)這些事件,在合適的時(shí)機(jī)通過(guò) Webpack 提供的 API 改變輸出結(jié)果。
plugin和loader的區(qū)別是什么?
對(duì)于loader,它就是一個(gè)轉(zhuǎn)換器,將A文件進(jìn)行編譯形成B文件,這里操作的是文件,比如將A.scss或A.less轉(zhuǎn)變?yōu)锽.css,單純的文件轉(zhuǎn)換過(guò)程
plugin是一個(gè)擴(kuò)展器,它豐富了wepack本身,針對(duì)是loader結(jié)束后,webpack打包的整個(gè)過(guò)程,它并不直接操作文件,而是基于事件機(jī)制工作,會(huì)監(jiān)聽(tīng)webpack打包過(guò)程中的某些節(jié)點(diǎn),執(zhí)行廣泛的任務(wù)。
webpack的運(yùn)行
webpack 啟動(dòng)后,在讀取配置的過(guò)程中會(huì)先執(zhí)行 new MyPlugin(options) 初始化一個(gè) MyPlugin 獲得其實(shí)例。在初始化compiler 對(duì)象后,再調(diào)用 myPlugin.apply(compiler) 給插件實(shí)例傳入 compiler 對(duì)象。插件實(shí)例在獲取到 compiler 對(duì)象后,就可以通過(guò) compiler.plugin(事件名稱(chēng), 回調(diào)函數(shù)) 監(jiān)聽(tīng)到 Webpack 廣播出來(lái)的事件。并且可以通過(guò) compiler 對(duì)象去操作 webpack
看到這里可能會(huì)問(wèn)compiler是啥,compilation又是啥?
Compiler 對(duì)象包含了 Webpack 環(huán)境所有的的配置信息,包含 options,loaders,plugins 這些信息,這個(gè)對(duì)象在 Webpack 啟動(dòng)時(shí)候被實(shí)例化,它是全局唯一的,可以簡(jiǎn)單地把它理解為 Webpack 實(shí)例;
Compilation 對(duì)象包含了當(dāng)前的模塊資源、編譯生成資源、變化的文件等。當(dāng) Webpack 以開(kāi)發(fā)模式運(yùn)行時(shí),每當(dāng)檢測(cè)到一個(gè)文件變化,一次新的 Compilation 將被創(chuàng)建。Compilation 對(duì)象也提供了很多事件回調(diào)供插件做擴(kuò)展。通過(guò) Compilation 也能讀取到 Compiler 對(duì)象。
Compiler 和 Compilation 的區(qū)別在于:
Compiler 代表了整個(gè) Webpack 從啟動(dòng)到關(guān)閉的生命周期,而 Compilation 只是代表了一次新的編譯。
事件流
webpack 通過(guò)?Tapable?來(lái)組織這條復(fù)雜的生產(chǎn)線。
webpack 的事件流機(jī)制保證了插件的有序性,使得整個(gè)系統(tǒng)擴(kuò)展性很好。
webpack的事件流機(jī)制應(yīng)用了觀察者模式,和 Node.js 中的 EventEmitter 非常相似。
下面正式開(kāi)始開(kāi)發(fā)環(huán)境的配置:
入口設(shè)置 :
設(shè)置APP,幾個(gè)入口文件,即會(huì)最終分割成幾個(gè)chunk
在入口中配置 vendor,可以code spliting ,將這些公共的復(fù)用代碼最終抽取成一個(gè)chunk,多帶帶打包出來(lái)
要想在開(kāi)發(fā)模式中HMTL文件也熱更新,需要加入·index.html為入口文件
entry: { app: ["./src/index.js", "./src/index.html"], vendor: ["react"] //這里還可以加入redux react-redux better-scroll等公共代碼 },
output出口
webpack基于Node.js環(huán)境運(yùn)行,可以使用Node.js的API,path模塊的resolve方法
對(duì)輸出的JS文件,加入contenthash標(biāo)示,讓瀏覽器緩存文件,區(qū)別版本。
output: { filename: "[name].[contenthash:8].js", path: resolve(__dirname, "../dist") },
mode: "development" 模式選擇,這里直接設(shè)置成開(kāi)發(fā)模式,先從開(kāi)發(fā)模式開(kāi)始。
resolve解析配置,為了為了給所有文件后綴省掉 js jsx json,加入配置
resolve: { extensions: [".js", ".json", ".jsx"] }
加入插件 熱更新plugin和html-webpack-plugin
const HtmlWebpackPlugin = require("html-webpack-plugin") const webpack = require("webpack") new HtmlWebpackPlugin({ template: "./src/index.html" }), new webpack.HotModuleReplacementPlugin(),
加入代碼分割,開(kāi)發(fā)模式也需要代碼分割,性能優(yōu)化
optimization: { runtimeChunk: true, splitChunks: { chunks: "all" } }
加入 babel-loader 還有 解析JSX ES6語(yǔ)法的 babel preset
@babel/preset-react解析 jsx語(yǔ)法
@babel/preset-env解析es6語(yǔ)法
@babel/plugin-syntax-dynamic-import解析react-loadable的import按需加載,附帶code spliting功能
["import", { libraryName: "antd-mobile", style: true }], Antd-mobile的按需加載
{ loader: "babel-loader", options: { //jsx語(yǔ)法 presets: ["@babel/preset-react", //tree shaking 按需加載babel-polifill ["@babel/preset-env", { "modules": false, "useBuiltIns": "false", "corejs": 2 }]], plugins: [ //支持import 懶加載 "@babel/plugin-syntax-dynamic-import", //andt-mobile按需加載 true是less,如果不用less style的值可以寫(xiě)"css" ["import", { libraryName: "antd-mobile", style: true }], //識(shí)別class組件 ["@babel/plugin-proposal-class-properties", { "loose": true }], ], cacheDirectory: true }, }
加入thread-loader,在babel首次編譯后開(kāi)啟多線程
const os = require("os") { loader: "thread-loader", options: { workers: os.cpus().length } }
React的按需加載,附帶代碼分割功能 ,每個(gè)按需加載的組件打包后都會(huì)被多帶帶分割成一個(gè)文件
import React from "react" import loadable from "react-loadable" import Loading from "../loading" const LoadableComponent = loadable({ loader: () => import("../Test/index.jsx"), loading: Loading, }); class Assets extends React.Component { render() { return () } } export default Assets這即將按需加載
加入html-loader識(shí)別html文件
{ test: /.(html)$/, loader: "html-loader" }
加入eslint-loader
{ enforce:"pre", test:/.js$/, exclude:/node_modules/, include:resolve(__dirname,"/src/js"), loader:"eslint-loader" }
開(kāi)發(fā)模式結(jié)束 代碼在下面的git倉(cāng)庫(kù)里
必須了解的webpack熱更新原理 :webpack的熱更新又稱(chēng)熱替換(Hot Module Replacement),縮寫(xiě)為HMR。 這個(gè)機(jī)制可以做到不用刷新瀏覽器而將新變更的模塊替換掉舊的模塊。
首先要知道server端和client端都做了處理工作
第一步,在 webpack 的 watch 模式下,文件系統(tǒng)中某一個(gè)文件發(fā)生修改,webpack 監(jiān)聽(tīng)到文件變化,根據(jù)配置文件對(duì)模塊重新編譯打包,并將打包后的代碼通過(guò)簡(jiǎn)單的 JavaScript 對(duì)象保存在內(nèi)存中。
第二步是 webpack-dev-server 和 webpack 之間的接口交互,而在這一步,主要是 dev-server 的中間件 webpack-dev-middleware 和 webpack 之間的交互,webpack-dev-middleware 調(diào)用 webpack 暴露的 API對(duì)代碼變化進(jìn)行監(jiān)控,并且告訴 webpack,將代碼打包到內(nèi)存中。
第三步是 webpack-dev-server 對(duì)文件變化的一個(gè)監(jiān)控,這一步不同于第一步,并不是監(jiān)控代碼變化重新打包。當(dāng)我們?cè)谂渲梦募信渲昧?b>devServer.watchContentBase 為 true 的時(shí)候,Server 會(huì)監(jiān)聽(tīng)這些配置文件夾中靜態(tài)文件的變化,變化后會(huì)通知瀏覽器端對(duì)應(yīng)用進(jìn)行 live reload。注意,這兒是瀏覽器刷新,和 HMR 是兩個(gè)概念。
第四步也是 webpack-dev-server 代碼的工作,該步驟主要是通過(guò) sockjs(webpack-dev-server 的依賴(lài))在瀏覽器端和服務(wù)端之間建立一個(gè) websocket 長(zhǎng)連接,將 webpack 編譯打包的各個(gè)階段的狀態(tài)信息告知瀏覽器端,同時(shí)也包括第三步中 Server 監(jiān)聽(tīng)靜態(tài)文件變化的信息。瀏覽器端根據(jù)這些 socket 消息進(jìn)行不同的操作。當(dāng)然服務(wù)端傳遞的最主要信息還是新模塊的 hash 值,后面的步驟根據(jù)這一 hash 值來(lái)進(jìn)行模塊熱替換。
webpack-dev-server/client 端并不能夠請(qǐng)求更新的代碼,也不會(huì)執(zhí)行熱更模塊操作,而把這些工作又交回給了 webpack,webpack/hot/dev-server 的工作就是根據(jù) webpack-dev-server/client 傳給它的信息以及 dev-server 的配置決定是刷新瀏覽器呢還是進(jìn)行模塊熱更新。當(dāng)然如果僅僅是刷新瀏覽器,也就沒(méi)有后面那些步驟了。
HotModuleReplacement.runtime 是客戶端 HMR 的中樞,它接收到上一步傳遞給他的新模塊的 hash 值,它通過(guò) JsonpMainTemplate.runtime 向 server 端發(fā)送 Ajax 請(qǐng)求,服務(wù)端返回一個(gè) json,該 json 包含了所有要更新的模塊的 hash 值,獲取到更新列表后,該模塊再次通過(guò) jsonp 請(qǐng)求,獲取到最新的模塊代碼。這就是上圖中 7、8、9 步驟。
而第 10 步是決定 HMR 成功與否的關(guān)鍵步驟,在該步驟中,HotModulePlugin 將會(huì)對(duì)新舊模塊進(jìn)行對(duì)比,決定是否更新模塊,在決定更新模塊后,檢查模塊之間的依賴(lài)關(guān)系,更新模塊的同時(shí)更新模塊間的依賴(lài)引用。
最后一步,當(dāng) HMR 失敗后,回退到 live reload 操作,也就是進(jìn)行瀏覽器刷新來(lái)獲取最新打包代碼。
參考文章 webpack面試題-騰訊云
正式開(kāi)始生產(chǎn)環(huán)節(jié):
加入 WorkboxPlugin , PWA的插件
pwa這個(gè)技術(shù)其實(shí)要想真正用好,還是需要下點(diǎn)功夫,它有它的生命周期,以及它在瀏覽器中熱更新帶來(lái)的副作用等,需要認(rèn)真研究??梢詤⒖及俣鹊?b>lavas框架發(fā)展歷史~
const WorkboxPlugin = require("workbox-webpack-plugin") new WorkboxPlugin.GenerateSW({ clientsClaim: true, //讓瀏覽器立即servece worker被接管 skipWaiting: true, // 更新sw文件后,立即插隊(duì)到最前面 importWorkboxFrom: "local", include: [/.js$/, /.css$/, /.html$/,/.jpg/,/.jpeg/,/.svg/,/.webp/,/.png/], }),
加入每次打包輸出文件清空上次打包文件的插件
const CleanWebpackPlugin = require("clean-webpack-plugin") new CleanWebpackPlugin()
加入code spliting代碼分割
optimization: { runtimeChunk:true, //設(shè)置為 true, 一個(gè)chunk打包后就是一個(gè)文件,一個(gè)chunk對(duì)應(yīng)`一些js css 圖片`等 splitChunks: { chunks: "all" // 默認(rèn) entry 的 chunk 不會(huì)被拆分, 配置成 all, 就可以了拆分了,一個(gè)入口`JS`, //打包后就生成一個(gè)多帶帶的文件 } }
加入多帶帶抽取CSS文件的loader和插件
const MiniCssExtractPlugin = require("mini-css-extract-plugin") { test: /.(less)$/, use: [ MiniCssExtractPlugin.loader, { loader: "css-loader", options: { modules: true, localIdentName: "[local]--[hash:base64:5]" } }, {loader:"postcss-loader"}, { loader: "less-loader" } ] } new MiniCssExtractPlugin({ filename:"[name].[contenthash:8].css" }),
加入壓縮css的插件
const OptimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin") new OptimizeCssAssetsWebpackPlugin({ cssProcessPluginOptions:{ preset:["default",{discardComments: {removeAll:true} }] } }),
殺掉html一些沒(méi)用的代碼
new HtmlWebpackPlugin({ template: "./src/index.html", minify: { removeComments: true, collapseWhitespace: true, removeRedundantAttributes: true, useShortDoctype: true, removeEmptyAttributes: true, removeStyleLinkTypeAttributes: true, keepClosingSlash: true, minifyJS: true, minifyCSS: true, minifyURLs: true, } }),
加入圖片壓縮
{ test: /.(jpg|jpeg|bmp|svg|png|webp|gif)$/, use:[ {loader: "url-loader", options: { limit: 8 * 1024, name: "[name].[hash:8].[ext]", outputPath:"/img" }}, { loader: "img-loader", options: { plugins: [ require("imagemin-gifsicle")({ interlaced: false }), require("imagemin-mozjpeg")({ progressive: true, arithmetic: false }), require("imagemin-pngquant")({ floyd: 0.5, speed: 2 }), require("imagemin-svgo")({ plugins: [ { removeTitle: true }, { convertPathData: false } ] }) ] } } ] }
加入file-loader 把一些文件打包輸出到固定的目錄下
{ exclude: /.(js|json|less|css|jsx)$/, loader: "file-loader", options: { outputPath: "media/", name: "[name].[contenthash:8].[ext]" } }
里面有一些注釋可能不詳細(xì),代碼都是自己一點(diǎn)點(diǎn)寫(xiě),試過(guò)的,肯定沒(méi)用任何問(wèn)題
需要的依賴(lài)
{ "name": "webpack", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "@babel/core": "^7.4.4", "@babel/preset-env": "^7.4.4", "@babel/preset-react": "^7.0.0", "autoprefixer": "^9.5.1", "babel-loader": "^8.0.5", "clean-webpack-plugin": "^2.0.2", "css-loader": "^2.1.1", "eslint": "^5.16.0", "eslint-loader": "^2.1.2", "file-loader": "^3.0.1", "html-loader": "^0.5.5", "html-webpack-plugin": "^3.2.0", "imagemin": "^6.1.0", "imagemin-gifsicle": "^6.0.1", "imagemin-mozjpeg": "^8.0.0", "imagemin-pngquant": "^7.0.0", "imagemin-svgo": "^7.0.0", "img-loader": "^3.0.1", "less": "^3.9.0", "less-loader": "^5.0.0", "mini-css-extract-plugin": "^0.6.0", "optimize-css-assets-webpack-plugin": "^5.0.1", "postcss-loader": "^3.0.0", "react": "^16.8.6", "react-dom": "^16.8.6", "react-loadable": "^5.5.0", "react-redux": "^7.0.3", "style-loader": "^0.23.1", "url-loader": "^1.1.2", "webpack": "^4.30.0", "webpack-cli": "^3.3.2", "webpack-dev-server": "^3.3.1", "workbox-webpack-plugin": "^4.3.1" }, "scripts": { "start": "webpack-dev-server --config ./config/webpack.dev.js", "dev": "webpack-dev-server --config ./config/webpack.dev.js", "build": "webpack --config ./config/webpack.prod.js " }, "devDependencies": { "@babel/plugin-syntax-dynamic-import": "^7.2.0" } }整個(gè)項(xiàng)目和webpack配置的源碼地址 已經(jīng)更新 : 源碼地址啊 看得見(jiàn)嗎親 路過(guò)的小伙伴麻煩點(diǎn)個(gè)贊給個(gè)star,寫(xiě)得好辛苦?。。。。?/strong>
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/110199.html
摘要:只有動(dòng)手,你才能真的理解作者的構(gòu)思的巧妙只有動(dòng)手,你才能真正掌握一門(mén)技術(shù)持續(xù)更新中項(xiàng)目地址求求求源碼系列跟一起學(xué)如何寫(xiě)函數(shù)庫(kù)中高級(jí)前端面試手寫(xiě)代碼無(wú)敵秘籍如何用不到行代碼寫(xiě)一款屬于自己的類(lèi)庫(kù)原理講解實(shí)現(xiàn)一個(gè)對(duì)象遵循規(guī)范實(shí)戰(zhàn)手摸手,帶你用擼 Do it yourself!!! 只有動(dòng)手,你才能真的理解作者的構(gòu)思的巧妙 只有動(dòng)手,你才能真正掌握一門(mén)技術(shù) 持續(xù)更新中…… 項(xiàng)目地址 https...
摘要:馬上要出了,完全手寫(xiě)一個(gè)優(yōu)化后的腳手架是不可或缺的技能。每個(gè)依賴(lài)項(xiàng)隨即被處理,最后輸出到稱(chēng)之為的文件中,我們將在下一章節(jié)詳細(xì)討論這個(gè)過(guò)程。的事件流機(jī)制保證了插件的有序性,使得整個(gè)系統(tǒng)擴(kuò)展性很好。 webpack馬上要出5了,完全手寫(xiě)一個(gè)優(yōu)化后的腳手架是不可或缺的技能。 本文書(shū)寫(xiě)時(shí)間 2019年5月9日 , webpack版本 4.30.0最新版本 本人所有代碼均手寫(xiě),親自試驗(yàn)過(guò)可...
摘要:馬上要出了,完全手寫(xiě)一個(gè)優(yōu)化后的腳手架是不可或缺的技能。每個(gè)依賴(lài)項(xiàng)隨即被處理,最后輸出到稱(chēng)之為的文件中,我們將在下一章節(jié)詳細(xì)討論這個(gè)過(guò)程。的事件流機(jī)制保證了插件的有序性,使得整個(gè)系統(tǒng)擴(kuò)展性很好。 webpack馬上要出5了,完全手寫(xiě)一個(gè)優(yōu)化后的腳手架是不可或缺的技能。 本文書(shū)寫(xiě)時(shí)間 2019年5月9日 , webpack版本 4.30.0最新版本 本人所有代碼均手寫(xiě),親自試驗(yàn)過(guò)可...
摘要:或者的,都會(huì)對(duì)其進(jìn)行分析。舒適的開(kāi)發(fā)體驗(yàn),有助于提高我們的開(kāi)發(fā)效率,優(yōu)化開(kāi)發(fā)體驗(yàn)也至關(guān)重要組件熱刷新熱刷新自從推出熱刷新后,前端開(kāi)發(fā)者在開(kāi)環(huán)境下體驗(yàn)大幅提高。實(shí)現(xiàn)熱調(diào)試后,調(diào)試流程大幅縮短,和普通非直出模式調(diào)試體驗(yàn)保持一致。 showImg(https://segmentfault.com/img/bVbtOR3?w=1177&h=635); webpack,打包所有的資源 不知道不...
閱讀 1561·2021-11-25 09:43
閱讀 2347·2019-08-30 15:55
閱讀 1471·2019-08-30 13:08
閱讀 2682·2019-08-29 10:59
閱讀 823·2019-08-29 10:54
閱讀 1595·2019-08-26 18:26
閱讀 2555·2019-08-26 13:44
閱讀 2659·2019-08-23 18:36