Webpack 原理與實(shí)踐之如何通過 Loader 加載器進(jìn)行資源加載?
寫在前面
我們知道webpack其實(shí)不僅是javascript模塊打包工具,更是整個前端項(xiàng)目即前端工程的模塊打包工具,可以通過webpack去管理前端項(xiàng)目中任意類型的資源文件。
如何加載資源模塊
首先,我們在項(xiàng)目的src目錄下添加一個樣式文件main.css。目錄結(jié)構(gòu)如下:
- |--03-loader
- |--src
- |--main.css
- |--package.json
- |--webpack.config.js
- /* main.css */
- body{
- margin:0 auto;
- padding:0 20px;
- max-width:800px;
- background:yellow;
- }
接下來,在webpack.config.js配置中的入口文件路徑進(jìn)行更改為main.css文件路徑,執(zhí)行webpack直接進(jìn)行打包c(diǎn)ss資源文件。
- const path = require("path")
- module.exports = {
- // 樣式文件路徑
- entry:"src/main.css",
- output:{
- filename:"bundle.js",
- path:path.join(__dirname,"output")
- },
- mode:"none"
- }
如果我們不進(jìn)行其他的任何配置,此時直接執(zhí)行打包命令,會報(bào)錯提示我們報(bào)錯,因?yàn)橹荒苁鞘褂胘s文件作為打包入口。之所以會這樣,那是因?yàn)樵趙ebpack中默認(rèn)解析的是js語法,而對于非js語法需要先進(jìn)行Loader,再在配置文件中另外進(jìn)行配置loader。
css文件通過css-loader進(jìn)行處理,再提交給webpack進(jìn)行打包生成js文件。
- $ npm i css-loader -D
但是,當(dāng)你此時執(zhí)行打包命令后,嘗試在你頁面中使用生成bundle.js文件,會發(fā)現(xiàn)剛剛的main.css模塊并沒有起作用,那么我們需要額外添加一個style-lodaer加載器,這樣就能正常工作了。樣式?jīng)]有生效的原因是:css-loader只會把css模塊加載到j(luò)s代碼中,而不會直接使用此模塊。
那么,在你安裝完style-lodaer后,將配置文件中的use屬性修改為數(shù)組,將style-lodaer也配置進(jìn)去。因?yàn)閘oader數(shù)組的加載順序是自下而上的,所以style-lodaer應(yīng)該配置在css-loader上面。
- //main.js
- import "./style.css"
- console.log("hello yichuan");
- /* style.css */
- body{
- margin:0 auto;
- padding:0 20px;
- max-width:800px;
- background:yellow;
- }
loader加載器是整個webpack打包配置的核心,因?yàn)樾枰ㄟ^它去實(shí)現(xiàn)任意類型文件的打包,這樣最后都進(jìn)行打包生成了js文件。
那么,為什么webpack要在js中載入css文件,而不是將樣式文件和行為進(jìn)行分離?
這是因?yàn)椋嬲枰渌Y源的并不是整個項(xiàng)目中,而是某個模塊需要使用。
假設(shè)在進(jìn)行頁面開發(fā)某個局部功能時,需要使用到一個樣式模塊和一個圖片文件,如果你還是將這些資源單獨(dú)引入到html文件中,然后再到j(luò)s中添加對應(yīng)的邏輯代碼,試想如果后期不需要這個局部功能,那么就需要同時刪除JS中的代碼和html中的資源文件引入,也就是需要同時維護(hù)多條線。然而,此時你遵循webapck的導(dǎo)入設(shè)計(jì),所有資源加載都是通過js代碼控制,那么后期只需要維護(hù)js代碼就行。
為什么要建立這種JS文件導(dǎo)入其他資源的依賴關(guān)系,這是因?yàn)椋?/p>
邏輯上比較合理:因?yàn)镴S確實(shí)需要這些資源文件配合才能實(shí)現(xiàn)整體功能
配合webapck這類工具的打包:能夠確保在上線時,資源不會缺失,而且都是必要的。
接下來,我們進(jìn)行簡易的loader開發(fā),目標(biāo)是實(shí)現(xiàn)對md文件的打包。
- // index.js
- import mrakdown from "hello.md"
- <!-- hello.md -->
- ## 你好呀
- //md-loader.js
- const md = require("./hello.md")
- module.exports = source => {
- // 加載到的模塊內(nèi)容
- console.log("加載到的模塊內(nèi)容==>",source);
- // 返回值就是最終打包的結(jié)果
- return "你好呀"
- }
- //webpack.config.js
- const path = require("path")
- module.exports = {
- // 樣式文件路徑
- entry:"./src/index.js",
- output:{
- filename:"bundle.js"
- },
- mode:"none",
- module:{
- rules:[{
- test:/\.md$/,//根據(jù)打包過程中所遇文件路徑記性匹配是否使用此loader
- use:"./md-loader"//指定具體使用的loader
- }]
- }
- }
此時執(zhí)行打包命令后報(bào)錯,提示我們加載對應(yīng)的loader。這是因?yàn)榇虬拿總€loader形成一個鏈條,每個loader都依賴于另一個loader的引入,最終打包出來的必須是js文件。對此,我們有處理方法:
- 將我們自定義的md-laoder加載器的輸出設(shè)置為js語法
- 安裝對應(yīng)的loader加載器
- module.exports = source => {
- // 加載到的模塊內(nèi)容
- console.log("加載到的模塊內(nèi)容==>",source);
- // 返回值就是最終打包的結(jié)果
- return "console.log('你好呀')";
- }
那么當(dāng)我們使用合適的Loader加載器將md文件解析為html模塊,需要先進(jìn)行安裝marked,安裝完后在md-loader.js導(dǎo)入模塊,然后進(jìn)行解析。
- $ npm i marked
- //./md-loader.js
- const marked = require("marked")
- module.exports = source => {
- // 1.將md文件轉(zhuǎn)為html字符串
- const html = marked(source);
- return `export default ${JSON.stringify(html)}`
- }
參考文章
《webpack原理與實(shí)踐》
《webpack中文文檔》
寫在最后
loader機(jī)制是webpack核心內(nèi)容,因?yàn)橛辛薼oader機(jī)制webpack才能足以支撐整個前端項(xiàng)目模塊化,實(shí)現(xiàn)通過webpack去加載任何想要的資源。