核心
- webpack 是用來搭建前端工程的
- 它運行在node環境中,它所做的事情,簡單來說,就是打包
- 具體來說,就是以某個模塊作為入口,根據入口分析出所有模塊的依賴關系,然后對各種模塊進行合并、壓縮,形成最終的打包結果
- 在webpack的世界中,一切都是模塊
體驗
按照習慣,所有的模塊均放置在 src 目錄中
- 安裝依賴
- 編寫多個模塊 隨意模塊,可以是js、圖片、音視頻,以入口模塊為起點,形成依賴關系
- 運行
npm run build
命令,進行打包 - 查看打包結果 ,打包結果放置在dist目錄中
不難發現,webpack給我們帶來了以下好處:
- 可以大膽的使用任意模塊化標準,無須擔心兼容性問題,因為webpack完成打包后,已經沒有了任何模塊化語句
- 可以將一些非 js 代碼也視為模塊,這樣可以對 css 、圖片等資源進行更加細粒度的劃分
- 在前端開發中,也可以使用npm。webpack不會運行源代碼,無論是自己寫的模塊還是通過npm安裝的模塊,webpack 一律認為是依賴,最終合并到打包結果中
- 非常適合開發單頁應用,單頁應用是前端用戶體驗最好的web應用,所謂單頁應用,是指只有一個html頁面,頁面中沒有任何內容,所有的內容均靠js生成,要優雅的實現單頁應用,最好依托于前端框架,比如vue、react
- webpack 給我們開發帶來的變化遠不止于此
頁面模版
- 對于單頁應用而言,只有一個空白的頁面,所有內容都靠 js 代碼創建
- webpack 會自動生成一個頁面,并且在頁面中會自動加入對 js 和 css 的引用
- 它生成頁面時,參考的是 public/index.html,其稱之為頁面模版
public目錄
- webpack 會非常暴力的將 public 目錄中的所有文件(除頁面模板外),復制到打包結果中
開發服務器
- 如果每次修改完代碼,都要經過 打包-> 運行,太過麻煩了
- 在開發階段,我們可以運行
npm run serve
命令獲得更好的打包體驗 - 該命令會讓
webpack
啟動一個開發服務器 - 在這個階段,webpack并不會形成打包結果文件,而是把打包的內容放到內存中,當我們請求服務器時,服務器從內存中給予我們打包結果
- 與此同時,當源碼發生變動時,webpack會自動重新打包,同時刷新頁面以訪問到最新的打包結果
文件緩存
- 除了頁面外,其他的資源在打包完成后,文件名多了一些奇奇怪怪的字符
- 例如:js/app-22324a23.js
- 其中,22324a23 這樣的字符稱之為hash,它會隨著模塊內容的變化而變化
- 源碼內容不變,hash不變;源碼內容變化,hash變化
- 之所以這樣做,是因為生產環境中,瀏覽器會對除頁面外的靜態資源進行緩存
- 如果不設置hash值,一旦代碼更新,瀏覽器還會使用之前緩存的結果,無法使用最新的代碼
- **webpack會在打包時自動處理 hash 值,并不會對我們寫代碼造成任何影響,但作為一個前端開發者,有必要了解一下
資源路徑
-
除代碼和樣式模塊外,其他模塊被視為資源模塊
-
值得注意的是,資源模塊在源代碼中的路徑和打包后的路徑是不一樣的,這就導致了我們在編寫代碼的時候,根本無法知曉資源最終的路徑
-
最常見的例子就是在css中使用背景圖片
-
.container {/* 背景圖使用了源碼中的路徑 */background: url('../assets/1.jpg'); }
-
這里可以正常工作,因為webpack 可以非常智能的發現這一點,對于css中的路徑,webpack在打包時,會將其自動轉為打包結果的路徑
-
上面的例子可能被轉換為下面的代碼:
-
.container {background: url(/img/1234aa.jpg); }
-
但是我們要通過 js 動態的使用路徑,webpack 是無法識別的
// 打包前
const url = './assets/1.png'; // 路徑無法被轉換
img.src = url;// 打包后
const url = './assets/1.png'; // 錯誤
img.src = url;
- 正確的做法是,通過模塊化的方式導入資源,并獲取資源路徑
// 打包前
import url from './assets/1.png'; // 打包后,url得到的是打包后的路徑
img.src = url;// 打包后
const url = '/img/1234aa.png'; // 正確
img.src = url;
缺省的文件和后綴名
- 導入模塊時,所有 js 模塊均可省略 .js ,若導入的模塊文件名為 index.js ,可省略文件名
import './home'; // home.js
import './movie'; // 若movie是一個目錄,則導入的是./movie/index.js
路徑別名
- 隨著代碼量的增加,不可避免的是形成層級深的目錄
- webpack 提供了別名供我們快速定位到 ./src 目錄,通常,該別名為@
js 兼容性
- 當webpack 讀取到 js 代碼時,會自動對其進行兼容性處理
- 具體的處理方案涉及兩個配置文件
-
babel.config.js
: 配置該文件,可以設置對哪些 js 代碼進行降級處理.browserslistrc
: 配置該文件,可以設置在降級時,要兼容哪些瀏覽器,兼容的范圍越廣,降級產生的代碼就越多,自然打包后的體積就越大
打包壓縮
- webpack 在打包時,會對所有的 js 和 css 代碼進行壓縮
- 對于 js ,除了壓縮外,還會對其中的各種名稱進行混淆
- 混淆的作用一是為了進一步壓縮包體積,二是為了我們的代碼更難被其他人理解利用
源碼地圖
- source map
- 打包后的結果是很難閱讀的
- 如果代碼報錯,我們將難以得知出錯的代碼行
- 可以發現,打包后都會跟上一個同名的、后綴為 .map 的文件,該文件就保存了原始代碼的內容
- 這個內容人類是看不懂的,但是瀏覽器可以看懂
- 代碼報錯時,瀏覽器定位到源碼地圖中的對應代碼,而不是把真實報錯的代碼展示給我們
css工程化
- webpack 能夠識別所有的樣式代碼,包括 css、 less、sass、stylus
- 打包時,便會將它們轉換為純正的 css
自動廠商前綴
- css有很多兼容性問題,解決這些問題最常見的辦法就是加上廠商前綴
- webpack 會根據
.browserlistrc
中指定的瀏覽器范圍,按需自動加上廠商前綴
css module
- css 文件多了后,為了保證它們之間沒有沖突的類樣式
- 靠的是 css module
- 當樣式文件以
xxx.module.xxx
的方式命名時,webpack 會將該文件當成一個開啟了 css module 的文件 - 然后文件中的所有類名都將被 hash 化
- 我們在使用類名時,通過下面的方式得知打包后的類名
import './index.module.less';
dom.classList.add('container'); // ? 最終的類名可不是這個// styles 是一個對象,里面映射了源碼類名和打包類名的關系
import styles from './index.module.less';
dom.classList.add(styles.container); // ? 屬性container中記錄的就是container轉換后的類名
其實webpack 并沒有這么強大
- 實際上,它就是通過插件(plugin) 和加載器(loader)將這些技術整合在一起
.browserslistrc
:表達適配的瀏覽器范圍,會被工程化中的其他技術所使用babel.config.js
:babel的配置文件,做 js 降級處理postcss.config.js
:postcss 的配置文件,做css代碼轉換webpack.config.js
:webpack 的配置文件,整合其他工程化技術,以及配置打包細節、開發服務器、路徑別名等
對我們的影響(important)
- 學會訪問開發服務器查看效果
- 學會動態獲取資源文件路徑(import url from ‘./assets/1.jpg’)
- 學會省略文件和后綴名(js文件和index.js文件)
- 學會使用別名簡化導入代碼(import ‘@/a/a1’)
- 學會使用 css module(index.module.less)