前言
大概一年前寫了個小小的js外掛 remember-scroll,並且分享了一篇文章:用Class寫一個記住使用者離開位置的js外掛,是一個純js庫,功能是在使用者再次進入頁面時能自動定位到上一次瀏覽的位置,使用webpack+babel打包,裡面的webpack和babel的配置至今看來也算是很典型的。
前端打包工具有很多——webpack
,gulp
,rollup
等等,網上有很多文章分析它們分別更適合哪些場景,webpack
更適合打包元件庫、應用程式之類的應用,而rollup
更適合打包純js的類庫。因此筆者一直有想法嘗試將 remember-scroll 的打包工具由webpack
更換為rollup
,從實際應用的角度來對比一下兩者的區別。
從零配置rollup
- 安裝rollup和一些外掛
npm i rollup rollup-plugin-uglify rollup-plugin-filesize @rollup/plugin-node-resolve @rollup/plugin-commonjs -D
rollup-plugin-uglify
用於壓縮混淆打包後的js。rollup-plugin-filesize
打包後在控制檯顯示檔案大小。@rollup/plugin-node-resolve
讓rollup
能夠識別node_modules的第三方模組。@rollup/plugin-commonjs
將 CommonJS 的模組轉換為 ES2015 供rollup
處理。
- 新增babel
npm i @rollup/plugin-babel @babel/core @babel/plugin-transform-runtime @babel/preset-env core-js@2 -D
@rollup/plugin-babel
rollup 的babel外掛。@babel/core
babel核心。@babel/plugin-transform-runtime
用於避免汙染全域性函式(不是必須要用到,但作為類庫最好要加上)。@babel/preset-env
自動根據目標瀏覽器注入相關的polyfill。core-js
polyfill的類庫,這裡使用的是2.x版本(使用3會增加包的大小)。
根目錄下的babel.config.js
如下:
const presets = [
[
'@babel/env',
{
useBuiltIns: 'usage',
corejs: { version: 2 }
},
],
]
const plugins = [
'@babel/plugin-transform-runtime'
]
module.exports = { presets, plugins }
- 根目錄下新建
rollup.config.js
,全部配置如下:
import filesize from 'rollup-plugin-filesize'
import babel from '@rollup/plugin-babel'
import resolve from '@rollup/plugin-node-resolve'
import { uglify } from 'rollup-plugin-uglify'
import commonjs from '@rollup/plugin-commonjs'
const isProd = process.env.NODE_ENV === 'production'
export default {
input: 'src/index.js',
output: {
file: isProd ? 'dist/remember-scroll.min.js' : 'dist/remember-scroll.js',
format: 'umd',
exports: 'default',
name: 'RememberScroll',
},
plugins: [
resolve(),
commonjs(),
filesize(),
babel({ babelHelpers: 'runtime', exclude: ['node_modules/**'] }),
(isProd && uglify())
]
}
package.json
打包命令如下:
"build": "rollup -c --environment NODE_ENV:production && rollup -c",
"dev": "rollup -c --watch",
總之,一切配置都是與之前webpack
版本的一樣,都使用了babel。npm run build
就可以將資源打包到dist了,接下來我們對比一下webpack
和rollup
兩個工具打出來的體積有啥區別。
webpack和rollup打包體積對比
筆者特地建了一個同時有rollup和webpack打包出來的資源的分支,大家可以直接看下github上feature/webpack_rollup
分支的remember-scroll/dist,對比結果如下:
- | webpack | rollup |
---|---|---|
開發模式大小 | 52.8KB | 19.46KB |
生產打包大小 | 10.3KB | 7.66KB |
生產包gzip後大小 | 4.1KB | 3.4KB |
可見,rollup
打包出來的體積都比webpack
略小一些,通過檢視打包出來的程式碼,webpack打包出來的檔案裡面有很多__webpack_require__
工具函式的定義,可讀性也很差,而rollup打包出來的js會簡單一點。
專案的master分支已經改為使用rollup進行構建,feature/webpack分支保留了之前webpack的配置,感興趣的同學可以去github上詳細瞭解下。
不得不說,從打包體積上來看,使用rollup
構建無疑是更適合的。
package.json的main指向問題
筆者之前遇到過一個問題是package.json
的main
到底應該是指向構建後的開發版本還是生產版本呢?
關於package.json中main欄位的指向問題這篇文章給了答案:main應該指向開發版本。
這裡會有一個疑問:引用開發版本的包體積很大,豈不是讓我的應用打包上線版本很大?
為了驗證上面 package.json 的main
指向開發或生產版本有什麼不同,筆者這裡直接實戰做個對比。
使用VueCli v4.5.9 新建一個vue專案,然後在App.vue
引入不同工具打包而成的remember-scroll
,再npm run build
打包該vue專案,對比打包出來chunk-vendors.[hash].js
的體積。
引入的npm包預設會打包進chunk-vendors
,app.js
的增量體積都是一樣的就不作對比了。
- | vue打包 | webpack開發版(52.8KB) | webpack生產版(10.3KB) | rollup開發版(19.46KB,推薦) | rollup生產版(7.66KB) |
---|---|---|---|---|---|
Size | 89.42 | 134.97 | 99.34 | 97.29 | 96.96 |
Gzip | 32.04 | 40.47 | 34.60 | 34.52 | 34.51 |
可以看到,使用rollup
打包的,無論main指向開發版還是生產版,gzip後幾乎一致,但webpack
打包出來的,main指向開發版時體積會相差非常大。
所以使用webpack
打包的外掛,一般都是會根據NODE_ENV
來載入對應的包,NODE_ENV === 'production'
時指向壓縮後的生產版本。比如像下面這樣,在根目錄新建一個index.js
,package.json
的main
指向該檔案,然後在js中寫上:
if (process.env.NODE_ENV === 'production') {
module.exports = require('./dist/remember-scroll.min.js')
} else {
module.exports = require('./dist/remember-scroll.js')
}
倘若各位以後要寫一個用webpack打包的外掛,要特別注意這一點。
而如果用rollup打包的,其實就不用在意這個細節啦,在這個環節rollup
又比webpack
更香一點哈哈哈。
總結
通過實戰,功能不變且瀏覽器相容性一致的情況下,對remember-scroll這個js庫來說,使用rollup
打包確實比webpack
會更合適一些。所以如果我們以後要做技術選型,對於純js的類庫,選擇使用rollup
會更合適一點。
當然,rollup
和webpack
都是作為構建工具,它們都有著各自的優勢和各自的使用場景,利用好它們的優點就可以了。