Vue 是如何用 Rollup 打包的?

大家好,我是若川。持續組織了6個月源碼共讀活動,感興趣的可以點此加我微信 ruochuan12?參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》?包含20余篇源碼文章。歷史面試系列

Rollup 是一個 JavaScript 模塊打包器,它將小塊的代碼編譯并合并成更大、更復雜的代碼,比如打包一個庫或應用程序。它使用的是 ES Modules 模塊化標準,而不是之前的模塊化方案,如 CommonJS 和 AMD。ES 模塊可以讓你自由、無縫地使用你最喜愛庫中那些最有用的獨立函數,而讓你的項目無需包含其他未使用的代碼。

近期在團隊內組織學習 Rollup 專題,在著重介紹了 Rollup 核心概念和插件的 Hooks 機制后,為了讓小伙伴們能夠深入了解 Rollup 在實際項目中的應用。我們就把目光轉向了優秀的開源項目,之后就選擇了尤大的 Vue/Vite/Vue3 項目,接下來本文將先介紹 Rollup 在 Vue 中的應用。

dev 命令

vue-2.6.14 項目根目錄下的 package.json 文件中,我們可以找到 scripts 字段,在該字段內定義了如何構建 Vue 項目的相關腳本。

{"name":?"vue","version":?"2.6.14","sideEffects":?false,"scripts":?{"dev":?"rollup?-w?-c?scripts/config.js?--environment?TARGET:web-full-dev","dev:cjs":?"rollup?-w?-c?scripts/config.js?--environment?TARGET:web-runtime-cjs-dev",...
}

這里我們以 dev 命令為例,來介紹一下與 rollup 相關的配置項:

  • -c:指定 rollup 打包的配置文件;

  • -w:開啟監聽模式,當文件發生變化的時候,會自動打包;

  • --environment:設置環境變量,設置后可以通過 process.env 對象來獲取已配置的值。

dev 命令可知 rollup 的配置文件是 scripts/config.js

//?scripts/config.js
//?省略大部分代碼
if?(process.env.TARGET)?{module.exports?=?genConfig(process.env.TARGET)
}?else?{exports.getBuild?=?genConfigexports.getAllBuilds?=?()?=>?Object.keys(builds).map(genConfig)
}

觀察以上代碼可知,當 process.env.TARGET 有值的話,就會根據 TARGET 的值動態生成打包配置對象。

//?scripts/config.js
function?genConfig?(name)?{const?opts?=?builds[name]const?config?=?{input:?opts.entry,external:?opts.external,plugins:?[flow(),alias(Object.assign({},?aliases,?opts.alias))].concat(opts.plugins?||?[]),output:?{file:?opts.dest,format:?opts.format,banner:?opts.banner,name:?opts.moduleName?||?'Vue'},onwarn:?(msg,?warn)?=>?{if?(!/Circular/.test(msg))?{warn(msg)}}}//?省略部分代碼return?config
}

genConfig 函數內部,會從 builds 對象中獲取當前目標對應的構建配置對象。當目標為 'web-full-dev' 時,它對應的配置對象如下所示:

//?scripts/config.js
const?builds?={?'web-runtime-cjs-dev':?{?...?},'web-runtime-cjs-prod':?{?...?},//?Runtime+compiler?development?build?(Browser)'web-full-dev':?{entry:?resolve('web/entry-runtime-with-compiler.js'),dest:?resolve('dist/vue.js'),format:?'umd',env:?'development',alias:?{?he:?'./entity-decoder'?},banner},
}

在每個構建配置對象中,會定義 entry(入口文件)、dest (輸出文件)、format(輸出格式)等信息。當獲取構建配置對象后,就根據 rollup 的要求生成對應的配置對象。

需要注意的是,在 Vue 項目的根目錄中是沒有 web 目錄的,該項目的目錄結構如下所示:

├──?BACKERS.md
├──?LICENSE
├──?README.md
├──?benchmarks
├──?dist
├──?examples
├──?flow
├──?package.json
├──?packages
├──?scripts
├──?src
├──?test
├──?types
└──?yarn.lock

那么 web/entry-runtime-with-compiler.js 入口文件的位置在哪呢?其實是利用了 rollup 的 @rollup/plugin-alias 插件為地址取了個別名。具體的映射規則被定義在 scripts/alias.js 文件中:

//?scripts/alias.js
const?path?=?require('path')
const?resolve?=?p?=>?path.resolve(__dirname,?'../',?p)module.exports?=?{vue:?resolve('src/platforms/web/entry-runtime-with-compiler'),compiler:?resolve('src/compiler'),core:?resolve('src/core'),shared:?resolve('src/shared'),web:?resolve('src/platforms/web'),weex:?resolve('src/platforms/weex'),server:?resolve('src/server'),sfc:?resolve('src/sfc')
}

根據以上的映射規則,我們可以定位到 web 別名對應的路徑,該路徑對應的文件結構如下:

├──?compiler
├──?entry-compiler.js
├──?entry-runtime-with-compiler.js
├──?entry-runtime.js
├──?entry-server-basic-renderer.js
├──?entry-server-renderer.js
├──?runtime
├──?server
└──?util

到這里結合前面介紹的 builds 對象,相信你也知道了 Vue 是如何打包不同類型的文件,以滿足不同場景的需求,比如含有編譯器和不包含編譯器的版本。分析完 dev 命令的處理流程,下面我來分析 build 命令。

build 命令

同樣,在根目錄下 package.jsonscripts 字段,我們可以找到 build 命令的定義:

{"name":?"vue","version":?"2.6.14","sideEffects":?false,"scripts":?{"build":?"node?scripts/build.js",...
}

當你運行 build 命令時,會使用 node 應用程序執行 scripts/build.js 文件:

//?scripts/build.js
let?builds?=?require('./config').getAllBuilds()//?filter?builds?via?command?line?arg
if?(process.argv[2])?{const?filters?=?process.argv[2].split(',')builds?=?builds.filter(b?=>?{return?filters.some(f?=>?b.output.file.indexOf(f)?>?-1?||?b._name.indexOf(f)?>?-1)})
}?else?{//?filter?out?weex?builds?by?defaultbuilds?=?builds.filter(b?=>?{return?b.output.file.indexOf('weex')?===?-1})
}build(builds)

scripts/build.js 文件中,會先獲取所有的構建目標,然后根據進行過濾操作,最后再調用 build 函數進行構建操作,該函數的處理邏輯也很簡單,就是遍歷構建列表,然后調用 buildEntry 函數執行構建操作。

//?scripts/build.js
function?build?(builds)?{let?built?=?0const?total?=?builds.lengthconst?next?=?()?=>?{buildEntry(builds[built]).then(()?=>?{built++if?(built?<?total)?{next()}}).catch(logError)}next()
}

next 函數執行時,就會開始調用 buildEntry 函數,在該函數內部就是根據傳入了配置對象調用 rollup.rollup API 進行構建操作:

//?scripts/build.js
function?buildEntry?(config)?{const?output?=?config.outputconst?{?file,?banner?}?=?outputconst?isProd?=?/(min|prod)\.js$/.test(file)return?rollup.rollup(config).then(bundle?=>?bundle.generate(output)).then(({?output:?[{?code?}]?})?=>?{if?(isProd)?{?//?若為正式環境,則進行壓縮操作const?minified?=?(banner???banner?+?'\n'?:?'')?+?terser.minify(code,?{toplevel:?true,output:?{ascii_only:?true},compress:?{pure_funcs:?['makeMap']}}).codereturn?write(file,?minified,?true)}?else?{return?write(file,?code)}})
}

當打包完成后,下一個環節就是生成文件。在 buildEntry 函數中是通過調用 write 函數來生成文件:

//?scripts/build.js
const?fs?=?require('fs')function?write?(dest,?code,?zip)?{return?new?Promise((resolve,?reject)?=>?{function?report?(extra)?{console.log(blue(path.relative(process.cwd(),?dest))?+?'?'?+?getSize(code)?+?(extra?||?''))resolve()}fs.writeFile(dest,?code,?err?=>?{if?(err)?return?reject(err)if?(zip)?{zlib.gzip(code,?(err,?zipped)?=>?{if?(err)?return?reject(err)report('?(gzipped:?'?+?getSize(zipped)?+?')')})}?else?{report()}})})
}

write 函數內部是通過 fs.writeFile 函數來生成文件,該函數還支持 zip 參數,用于輸出經過 gzip 壓縮后的大小。現在我們已經分析完了 devbuild 命令,最后我們來簡單介紹一下構建過程中所使用的一些核心插件。

rollup 插件

package.json ?文件中,我們可以看到 Vue2 項目中用到的 rollup 插件:

//?package.json
{"name":?"vue","version":?"2.6.14","devDependencies":?{"rollup-plugin-alias":?"^1.3.1","rollup-plugin-buble":?"^0.19.6","rollup-plugin-commonjs":?"^9.2.0","rollup-plugin-flow-no-whitespace":?"^1.0.0","rollup-plugin-node-resolve":?"^4.0.0","rollup-plugin-replace":?"^2.0.0",}
}

其中,"rollup-plugin-alias" 插件在前面我們已經知道它的作用了。而其他插件的作用如下:

  • rollup-plugin-buble:該插件使用 buble 轉換 ES2015 代碼,它已經被移到新的倉庫 @rollup/plugin-buble;

  • rollup-plugin-commonjs:該插件用于把 CommonJS 模塊轉換為 ES6 Modules,它已經移到新的倉庫 @rollup/plugin-commonjs;

  • rollup-plugin-flow-no-whitespace:該插件用于移除 flow types 中的空格;

  • rollup-plugin-node-resolve:該插件用于支持使用 node_modules 中第三方模塊,會使用 Node 模塊解析算法來定位模塊。它也被移動到新的倉庫 @rollup/plugin-node-resolve;

  • rollup-plugin-replace:該插件用于在打包時執行字符串替換操作,它也被移動到新的倉庫 @rollup/plugin-replace。

除了以上的插件,在實際的項目中,你也可以使用 Rollup 官方倉庫提供的插件,來實現對應的功能,具體如下圖所示(僅包含部分插件):

808699bed864f97943944f3a0e07bd2b.png

(來源:https://github.com/rollup/plugins)

總結

本文只是簡單介紹了 Rollup 在 Vue 2 中的應用,很多細節并沒有展開介紹,感興趣的小伙伴可以自行學習一下。如果遇到問題的話,歡迎跟我一起交流哈。另外,你們也可以自行分析一下在 Vue 3 和 Vite 項目中是如何利用 Rollup 進行打包的。

5a0e6320b2947bf8ff36b5c1d12401a1.gif

·················?若川簡介?·················

你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助3000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。

6ac5979d7284a04ccba0b423324d4ff9.png

識別方二維碼加我微信、拉你進源碼共讀

今日話題

略。分享、收藏、點贊、在看我的文章就是對我最大的支持~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/274893.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/274893.shtml
英文地址,請注明出處:http://en.pswp.cn/news/274893.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

leetcode 207課程表

class Solution { public:bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {//驗證是否為DAG&#xff0c;每次驗證指向的是否已經存在于當前圖中//建圖vector<int> indegree(numCourses,0);//入度vector<vector<int>> …

2012-04-12

一.JS 中的return Return false&#xff1a;相當于一個終止符,用來阻止提交表單或繼續執行下面的代碼&#xff0c;只在當前函數有效&#xff0c;不會影響其他外部函數的執行 Eg: function a(){if(true) return false;} Function test{a();b();c();} //a方法中的return false 不…

sketch怎么傳到ps_2020年從Sketch移植到Figma的詳細指南

sketch怎么傳到psAs we’re locked up in our homes due to COVID-19 pandemic, many of us are working remotely and Figma is a go-to tool for designers for the same.由于COVID-19流行病使我們被關在家里&#xff0c;我們中的許多人都在遠程工作&#xff0c;而Figma是設計…

還沒搭建過Vue3.x項目?幾行代碼搞定~

大家好&#xff0c;我是若川。持續組織了6個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列相信現…

mysql 常用命令 匯總

參考閱讀 摘要 權限 允許公網訪問列操作 修改列名mysql 修改列屬性其他 登錄設置自動補全與utf-8編碼其他一次添加多條記錄修改表名字允許公網訪問 1,修改表,登錄mysql數據庫,切換到mysql數據庫,使用sql語句查看"select host,user from user ;" mysql -u root -pvmwa…

一步步創建 邊欄 Gadget(二)

相信使用上篇中創建的邊欄Gadget之后&#xff0c;大家會很郁悶。難道視頻窗口就那么小嗎&#xff1f;看起來真費勁。我能通過該Gadget看著一部電視劇。而不能夠定制自己需要的或者想要看的電視劇。 在上一篇一步步創建 邊欄 Gadget&#xff08;一&#xff09;中&#xff0c;我們…

tableau 自定義圖表_一種新的十六進制美國地圖布局的案例-Tableau中的自定義圖表

tableau 自定義圖表For whatever reason, 無論出于什么原因 maps are cool. Even though the earth has mostly been the same since those 地圖很酷 。 即使自Pangaea days, we humans make and remake maps constantly. It might be that old maps remind us of how things …

2022,前端工具鏈十年盤點

大家好&#xff0c;我是若川。持續組織了6個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列2021 …

var result = ![] == []; console.log(result); // 結果是?為什么?

相等操作符會對操作值進行隱式轉換后進行比較&#xff0c;如果一個操作值為布爾值&#xff0c;則在比較之前先將其轉換為數值&#xff0c;這里 ![] 一定是布爾值了。 http://www.csser.com/board/4f3f516e38a5ebc9780004d3轉載于:https://www.cnblogs.com/anjey/archive/2012/0…

講講volatile的作用

講講volatile的作用 講講volatile的作用254推薦一個定義為volatile的變量是說這變量可能會被意想不到地改變&#xff0c;這樣&#xff0c;編譯器就不會去假設這個變量的值了。精確地說就是&#xff0c;優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值&#xff0c;…

書籍排版學習心得_為什么排版是您可以學習的最佳技能

書籍排版學習心得重點 (Top highlight)I was introduced to design in a serpentine fashion. I don’t have any formal training. Instead, I’ve learned everything through the Web, books, and by interacting with designers daily.我被介紹為蛇形設計。 我沒有任何正規…

javascript專題:如何構建自己的js庫

首先看看這個&#xff1a; (function(){ //運行的代碼 })(); 紅色括號里面是一個匿名函數&#xff0c;紅色括號是分割&#xff0c;表示里面的函數是一個部分&#xff0c;綠色的括號表示一個運算符&#xff0c;表示紅色括號里面的函數要運行。 相當于定義完一個匿名函數后讓它直…

若川的 2021 年度總結,彈指之間

1前言從2014年開始&#xff0c;每一年都會寫年度總結&#xff0c;已經堅持了7個年頭。7年的光陰就是彈指之間&#xff0c;轉瞬即逝。正如孔子所說&#xff1a;逝者如斯夫&#xff0c;不舍晝夜。回顧2014&#xff0c;約定2015&#xff08;QQ空間日志&#xff09;2015年總結&…

線框圖用什么軟件_為什么要在線框中著色?

線框圖用什么軟件I was recently involved in a debate around why some wireframes (which were definitely not UI screens) were not 100% greyscale. This got me thinking — when is it ok to use colour in wireframes, and when is it going to cause you problems fur…

Linux 內核

Linux 內核是一個龐大而復雜的操作系統的核心&#xff0c;不過盡管龐大&#xff0c;但是卻采用子系統和分層的概念很好地進行了組織。通過本專題&#xff0c;我們可以學習 Linux 的分層架構、內核配置和編譯、內核性能調試和 Linux 2.6 中的許多提升功能。Linux 內核組成 Linux…

給asterisk寫app供CLI調用

環境&#xff1a;CentOS6.2 Asterisk 1.8.7.1 一、添加源文件 復制app_verbose.c為app_testApp.c 復制app_verbose.exports為app_testApp.exports 主要是修改一些標識&#xff0c;編譯不會出錯就行&#xff0c;這里列出我進行的主要修改。 1、添加頭文件 #include "aster…

前端,校招,面淘寶,指南

大家好&#xff0c;我是若川。持續組織了6個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列雖然是…

qq空間網頁設計_網頁設計中負空間的有效利用

qq空間網頁設計Written by Alan Smith由艾倫史密斯 ( Alan Smith)撰寫 Negative space is a key design element that you may come across in the fields of art, architecture, interior design, landscaping and web design. Rather than serving as awkward, empty areas …

自定義異常拋法

public List<LogRec> readLogs() throws ReadDataException { try { return returnLogRec(logFileName); } catch(Exception e) { throw new ReadDataException(e); } } 轉載于:https://www.cnblogs.com/zengmiaogen/archive/2012/04/15/2450438.html

SQL SERVER服務停止和啟動命令行

停止服務: net stop mssqlserver 啟動服務: net start mssqlserver 轉載于:https://www.cnblogs.com/davidgu/archive/2010/01/06/1640466.html