摘要:根據依賴關系,按照配置文件把模塊函數分組打包成若干個。會隨著自身的的修改,而發生變化。只需要在命令行運行時帶上參數就搞定一些插件的廢除和替換廢棄了頂替者用屬性變化壓縮優化代碼分割,下面詳解還有一些新的插件,。
1. 前端工程化項目打包歷史
前端工程化之前的時代略過
自從xmlhttprequest被挖掘出來,網頁能夠和服務端通訊,js能做的事越來越多,文件體積越來越大,互相引用原來越多。
然而網速只有幾兆的帶寬。于是想到,要把js文件狠狠的壓縮,能合并的就給合并起來
主要有的js壓縮工具:
JSMin 使用簡單、靈活,對不同語言、環境支持好。一般配合不同的環境、語言用命令行執行壓縮
YUI Compressor 雅虎推出。有JAVA版本和.NET版本,需兩者環境配合
UglifyJS 基于nodejs,壓縮策略較為安全,所以不會對源代碼進行大幅度的改造。
Closure Compiler 谷歌出品
在我理解,壓縮主要做了局部變量命名簡化、空格/換行/注釋消除、自動優化可簡化的語法等工作。
使用壓縮工具用es6語法寫的js在壓縮測試比較中:
UglifyJS壓縮率高,可以自動格式化、優化代碼。所以普及率高。現在也是主流的工具
YUI compressor 好處就是壓縮策略安全,相比UglifyJS,自動優化代碼的程度較保守
Closure Compiler 的Advanced模式直接破壞代碼的結構,bug多
壓縮有了,但是當a文件和b文件都引用了c文件的方法時,如果把c文件分別和a、b合并,這樣就只有兩個文件了。這就是最開始的合并方式。
一般是通過在windows上用bat腳本或者mac/linux上的shell腳本來決定合并哪些文件、用什么工具壓縮、怎么壓縮
進步:
解決當時網速普遍較慢的情況下網頁加載資源較慢的問題
代碼混淆了不容易被盜用
存在的問題:
工程化的項目里相互依賴關系變得非常復雜
合并的文件里可能會有很多無用代碼
2. 自動構建的嘗試階段通過腳本構建的項目里的文件相互依賴復雜,命名什么的完全有可能一不小心就沖突了,而且依賴可能是一層一層依賴下去的,維護起來要命呀。
所以先解決js相互依賴的問題
CommonJS規范解決了js模塊化依賴的問題
一個文件就是一個模塊
每個模塊內部,都有一個module對象,代表當前模塊,有規定好的一些默認屬性
module.exports屬性:初始值是一個空對象{},這個變量把定義的變量、方法暴露出去
exports變量:Node為每個模塊提供一個exports變量,指向module.exports。至于兩者的區別,不用去了解,平常就用module.exports
require引用:把module.exports定義的變量/方法來過來用
注意:它是同步的
既然CommonJS提供了模塊化的思路,也已經在服務端(nodejs)里大展手腳。那么瀏覽器里可不可行?
瀏覽器不兼容CommonJS的原因首先是,缺少了4個NodeJs環境變量:
module
exports
require
global
那么只需要提供了這些個環境變量就行了吧。Browerify就是做這的
Browserify 是目前最常用的 CommonJS 格式轉換的工具
Browserify的核心思路是講module暴露出的模塊放入一個數組,require時根據模塊id找到相應的module執行,總之就是給上面缺少的變量寫成可執行的es5的策略
那么是不是這樣就能在瀏覽器上愉快使用CommonJS?
CommoJS是同步require的方式獲取js模塊,在瀏覽器上會阻斷主線程。頁面會因加載js可能卡住
這肯定是不能容忍的
于是AMD(異步模塊定義)誕生
AMD也采用require()語句加載模塊,但是要傳兩個參數require([module], callback)。是的,回調思路。
解決兩個問題:
(1)實現js文件的異步加載,避免網頁失去響應
(2)管理模塊之間的依賴性,便于代碼的編寫和維護
模塊必須采用特定的define()函數來定義
非AMD的第三方庫加載之前要用require.config()定義固有特征
CMD規范 和AMD大同小異,具體實現是seajs。沒用過,應該都差不多吧,啊哈哈
2. html/css模塊化的規范less,sass,stylus 的 css 預處理器簡化css語法
ejs,jade 等html的模板語法
這些真的是前端狗的福音,不多說,css-next來了,繼續啃咯。
這樣html/css/js 就都有了適合自動構建的擴展結構。但是這時候寫一個構建這些依賴的命令太長太復雜,所以打包工具開始流行:
3.Grunt/Gulp 流處理構建工具讓前端構建更容易grunt 寫法簡單,插件還賊多
gulp 效率更高,可擴展性更強
nodejs配合這倆大佬做web項目的自動化構建用著都挺爽的
var gulp = require("gulp") var nodemon = require("gulp-nodemon") var browserSync = require("browser-sync").create() gulp.task("nodemon", function(cb) { var started = false return nodemon({ script: "mswadmin.js" , ext: "js" , env: { "NODE_ENV": "default" } }).on("start", function() { if (!started) { cb(); started = true; } }) }); gulp.task("serve", function(){ browserSync.init({ proxy: "http://10.3.10.27:18282", browser: "chrome", port: 18282 }) gulp.watch("static/**/*.+(scss|jade|ls)", ["inject"]) .on("change", browserSync.reload); }) gulp.task("default", ["nodemon","serve"]);
上面是一個用nodemon監控本地服務+watch代碼熱更新的配置。可以看出,以流任務的方式一個個執行。用起來也簡單
2. SPA(Single-page application)來了js 對應的 AMD 模塊,然后該 AMD 模塊渲染對應的 html 到容器內
這樣網頁不再是傳統的文檔一類的頁面了。而是更像一個完整的程序。一個主入口,js完成的前端路由,AMD模塊完成頁面內重新渲染。
雖然是做出來這個SPA了,但是小問題多:
很多成熟的第三方庫不支持AMD規范,引用起來賊麻煩
RequireJS在加載html依賴時,html里的img路徑要使用絕對路徑
只能一次性加載所有css文件
分模塊打包js文件時的通用依賴項很難配置
最重要的,AMD/CMD CommonJS規范太多造成很多第三方庫對規范支出不夠。。。而且ES6規范都要普及了,你不用???
3. webpack來解救你首先,webpack是靜態模塊打包器(bundler),grunt/gulp是流任務執行器。
區分兩者可以用grunt-webpack形象說明:你可以將 webpack 或 webpack-dev-server 作為一項任務(task)執行
webpack 能夠為ES6的 import/export 提供開箱即用般的支持
還支持CommonJS CMD/AMD模塊規范,做到隨時可用
這兩點是我覺得最突出的地方,詳細對比請參考對比
瀏覽器環境下,用了ES6規范的話,你應該不想用其他的了
webpack的工作步驟如下:從入口文件開始遞歸地建立一個依賴關系圖。
把所有文件都轉化成模塊函數。
根據依賴關系,按照配置文件把模塊函數分組打包成若干個bundle。
通過script標簽把打包的bundle注入到html中,通過manifest文件來管理bundle文件的運行和加載。
打包的規則為:一個入口文件對應一個bundle。該bundle包括入口文件模塊和其依賴的模塊。按需加載的模塊或需多帶帶加載的模塊則分開打包成其他的bundle。
除了這些bundle外,還有一個特別重要的bundle,就是manifest.bundle.js文件,即webpackBootstrap。這個manifest文件是最先加載的,負責解析webpack打包的其他bundle文件,使其按要求進行加載和執行。
無論你選擇哪種模塊語法,那些 import 或 require 語句現在都已經轉換為 webpack_require 方法,此方法指向模塊標識符(module identifier)。通過使用 manifest 中的數據,runtime 將能夠查詢模塊標識符,檢索出背后對應的模塊。
雖然網上有很多 十分鐘入門webpack 的教程。但還是推薦去擼一遍webpack官方指南
個人覺得指南里你要注意的細節:
4. webpack的優化點的補充說明webpack 不會更改代碼中除 import 和 export 語句以外的部分。如果你在使用其它 ES2015 特性,請確保你在 webpack 的 loader 系統中使用了一個像是 Babel 或 Bublé 的轉譯器
npm腳本運行時默認可以使用npx命令
source map要合理使用
留意webpack-dev-middleware,配合express做服務端渲染要用到哦
HMR(模塊熱替代)一般用你選用的框架自帶的loader(vue-loader)
用UglifyJsPlugin插件自動移除 JavaScript 上下文中的未引用代碼(dead-code)。webpack4里使用 mode=production 替代。要結合SideEffects使用,webpack4又提供了SideEffects插件使用的方式
process.env.NODE_ENV === "production" ? "[name].[hash].bundle.js" : "[name].bundle.js" 這樣的條件語句在配置文件里無法使用,用if/else
splitChunks優化,webpack4已經移除了CommonsChunkPlugin。下文會詳細解釋
dynamic imports(動態導入)優化,chunkFilename決定非入口 chunk 的名稱,vue里的運用實例就是路由懶加載(vue-lazyload),生成了新的bundle
動態導入在vue里的時間注意點:
webpack 可以使用dynamic imports的方式引用模塊,我們使用 async/ await 和 dynamic import 來實現。每一個dynamic import都將作為一個多帶帶的chunk打包。在vue中的一個例子就是路由懶加載+babel-plugin-dynamic-import-node的構建方案。使用babel-plugin-dynamic-import-node是因為開發環境下觸發熱更新很慢,這個插件講import異步全部改成require同步
打包生成的文件模塊標識符的問題
一般來說我們在dist生成了一下三種bundle
main bundle 會隨著自身的新增內容的修改,而發生變化。
vendor bundle 會隨著自身的 module.id 的修改,而發生變化。
manifest bundle 會因為當前包含一個新模塊的引用,而發生變化。
然而我們并不希望vendor每次構建都生成新的hash,畢竟我們希望用到緩存的。解決方法官方有兩個插件NamedModulesPlugin和HashedModuleIdsPlugin
vue里使用的是HashedModuleIdsPlugin
相信很多人從webpack3升級到4會碰到問題,接下來
### 5. 升級到webpack4你該搞明白
主要使用了模式的概念。
development 模式下,默認開啟了NamedChunksPlugin 和NamedModulesPlugin方便調試,提供了更完整的錯誤信息,更快的重新編譯的速度
production 模式下,由于提供了splitChunks和minimizer,所以基本零配置,代碼就會自動分割、壓縮、優化,同時 webpack 也會自動幫你 Scope hoisting(作用域提升) 和 Tree-shaking
相當于把一些基本的配置當成默認配置。只需要在命令行運行時帶上mode參數就搞定
#### 2. 一些插件的廢除和替換
廢棄了 | 頂替者(用optimization屬性) | 變化 |
---|---|---|
uglifyjs-webpack-plugin | minimizer | 壓縮優化 |
CommonsChunkPlugin | splitChunks | 代碼分割,下面詳解 |
還有一些新的插件:Tree Shaking,SideEffects。我還不知道怎么用--
3. 要注意的新的優化點extract-text-webpack-plugin -> mini-css-extract-plugin
它與extract-text-webpack-plugin最大的區別是:它在code spliting的時候會將原先內聯寫在每一個 js chunk bundle的 css,多帶帶拆成了一個個 css 文件。js變得更干凈了,css是根據optimization.splitChunks的配置自動拆分css文件為多帶帶的模塊的規則拆分的,不用擔心過多的httlp資源請求問題
所有的[chunkhash] ->[contenthash]
這是為了解決當css與js文件有依賴時,兩者有相同的chunkhash。這樣js修改了,css沒改的情況下chunkhash頁被修改了,沒法緩存了呀
contenthash 你可以簡單理解為是 moduleId + content 所生成的 hash
相關issue
代碼的壓縮優化改成了optimization.minimizer
在optimization.minimizer里推薦使用optimize-css-assets-webpack-plugin直接配置。但是vue-cli3里的配置自己配的。嗯...反正也不想看那些配置,就這樣吧~~~
4. 第三方庫和業務代碼分開打包策略上面多處提到了這個optimization.splitChunks
Webpack 4 最大的改進便是Code Splitting chunk。webpack3是通過CommonsChunkPlugin拆分的。然后現在直接被廢棄了,我能怎么辦?,跟著學唄。
開啟Code Splitting很簡單,使用production的mode就行,會自動開啟。并有一個設置好了的一個很合理的配置
如果同時滿足下列條件,chunk 就會被拆分:
新的 chunk 能被復用,或者模塊是來自 node_modules 目錄
新的 chunk 大于 30Kb(min+gz 壓縮前)
按需加載 chunk 的并發請求數量小于等于 5 個
頁面初始加載時的并發請求數量小于等于 3 個
默認配置已經很合理了,然而當出現如下情況:
已vue-cli創建的項目為例。項目用到了第三方的UI組件庫,在main.js入口處依賴了第三方庫。
因為在入口引入了,所以第三方庫會被打包進app.js。這樣,只要我修改了app.js里的其他代碼,打出來的包的hash就變了。瀏覽器又得再次緩存app.js。第三庫相當于又被緩存了一次,這顯然不是我們想要的。
看一下花褲衩的配置
splitChunks: { chunks: "all", cacheGroups: { libs: { name: "chunk-libs", test: /[/]node_modules[/]/, priority: 10, chunks: "initial" // 只打包初始時依賴的第三方 }, elementUI: { name: "chunk-elementUI", // 多帶帶將 elementUI 拆包 priority: 20, // 權重要大于 libs 和 app 不然會被打包進 libs 或者 app test: /[/]node_modules[/]element-ui[/]/ }, commons: { name: "chunk-commons", test: resolve("src/components"), // 可自定義拓展你的規則 minChunks: 2, // 最小共用次數 priority: 5, reuseExistingChunk: true } } };
主要思路就是
把初始化時依賴的第三方打包成基礎類庫,這一類改動小,又被全局需要
把類似elementUI這一類的比較大、改動較小的抽出來
全局公用的router、函數、svg圖標、layout布局組件等這些不管,直接扔app.js
業務里會經常使用但沒在main.js引入的的components被打包成一個common
業務里經常使用但是體積相當較小,就直接在main.js引入,打包進app.js
其他的低頻使用的組件會自動按默認splitChunks的設置來拆分
提醒: 代碼的拆分一定要結合項目的實際情況,比如你就用到element里的一兩個組件,完全可以按需加載在main.js,然后直接打包進app.js。所以沒有最合理的拆分規則,只有最適合你的。
5. Prefetching/Preloading modules支持了Prefetching/Preloading瀏覽器資源加載優化
核心思想是減少JS下載時間
學不動了學不動了,先緩緩
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98390.html
摘要:根據依賴關系,按照配置文件把模塊函數分組打包成若干個。會隨著自身的的修改,而發生變化。只需要在命令行運行時帶上參數就搞定一些插件的廢除和替換廢棄了頂替者用屬性變化壓縮優化代碼分割,下面詳解還有一些新的插件,。 1. 前端工程化項目打包歷史 前端工程化之前的時代略過 1. 半自動執行腳本來壓縮合并文件 自從xmlhttprequest被挖掘出來,網頁能夠和服務端通訊,js能做的事越來越多...
摘要:哈哈,我理解,架構就是骨架,如下圖所示譯年月個有趣的和庫前端掘金我們創辦的使命是讓你及時的了解開發中最新最酷的趨勢。 翻譯 | 上手 Webpack ? 這篇就夠了! - 掘金譯者:小 boy (滬江前端開發工程師) 本文原創,轉載請注明作者及出處。 原文地址:https://www.smashingmagazine.... JavaSrip... 讀 Zepto 源碼之代碼結構 - ...
摘要:一個用打包的的項目,參照的配置,一步一步帶你實現一個的打包的項目,每一個對應一個步驟。如下注釋模板生產環境的開啟靜態文件的壓縮如果是的話需要打包完成顯示包大小的狀態分析運行或者就可以實現打包項目啦。 一個用webpack4打包的vue 的項目,參照vue-cli的webpack配置, 一步一步帶你實現一個vue的打包的項目,每一個commit對應一個步驟。 github 地址 clon...
摘要:詳細具體的使用可以見文章手摸手,帶你優雅的使用。為了加速線上鏡像構建的速度,我們利用源進行加速并且將一些常見的依賴打入了基礎鏡像,避免每次都需要重新下載。 完整項目地址:vue-element-admin系類文章二:手摸手,帶你用vue擼后臺 系列二(登錄權限篇)系類文章三:手摸手,帶你用vue擼后臺 系列三(實戰篇)系類文章四:手摸手,帶你用vue擼后臺 系列四(vueAdmin 一...
閱讀 665·2021-11-15 11:37
閱讀 4105·2021-09-09 09:34
閱讀 3558·2019-08-30 15:52
閱讀 2601·2019-08-29 14:03
閱讀 2841·2019-08-26 13:36
閱讀 1586·2019-08-26 12:16
閱讀 1592·2019-08-26 11:45
閱讀 3487·2019-08-23 18:41