摘要:另外備注一部分參數的說明折疊有助于文檔樹中文本節點的空白區域對進行壓縮默認默認按照不同文件的依賴關系來排序。敲黑板講重點的當然目前這部分的文檔在官網還不是很全,所以這里我們參考了印記中文的說明文檔,指優化模塊。
鏈接
寫在前面
為什么要自己手寫一個腳手架?
如何去思考遇到的問題?
正文
鏈接原文鏈接
github
whale-vue
——寫在前面在寫這個腳手架之前我也深深的問過自己,在我工作的項目中需要去重新寫一個腳手架嗎?或者說有那么多已經寫好的腳手架為何不采用?
事情的經過是這樣的,在很早很早以前,我嘗試使用過VUE-CLI 2進行過項目開發,當時并不怎么熟悉webpack以及一些打包編譯的相關知識,隨著頁面的增加!項目的體積的增大,導致整體build出來的包非常之大,公共文件也會隨之增大,加載速度也會隨之降低。后續的結果我就不做闡述了!
那么!后來... vue-Cli 3.0誕生了,首次使用簡直是個救世的主,無論從速度還是編譯過程體驗都非常好,而且還可以通過vue.config.js自定義很多的配置,基本上完全可以自定義了,當然!也是隨著頁面的不斷增加核項目的增大,在這個時候。我開始發現我自己對于webpack或者說打包編譯的相關知識已經不能支撐我繼續自定義的開發下去了。發現了一些潛在的問題,但是并沒有實際的解決思路的時候,就可以追述到一些基礎知識的欠缺。
隨著項目的逐漸增大,尤其是多頁應用的支持以及一些文件模塊化的拆分,包括一些tree-shaking的運用。盡管vue-cli3.0支持configureWebpack 這樣強大的API。但是仔細想想,要想從事情的本質或根本上解決問題,首先自身要相對的熟悉,并在此基礎之上運用和操作,得以充分的發揮;所以還是決定自己去了解以便更好的開發。
在項目的開發中,尤其是在寫腳手架這種工具性的東西的時候,需要考慮到的場景和實際運用的時候,更多的是不能沉浸在自己的思維之中,參考并學習別人的經驗是有必要的,從而得出一套符合自己的思路。
從最開始的目錄結構,以及模塊化的一些思考,如何更好的做到性能的優化等等,都是值得思考的問題所在,如何處理好自己的業務邏輯,針對不同的項目以及兼容性的考慮等等。
——正文在此之前我們需要對webpack4的一些文檔或者API進行充分的了解,可以參考官方文檔或者參考印記中文的webpack文檔,但是針對于webpack4的文檔本來介紹的不是很全面,在很多的API上面還是之前的介紹,所以,有很多小伙伴在看文檔的時候發現并不能正常的進行操作,這時候可以結合兩個不同版本的文檔進行研究,當然時間的消耗成本也是比較高的。
在此之前我將控制業務邏輯的代碼進行分離,腳手架是多帶帶存在的。兩者目錄結構相互獨立,業務邏輯的代碼永遠不會干涉到腳手架的
對于一些最基礎的配置我就不一一講述了:
webpack.config.js module.exports = { mode:"development", entry: "./***.js", output: { path: path.resolve(__dirname, "dist"), filename: "[name].js" }, module:{ //... }, plugins:[ //... ] };
以上是一些基本的配置方式,當然我們可以通過package.json文件中的scripts選項自定義一些基于命令行的配置:
package.josn "scripts": { "dev": "APP_ENV=dev webpack-dev-server --config core/dev.js", "prd": "APP_ENV=build webpack --config core/build.js", "build": "APP_ENV=build webpack --config core/build.js", "lint": "eslint --fix */*.vue *.js", "test:whale": "jest tests/*.js && npm run build" },
以上的一些配置僅供參考,分別可以通過npm run dev | npm run prd | ...來進行相關的操作。關于更多的npm script 詳細參考
關于node_modules這塊其實非常的龐大,這也是npm的一個巨大的社區。與其說是學習,不如說是抽一部分優秀的包來使用,要知道一個node_modules包是在做什么事情,可以通過npm搜索包進行瀏覽其詳細介紹,在對應的github地址進行相應的了解。
關于如何學習node_modules包并不在我的介紹范圍內,但是我會介紹一些常用的一些比較好用的包進行分享。而且在構建腳手架之前,必須要對很多的包進行相關的學習,不需要知道每個包的源碼是什么,但是至少需要知道一些包的作用和用法,比如.vue文件需要使用vue-loader進行解析,使用到一些語法校驗的時候需要用到eslint,基于webpack進行生成html頁面的時候需要用到html-webpack-plugin;ES6轉ES5需要用到一系列的@babel/xxx插件,等等..
我這里不做一一的介紹,但是會在后續用到每一個包的時候做相對的介紹即可。
——多入口的輸入和編譯的輸出多入口的輸入相對比較簡單,可以直接參考官方文檔
當然entry可以接受一個對象進行多頁面的輸入,如果只是起步階段建議使用一個入口文件進行編寫,例:
module.exports = { entry: index:"xxx/xxx/index.js" } ////或 module.exports = { mode: isProd ? "production" : "development", entry: { index:"xxx/xxx/index.js" } }
輸出可以根據自己的需要配置output參數:
let path = require("path"); output: { filename: "./js/[name].js", chunkFilename: "./js/[name].js", path: path.resolve(__dirname, "../build/") },
關于module | plugins | optimization | ...等模塊的配置我就不詳細的說了,但是主要還是要說一下各個模塊之間的配合使用。
首先module.noParse是一個必備的參數,可以忽略一下大型的已經構建過的模塊,從而提高構建的性能,這里放一個案例:
webpack.config.js module:{ noParse:/^(vue|vue-router|vuex|vuex-router-sync|lodash|echarts|axios)$/, }
以上的案例忽略了vue | vue-router | vuex | ...等大型額已經構建過的模塊。(通俗易懂的說一下,webpack在打包時會將所有用到的模塊進行打包編譯,在這里只是忽略了重新構建的過程,但是對于chunk的時候依然還是會在內存堆里面使用并打包。)
其實相對來說,在webapck 4的module.rules還是和之前一樣的使用,針對不同的后綴的文件進行不同的處理,在這里主要說一下借助了happypack進行多線程處理,當然你也可以從npm網站詳細了解。與此同時我也選擇放棄使用DllPlugin | DLLReferencePlugin插件,下面我就說一下,如何選擇?為何放棄?
我們都知道webpack在打包編譯時是單線程的運作,但是我們的電腦已經非常強大,單線程的處理,第一是隨著項目的增大時間會增長,第二是有些空閑的cpu等硬件設備得不到充分的利用,這是有我們選擇開啟多線程的操作,在node中是可以開啟多線程的,只是我們借助了happypack這樣的工具來進行多線程的控制和使用,在webpack中,我們可能需要處理到.js文件,也可能會用到.css文件,那么在打包的時候會將所有的字符匯聚到內存中,進行大量的密集型運算,并提取拆分成不同的塊,這時候我們借助多線程來處理即可,使用方法如下:
首先在當前項目中執行命令行npm i happypack -D在開發環境中安裝,引入:
const webpack = require("webpack");
例如我們再處理.js文件時候需要使用cache-loader和babel-loader時,只需要配置:
{ test: /.js$/, use: ["happypack/loader?id=babel" ], exclude: /node_modules/ }
并在plugins選項中配置:
new HappyPack({ id: "babel", cache: true, threads: require("os").cpus().length, //開幾個線程去處理 loaders: [ "cache-loader","babel-loader?cacheDirectory" ] verbose: true, //允許 HappyPack 輸出日志 ,默認true //threadPool: happyThreadPool, })
需要注意的只是rules中調用的HappyPack的id與plugins中實例化的id相同即可。
最后說一下為何要放棄DllPlugin,這個插件是生成一個動態的鏈接文件,也就是你把你認為不需要多次重復編譯的文件通過DllPlugin插件如生成一個.js和.json文件,當你第二次進行打包編譯的時候再通過DllReferencePlugin進行引入使用,這樣就會大大減少了編譯的數量,好處是可以多一些固定的模塊包進行減少處理,但是后來我發現,在項目中只有模塊拆分的足夠細致時候這個確實有不少作用,否則徒增一些步驟,因為每次在拆分塊的時候,很多的模塊是會進行重新組裝的。(以上只是個人觀點,僅供參考~)
如果是在開發環境,我們需要對頁面進行熱更新,我們可以開啟:
plugins:[ new webpack.NamedModulesPlugin(), new webpack.HotModuleReplacementPlugin() ]
NamedModulesPlugin是現實熱更新的模塊的名稱,HotModuleReplacementPlugin啟用HRM官方有介紹。
如果你是使用VUE開發項目,那么new VueLoaderPlugin()是必不可少的了。
注入一些全局變量使用參考:
new webpack.DefinePlugin({ //... }),
重點的說一下html-webpack-plugin這個插件,用于生成過一些頁面的小伙伴應該都有所了解,那么在生成多個頁面的時候,我們就需要new HtmlWebpackPlugin({ ... })多個實例即可,通常情況下,我們會通過循環入口文件進行循環注入一個數組中即可。
另外備注一部分參數的說明:
new HtmlWebpackPlugin({ title: PAGES[k].title || "title", chunks: chunks, filename:`${k}.html`, minify: { removeComments: true, //Strip HTML comments collapseWhitespace: true, //折疊有助于文檔樹中文本節點的空白區域 }, //對html進行壓縮,默認false hash: PAGES[k].hash === true ? true : false, //默認false template: PAGES[k].template, excludeChunks: excludeChunks, favicon:PAGES[k].favicon || "" // chunksSortMode:"dependency" /** * "dependency" 按照不同文件的依賴關系來排序。 * "auto" 默認值,插件的內置的排序方式,具體順序我也不太清楚... * "none" 無序? 不太清楚... * "function" 提供一個函數!!復雜... */ })
上面的代碼只是截取的部分代碼片段,有一些值是需要做一些相應的處理,關于HtmlWebpackPlugin插件的詳細參考
這里需要注意的是,當我們對項目包中的公共代碼做了不同的splitChunks(下面會講解這個模塊)時候,比如像chunks默認會全部注入進入頁面,所以我么你可能需要手動進行一些處理,或者使用excludeChunks對一些塊進行排除,其排除的是你最終生成的代碼文件名稱。template是指對應的模版。更加詳細的參考github 文檔等。
當然目前這部分的文檔在官網還不是很全,所以這里我們參考了印記中文webpack的說明文檔,optimization指優化模塊。splitChunks可以翻譯為拆分塊,默認的配置參數參考官方文檔即可,重要的說一下optimization.splitChunks.cacheGroups,非常強大的一個API,先說什么時候會用到這個功能,這就對應了我們最前面所說的,vue-cli3腳手架不太方便的地方,當項目包逐漸增大的同時,通常情況下,會為我們提供一個公共文件,在vue-cli3腳手架中,為我們提取了 vendor-chunks.js為所有文件的公共文件,但是如果我們有一個場景,其中的某一個頁面根本不需要依賴一些包的,且這個包相對較大的同時,我們另可多發一次請求,也不需要去加載這些多余的文件,我們就可以通過optimization.splitChunks.cacheGroups將這部分公共的提取出來,在對制定的頁面在HtmlWebpackPlugin插件中將它排除即可(或者采用注入指定的chunk的形式),舉一個例子,我們可以吧所有頁面中的vue相關的源碼包提取到一個多帶帶的文件,我們可以采用如下的配置:
optimization: { splitChunks: { minSize: 30000, //緩存組 cacheGroups: { vue: { test: /([/]node_modules[/]vue)/, // <- window | mac -> /node_modules/vue/ name: "vue-vendor", //拆分塊的名稱 chunks: "initial", //initial(初始塊)、async(按需加載塊)、all(全部塊),默認為all; priority: 100, // 該配置項是設置處理的優先級,數值越大越優先處理 enforce: true, // 如果cacheGroup中沒有設置minSize,則據此判斷是否使用上層的minSize,true:則使用0,false:使用上層minSize //minSize: 1024*10, //表示在壓縮前的最小模塊大小,默認為0; //minChunks: 1, //表示被引用次數,默認為1; //maxAsyncRequests: //最大的按需(異步)加載次數,默認為1; //maxInitialRequests: //最大的初始化加載次數,默認為1; //reuseExistingChunk: true //表示可以使用已經存在的塊,即如果滿足條件的塊已經存在就使用已有的,不再創建一個新的塊。 } } }, }
當然你可以根據自己的需要進行多個的配置,名稱可以自定義,test是過濾的方式,這里核心要說明的是priority(優先權),當然是數字越大優先權越高,什么意思,當我們在進行webpack打包的同時,會將我們所有用到的代碼全部加載在內存中,進行進行轉換和編譯等操作,拆分塊的核心在于,將一些公共的模塊拆分成多個模塊,按照優先級進行提取出去,生成一個文件,然后再去查找下一個優先級的進行提取。這里如何進行包拆分可以借助webpack-bundle-analyzer插件進行可視化的進行操作。其用法是直接npm i webpack-bundle-analyzer
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
在webpack中配置plugin選項新增即可:
new BundleAnalyzerPlugin({ defaultSizes:"gzip", logLevel:"warn" }),
在執行項目的時候會進行包依賴的詳細分析,此時我們可以通過可視化的方式進行更好的拆分。
splitChunks也是在webpack4鼎力打造的一個功能,在于理解其中的用法,拆分的代碼塊更多的時候是要我們在html-webpack-plugin的時候更好的生成每一個獨立的頁面,有一些框架中采用了每增加一個文件就回去自動添加一個新的頁面的方式,當然這樣的額缺點是必須按照對應的目錄進行生成對應的頁面,這里我們采用了手動配置的方式生成新的頁面,每生成一個頁面,會默認的注入一些拆分出來的代碼塊。
雖然html-webpack-plugin沒生成一個新的html頁面必須要實例化一個新的對象。所以我們可以通過配置文件的循環進行生成對應的配置:
new HtmlWebpackPlugin({ title: PAGES[k].title || "title", chunks: chunks, filename:`${k}.html`, minify: { removeComments: true, //Strip HTML comments collapseWhitespace: true, //折疊有助于文檔樹中文本節點的空白區域 }, //對html進行壓縮,默認false hash: PAGES[k].hash === true ? true : false, //默認false template: PAGES[k].template, excludeChunks: excludeChunks, favicon:PAGES[k].favicon || "" // chunksSortMode:"dependency" /** * "dependency" 按照不同文件的依賴關系來排序。 * "auto" 默認值,插件的內置的排序方式,具體順序我也不太清楚... * "none" 無序? 不太清楚... * "function" 提供一個函數!!復雜... */ })
上面是一些腳手架中的源代碼,在一些簡單的頁面,可以通過排除的方式省去一些文件的加載,而不是通用的加載一個較大的文件包。在優化的過程中我們可以減少http請求,但是我們也可以減少請求包的大小。
放棄使用DllPlugin | DLLReferencePlugin經過一段時間的考量,我發現關于DllPlugin & DLLReferencePlugin這兩個插件的使用只有在一部分情況下才比較適合,當你的項目包中用一個不需要重新構建的模塊的時候你再使用這個插件是比較合適的,然而很多時候,我們每次的構建幾乎都會重新編譯我們的代碼,當然他們的使用方式是先通過DllPlugin去打包好不不需要重新構建的文件,同時生成manifest.json文件,在下次編譯的同時通過DLLReferencePlugin進行載入即可,減少了一些包的重復編譯。
總結寫在最后,這一塊所包含的信息量相對較多,同時需要對項目構建有一定程度的了解,在很多的過程中是需要去思考一個問題的解決方法和方式,而不僅僅是追求使用,每一個工具都會提供強大的API和功能以適合眾多的業務場景。對于一些通過不同的方式得到同樣結果的問題就仁者見仁吧!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105650.html
摘要:五六月份推薦集合查看最新的請點擊集前端最近很火的框架資源定時更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥雀呼晴,侵曉窺檐語。葉上初陽乾宿雨,水面清圓,一一風荷舉。家住吳門,久作長安旅。五月漁郎相憶否。小楫輕舟,夢入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請::點擊::集web前端最近很火的vue2框架資源;定時更新,歡迎 Star 一下。 蘇...
摘要:五六月份推薦集合查看最新的請點擊集前端最近很火的框架資源定時更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥雀呼晴,侵曉窺檐語。葉上初陽乾宿雨,水面清圓,一一風荷舉。家住吳門,久作長安旅。五月漁郎相憶否。小楫輕舟,夢入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請::點擊::集web前端最近很火的vue2框架資源;定時更新,歡迎 Star 一下。 蘇...
摘要:構建的基于的多頁應用腳手架,本文聊聊本次項目中構建多頁應用的一些心得體會。倉庫構建的舊版多頁應用構建的多頁應用。例如多頁應用中每個的值對應的文件。Webpack構建的基于zepto的多頁應用腳手架,本文聊聊本次項目中Webpack構建多頁應用的一些心得體會。 1.前言 由于公司舊版的腳手架是基于Gulp構建的zepto多頁應用(有興趣可以看看web-mobile-cli),有著不少的痛點。例...
摘要:適用于主要入口頁面生成多頁,子頁面和次要頁面使用單頁形式的項目。文件用來存放固定的數據,而文件可更加自由的處理并返回數據。 VUE2的單頁應用框架有人分享了,多頁應用框架也有人分享了,這里分享一個單頁+多頁的混合應用框架吧,node.js寫了一個簡單的mock服務也集成在里面,整體初現雛形,還有很多需要優化和改善的地方。。。 項目結構 │ ├─build ...
閱讀 2048·2019-08-30 15:52
閱讀 2440·2019-08-29 18:37
閱讀 790·2019-08-29 12:33
閱讀 2839·2019-08-29 11:04
閱讀 1522·2019-08-27 10:57
閱讀 2092·2019-08-26 13:38
閱讀 2759·2019-08-26 12:25
閱讀 2445·2019-08-26 12:23