摘要:為何有查閱了的文檔,并沒有找到字段的定義,直到才知道它是中最早就提出的概念。況且目前大部分仍是采用,所以便使用了另一個字段。所以目前主流的打包工具都是支持的,鑒于其優(yōu)點,字段很有可能加入的規(guī)范之中。
引入
最近團(tuán)隊的一個同學(xué)在搞 npm library 源碼的調(diào)試插件,因為內(nèi)部的一個組件庫含有大量的邏輯,在某個項目中不經(jīng)意就出現(xiàn)一個磨人的 bug,但是組件庫發(fā)布都是打包編譯后的代碼,而且沒有 publish src 代碼,不方便調(diào)試,每次還要 down 一下包的源碼,再改下 webpack 的配置(比如 rule 中 exclude 去掉組件庫, 改下 resolve ,在 dll 中去掉組件庫)。被他們耳語目染了好幾天,我就想,記得 npm 包是可以直接引源碼的,大概改下 webpack 配置就可以了。然后便找到了 package.json 中 module 字段,并查漏 js 中 tree shaking 的知識,所以我并沒有去研究怎么搞那樣的一個插件?,而是由 package 中的 module 字段延伸出的一些知識。
為何有 module查閱了 package.json 的文檔,并沒有找到 module 字段的定義,直到 google 才知道它是 rollup 中最早就提出的概念 --- pkg.module。大概就是最早的 npm 包都是基于 CommonJS 規(guī)范的,package.json 形如:
"name": "package1", "version": "1.0.0", "main": "lib/index.js"
當(dāng) require("package1") 的時候,就會根據(jù) main 字段去查找入口文件。
而 es2015 后,js 擁有了 ES Module,相較于之前的模塊化方案更爽滑,更優(yōu)雅,并且 ES 模塊也是官方標(biāo)準(zhǔn)(JS 規(guī)范),而 CommonJS 模塊是一種特殊的傳統(tǒng)格式,在 ES 模塊被提出之前做為暫時的解決方案。所以 rollup 去利用 ES Module 構(gòu)建,就可以利用 ES Module 的很多特性,從而提高打包的性能,其中提升一個便是 tree shaking,這個我們后面去介紹。在這個構(gòu)建思想的基礎(chǔ)上,開發(fā)、產(chǎn)出的 npm 包同樣使用 es6 的 module,即可同樣受益于 tree shaking 等特性。
而 CommonJS 規(guī)范的包都是以 main 字段表示入口文件了,如果使用 ES Module 的也用 main 字段,就會對使用者造成困擾,假如他的項目不支持打包構(gòu)建,比如大多數(shù) node 項目(盡管 node9+ 支持 ES Module)。這就是庫開發(fā)者的模塊系統(tǒng)跟項目構(gòu)建的模塊系統(tǒng)的沖突,更像是一種規(guī)范上的問題。況且目前大部分仍是采用 CommonJS,所以 rollup 便使用了另一個字段:module。
像這樣:
"name": "package1", "version": "1.0.0", "main": "lib/index.js", "module": "es/index.js"
webpack 從版本 2 開始也可以識別 pkg.module 字段。打包工具遇到 package1 的時候,如果存在 module 字段,會優(yōu)先使用,如果沒找到對應(yīng)的文件,則會使用 main 字段,并按照 CommonJS 規(guī)范打包。所以目前主流的打包工具(webpack, rollup)都是支持 pkg.module 的,鑒于其優(yōu)點,module 字段很有可能加入 package.json 的規(guī)范之中。另外,越來越多的 npm 包已經(jīng)同時支持兩種模塊,使用者可以根據(jù)情況自行選擇,并且實現(xiàn)也比較簡單,只是模塊導(dǎo)出的方式。
注意:雖然打包工具支持了 ES Module,但是并不意味著其他的 es6 代碼可以正常使用,因為使用者可能并不會對你的 npm 包做編譯處理,比如 webpack rules 中 exclude: /node_modules/,所以如果不是事先約定好后編譯或者沒有兼容性的需求,你仍需要用 babel 處理,從而產(chǎn)出兼容性更好的 npm 包。還好 rollup 在這方面做的不錯,對于 library 開發(fā)者更友好一些。
同時支持的效果類似這樣:
Tree-shaking
tree-shaking 是近兩年才在 JS 中出現(xiàn)的,之前沒有的,而模塊化的概念是一直都有方案的,只不過直到 ES Module 才有統(tǒng)一的標(biāo)準(zhǔn)趨勢。
前面提到 rollup 采用 ES Module,帶來的一個優(yōu)點便是 tree shaking,那什么是 tree-shaking 呢。
有一個圖片很形象的解釋了它的功能。
tree-shaking 的功能就是把我們 JS 中無用的代碼,給去掉,如果把打包工具通過入口文件,產(chǎn)生的依賴樹比作 tree,tree-shaking 就是把依賴樹中用不到的代碼 shaking 掉。
我們通過代碼了解下,webpack3.x 下打包驗證 tree-shaking。
// 入口文件 index.js import { func1 } from "./export1"; func1();
// export1 文件 export function func1() { console.log("func1"); } export function func2() { console.log("func2"); }
func2 方法雖然導(dǎo)出了,但是在 index.js 中是沒有用到的,func2 就是無用代碼,最終打包生成的 build 是應(yīng)該去掉的。
使用最簡單的 webpack 配置,不使用 babel,產(chǎn)出 build.js,export1 是這樣的:
/* 2 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony export (immutable) */ __webpack_exports__["a"] = func1; /* unused harmony export func2 */ function func1() { console.log("func1"); } function func2() { console.log("func2"); } /***/ })
我們發(fā)現(xiàn)有兩行注釋,/* harmony export (immutable) 表明代碼是有用的,unused harmony export func2表明 func2 是無用代碼,說明 webpack 已經(jīng)識別。不過 webpack 僅僅是做了“標(biāo)記”,去掉這些代碼的能力,是通過插件實現(xiàn)的,常用的便是 unglify。在 plugins 用啟用 UglifyJsPlugin 后,查看下 build。
// webpack.config.js const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); module.exports = { ... plugins: [ new UglifyJsPlugin(), ] }
上圖即編譯后 export1 模塊的截圖,可以看到 func2 已經(jīng)被去掉了。不過在我開啟 babel-loader 以后,babel 配置就是一個簡單的 "presets: ["env"]",卻發(fā)現(xiàn) func2 又回來了,如下:
這是為什么呢。因為 tree-shaking 是依賴 ES Module 的靜態(tài)加載,而 babel-presets-env 中是包含 ES2015 modules to CommonJS transform 的 plugin,也就是轉(zhuǎn)化成 CommonJS,所以無法識別哪些代碼是未引用的,也就是無法 tree-shaking,所以 babel transform 的時候應(yīng)該保留 ES Module。
通過 presets 的 option 選擇,設(shè)置 modules 為 false 即可。
另外,tree-shaking 并不是完美無缺的,有些情況還無法識別。比如你導(dǎo)入了一個模塊,但是這個變量代碼中未使用,是不會去掉的,細(xì)節(jié)可以看這篇文章
為什么是 ES ModuleES Module 之前的 JS 實現(xiàn)模塊化,都是基于第三方依賴管理實現(xiàn)的,比如 requirejs,seajs,這都是在代碼執(zhí)行的時候,才知道依賴了哪些模塊,常用的 node 中的 commonjs,也是如此
(function (exports, require, module, __filename, __dirname) { // YOUR CODE INJECTED HERE! });
所以,當(dāng) ES Module 在代碼不執(zhí)行的時候,就可以知道模塊的依賴關(guān)系,就不難理解是為什么了。
思考我的本意是,可否利用 module 字段的特性,讓我的 npm 包支持引入源碼,從而可以實現(xiàn)源碼調(diào)試、并且后編譯的效果,不過從目前的規(guī)范看來,內(nèi)部還是可以試一下的,開源的包最好不要這樣做,除非你有自己的一套規(guī)范以及后編譯生態(tài)。雖然沒有達(dá)到目的,不過也后知后覺的了解到 module 的用意,以及 rollup 在開發(fā)包時候的妙用,以及 tree-shaking 并不是自己了解的那么美好。
相關(guān)推薦你的Tree-Shaking并沒什么卵用
【譯】如何在 Webpack 2 中使用 tree-shaking
手把手帶你走進(jìn)下一代的ES6模塊打包工具—Rollup
原文:https://github.com/configu/bl...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/107674.html
摘要:字段由腳本命令組成的字典,這些命令運行在包的各個生命周期中。在打包過程中,如果遇到字段會優(yōu)先使用字段表示的路徑下的文件,如果不存在,則用字段表示的作為入口,并按照的規(guī)范打包。其中還分析了文件中字段和字段的不同以及和兩個字段的區(qū)別。 所有用npm下載的包或者要上傳至npm的模塊都會有一個package.json文件,這個文件總是存在于模塊(或者包)的根目錄下,這個文件到底是干嘛的,現(xiàn)在就...
摘要:但是,面對辣么多的配置文件,還是從開始自己來吧,畢竟我只想打包一個組件。這里想一下我們的需求,我們想要打包一個組件,使用,根據(jù)上面的說明,不難想到還應(yīng)該需要一個可以用來識別并轉(zhuǎn)換文件,一句話,就是把按下面格式的編寫的組件轉(zhuǎn)換為模塊。 對于vue單文件組件的使用,我們知道使用vue-cli可以快速生成項目結(jié)構(gòu),進(jìn)行.vue單文件組件的編寫,使用 npm run build命令會從main...
摘要:但是,面對辣么多的配置文件,還是從開始自己來吧,畢竟我只想打包一個組件。這里想一下我們的需求,我們想要打包一個組件,使用,根據(jù)上面的說明,不難想到還應(yīng)該需要一個可以用來識別并轉(zhuǎn)換文件,一句話,就是把按下面格式的編寫的組件轉(zhuǎn)換為模塊。 對于vue單文件組件的使用,我們知道使用vue-cli可以快速生成項目結(jié)構(gòu),進(jìn)行.vue單文件組件的編寫,使用 npm run build命令會從main...
摘要:但是,面對辣么多的配置文件,還是從開始自己來吧,畢竟我只想打包一個組件。這里想一下我們的需求,我們想要打包一個組件,使用,根據(jù)上面的說明,不難想到還應(yīng)該需要一個可以用來識別并轉(zhuǎn)換文件,一句話,就是把按下面格式的編寫的組件轉(zhuǎn)換為模塊。 對于vue單文件組件的使用,我們知道使用vue-cli可以快速生成項目結(jié)構(gòu),進(jìn)行.vue單文件組件的編寫,使用 npm run build命令會從main...
摘要:同時虛擬主機管理系統(tǒng)還包含了財務(wù)管理功能功能。隨著互聯(lián)網(wǎng)的發(fā)展和技術(shù)的不斷更新,虛擬主機管理系統(tǒng)的開發(fā)也越來越完善,功能也越來越強大,尤其值得一說的是虛擬主機管理系統(tǒng)更加智能化。點開網(wǎng)頁出現(xiàn)虛擬主機已開通是什么意思?虛擬主機是把一臺服務(wù)器分成很多虛擬的服務(wù)器,每一個虛擬主機都具有獨立的域名和完整的Internet服務(wù)器(支持WWW、FTP、E-mail等)功能。缺點只有一個id,一旦有別的網(wǎng)...
閱讀 1253·2021-11-22 13:54
閱讀 1440·2021-11-22 09:34
閱讀 2717·2021-11-22 09:34
閱讀 4030·2021-10-13 09:39
閱讀 3352·2019-08-26 11:52
閱讀 3373·2019-08-26 11:50
閱讀 1540·2019-08-26 10:56
閱讀 1923·2019-08-26 10:44