rollup是什么呢?
我们前端打包用的最多的就是webpack,因为webapck生态太丰富了,给我们提供了大量的loader以及plugin,帮助我们完成代码压缩,热更新,代码分割,server服务,sourceMap,打包分析,treeShaking等功能;
现在的vue3版本使用vite来打包,那么vite是什么呢,以及与webpack的区别是什么呢?我们我们下篇文章记录学习。vite是下一代前端开发与构建工具,其中生产环境的打包用的就是rollup来打包的,接下来我们来详细的学习rollup
Rollup是JavaScript的模块绑定器,它将小段代码编译成更大更复杂的代码,比如库或应用程序。它使用了JavaScript ES6修订版中包含的新的标准化代码模块格式,而不是以前的特殊解决方案,如CommonJS和AMD。
一:安装:可以分为两种方式来进行安装
全局安装: npm i rollup -g
本地项目安装: npm i rollup -D(–save-dev 的简写 开发环境的依赖)
新建rollup-demo文件夹:
- npm init -y 在项目根目录初始化package.json文件
- npm i rollup -D 本地安装rollup包
二:简单的启动打包,不用配置文件,推荐使用配置文件rollup.config.js来配置
在根目录新建main.js代码如下:
const a='hello rollup'
console.log(a)
在终端执行 rollup main.js --file bundle.js --format iife 命令之后,会在根目录生成一个bundle.js打包后的文件
注意点:
自己操作后发现执行上面命令后,会报错,原因是rollup也必须要全局安装才可以npm i rollup -g
bundle.js代码如下: 因为我们上面命令指定生成的是iife,立即执行函数的模式,可以自己指定
(function () {
'use strict';
const a='hello rollup';
console.log(a);
})();
比如:我们指定生成commonjs模块的命令:rollup main.js --file bundle.js --format cjs
三:那么rollup可以将文件编译成几种模式呢?我们来学习下:
rollup可以将文件编译成amd
, cjs
, esm
, iife
, umd
, system
六种模式,这几种模式代表着不同的使用规则和场景,我们简单来学习下:
1. cjs commonjs的简写 只能使用在node.js的模块,运行时加载的,需要require引入 module.exports导出,是同步运行的代码
2. esm esModule的简写 静态化,编译时加载,采用import/export语法,主流浏览器都支持
3. amd 采用异步方式加载模块,模块的加载不影响它后面语句的运行,主要是解决各个模块之间的依赖关系
4. umd 是集结了 CommonJs、CMD、AMD 的规范于一身,判断是谁的规范就使用谁的规范,他的最外层是一个iife
5. system systemjs的简写,SystemJs是一个通用的模块加载器,支持 CJS,AMD 和 ESM 模块
6. iife 立即调用函数表达
四.配置rollup.config.js来打包编译(单文件和多文件输出)
在根目录下新建rollup.config.js文件:最简单的配置,打包输出一个文件引入使用
export default {
input: 'src/main.js', //要打包的文件入口源文件
output: { //打包后文件的输出配置,打包后文件的位置,格式以及名字
file: 'dist/bundle.cjs.js', //打包后文件的位置,以及打包输出后的文件名
format: 'cjs', //以什么的格式打包输出 有六种 cjs,esm,amd,umd,iife,system
name:"myModuleName" //包的全局变量名称
}
};
在src目录下新建main.js,以及modules文件夹用来存放自己的模块文件,并在moduels文件夹下新建myModule.js文件,代码如下:
myModule.js文件:
// modules的作用的区分模块和主入口,modules中可根据你自己的js库设计文件目录结构。
const welcomeRollup=(message)=>{
console.log(message)
}
export default welcomeRollup
main.js文件:
import welcomeRollup from "./modules/myModule";
welcomeRollup('hello rollup')
配置package.json文件,代码如下:
{
"name": "rollup-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type":"module", //加上type,解决下面的报错
"scripts": {
"build": "rollup --config rollup.config.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"rollup": "^3.2.3"
}
我们执行npm run build命令来,发现报错如下:
大概的意思就是: 要加载需要在package.json中配置"type":"module"或者使用.mjs扩展名
再次执行npm run build命令:打包成功
dist/bundle.cjs.js中的代码如下:可以看到代码很简洁,没有多余的代码
多文件:
上面是单个文件的打包输出,也可以向webpack一样的多文件打包输出,配置如下:
rollup.config.js
export default [ //写成数组的形式
// 可以多个入口多个输出
{
input:"src/main.js",
output:{
file:"dist/bundle.cjs.js",
format:'cjs'
}
},
// 也可以单个入口,多个输出
{
input:"src/main1.js",
output:[
{
file:"dist/bundle1.cjs.js",
format:'cjs'
},
{
file:"dist/bundle1-1.cjs.js",
format:'iife'
}
]
}
]
打包后可以看到文件目录如下:输出三个文件
五。rollup.config.js中配置详解:
- input:入口文件的位置,
- output:输出文件的配置
- plugins:各种辅助插件的使用配置
- global:设置全局变量的别名的
- external:告诉rollup什么不需要打包,而是作为外部依赖来使用
export default {
input: 'src/main.js', //要打包的文件入口源文件
external:['lodash'], //告诉rollup,不要将lodash打包,当作外部依赖
output: { //打包后文件的输出配置,打包后文件的位置,格式以及名字
file: 'dist/bundle.cjs.js', //打包后文件的位置,以及打包输出后的文件名
format: 'cjs', //以什么的格式打包输出 有六种 cjs,esm,amd,umd,iife,system
name:"myModuleName", //包的全局变量名称, 当format为iife和umd时必须提供,将作为全局变量挂在window(浏览器环境)下:window.myModuleName=...
sourcemap:true, //生成map文件,方便调试
globals:{
"lodash":"_" //告诉rollup,全局变量_就是lodash
}
},
plugins:[
//各种辅助功能的插件来使用
]
};
六。接下里我们学习使用常用的插件plugins
1.@rollup/plugin-commonjs
rollup默认是打包的es格式的代码,commonjs的代码需要插件来转化
修改main.js中和myModule.js中的代码如下:
myModule.js:
// commonjs的格式导出
module.exports=2
main.js:
// 我们还是使用es6的方式引入:
import a from './modules/myModule'
console.log(a)
npm run build:打包报错如下:
我们就需要插件 @rollup/plugin-commonjs 来帮我们转化
安装插件:npm i @rollup/plugin-commonjs -D
配置如下:
// 引入可以解决引入commonjs模块的插件
import commonjs from '@rollup/plugin-commonjs'
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.cjs.js',
format: 'cjs',
name:"myModuleName",
},
plugins:[
commonjs() //直接使用
]
};
npm run build命令打包成功,bundle.cjs.js中的代码很简单:
'use strict';
// commonjs的格式导出
var myModule=2;
console.log(myModule);
2.@rollup/plugin-node-resolve
假如我们需要引入第三方库来使用,就要使用@rollup/plugin-node-resolve插件来允许我们加载第三方模块
我们先不引入这个插件,引入lodash来使用
安装 npm i lodash -D
修改main.js中的代码,如下:
// 我们还是使用es6的方式引入:
import a from './modules/myModule'
import _ from 'lodash' //引入lodash
const arr=_.chunk([2,3,4,5],2) //使用chunk方法,将数组拆分,组成新的数组
console.log(a,arr)
打包 npm run build 是可以打包成功的,但是有提示如下:
大致的意思是: 打包成时无法找到外部的依赖,导致报错。
而且我们将打包后的js文件引入到html中后,控制台会报错,无法找到引入的模块
我们引入插件:@rollup/plugin-node-resolve
安装 npm i @rollup/plugin-node-resolve -D
配置:
// 引入可以解决引入commonjs模块的插件
import commonjs from '@rollup/plugin-commonjs'
// 引入允许我们使用第三方插件的插件
import nodeResolve from '@rollup/plugin-node-resolve'
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.cjs.js',
format: 'cjs',
name:"myModuleName",
},
plugins:[
commonjs(), //直接使用
nodeResolve() //直接使用
]
};
在执行打包命令:成功打包,没有报错,而且打包文件bundle.cjs.js文件中多了引入的lodash代码,
控制台打开html也是成功的打印出信息:
3.babel转化
会使用到的插件:
-
@babel/core babel的核心代码库
-
@babel/preset-env 这是一个智能预设,它允许你使用最新的 JavaScript 语法,而无需对目标环境需要哪些语法转换进行管理;拥有根据 useBuiltIns 参数的多种polyfill实现,优点是覆盖面比较全(entry), 缺点是会污染全局, 推荐在业务项目中使用
-
@rollup/plugin-babel rollup中babel插件
-
@babel/plugin-transform-runtime 一个插件,可以重用Babel注入的助手代码,以节省代码大小。沙箱垫片和代码复用, 避免帮助函数重复 inject 过多的问题, 该方式的优点是不会污染全局, 适合在类库开发中使用
安装 npm i @babel/core @babel/preset-env @rollup/plugin-babel -D
修改main.js中的代码如下:
// 我们还是使用es6的方式引入:
import a from './modules/myModule'
// import _ from 'lodash'
// const arr=_.chunk([2,3,4,5],2)
const arr=[1,2,3,4].map(item=>(item++))
console.log(a,arr)
配置如下:
// 引入可以解决引入commonjs模块的插件
import commonjs from '@rollup/plugin-commonjs'
// 引入允许我们使用第三方插件的插件
import nodeResolve from '@rollup/plugin-node-resolve'
// 引入转化语法的babel,兼容更多的浏览器
import babel from '@rollup/plugin-babel'
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.cjs.js',
format: 'cjs',
name:"myModuleName",
},
plugins:[
commonjs(), //直接使用
nodeResolve(),
babel({
exclude:"node_modules/**", //将node_modules中的文件排除
// babelHelpers: 'runtime'
})
],
external:['lodash']
};
并且新建.babelrc文件在src目录下:代码如下:
{
"presets": [
"@babel/env"
]
}
执行打包命令:会有个提示,以及打包文件的bundle.cjs.js中的代码如下:我们可以看到const已经被转化为var ,但是map并没有被转化;使用了@abbel/preset-env后 标准引入的语法:箭头函数,let,const等是可以转换的 但是引入的全局变量,部分原生对象新增的原型链上的方法不可以转化 例如:promise.symbol,set,map等;就需要引入别的插件来处理 ,我们使用 @bebal/plugin-transform-runtime来帮我们处理
'use strict';
// commonjs的格式导出
var myModule = 2;
// 我们还是使用es6的方式引入:
// import _ from 'lodash'
// const arr=_.chunk([2,3,4,5],2)
var arr = [1, 2, 3, 4].map(function (item) {
return item++;
});
console.log(myModule, arr);
安装 npm i @babel/plugin-transform-runtime -D
配置如下:
// 引入可以解决引入commonjs模块的插件
import commonjs from '@rollup/plugin-commonjs'
// 引入允许我们使用第三方插件的插件
import nodeResolve from '@rollup/plugin-node-resolve'
// 引入转化语法的babel,兼容更多的浏览器
import babel from '@rollup/plugin-babel'
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.cjs.js',
format: 'cjs',
name:"myModuleName",
},
plugins:[
commonjs(), //直接使用
nodeResolve(),
babel({
exclude:"node_modules/**", //将node_modules中的文件排除
babelHelpers: 'runtime' //显示这个配置项 有'bundled' | 'runtime' | 'inline' | 'external'
})
],
external:['lodash']
};
.babelrc代码如下:
{
"presets": [
"@babel/env"
],
"plugins": [
["@babel/plugin-transform-runtime", {
"corejs": 3
}]
]
}
在执行打包命令:发现报错:需要安装和@babel/plugin-transform-runtime配套使用的插件:@babel/runtime-corejs3
安装 npm i @babel/runtime-corejs3 -D
再次执行命令,打包成功不报错。
4.@rollup/plugin-alias 配置别名的插件
安装 npm i @rollup/plugin-alias -D
配置如下:
// 引入配置别名的插件
import alias from '@rollup/plugin-alias'
.....
plugins:[
commonjs(), //直接使用
nodeResolve(),
babel({
exclude:"node_modules/**", //将node_modules中的文件排除
babelHelpers: 'runtime'
}),
// 配置别名的插件
alias({
entries:[
{
find:'@',replacement:path.resolve(__dirname,'./src/modules')
}
]
})
],
修改main.js中的代码如下:
// 我们还是使用es6的方式引入:
import a from '@/myModule' //使用别名引入
// import _ from 'lodash'
// const arr=_.chunk([2,3,4,5],2)
const arr=[1,2,3,4].map(item=>(item++))
console.log(a,arr)
执行打包命令:报错如下:
原因是找不到__dirname,我们需要把__dirname先定义出来,完整代码如下:
import path from 'path'
const __dirname = path.resolve() //先把__dirname定义出来,防止报错
// 引入可以解决引入commonjs模块的插件
import commonjs from '@rollup/plugin-commonjs'
// 引入允许我们使用第三方插件的插件
import nodeResolve from '@rollup/plugin-node-resolve'
// 引入转化语法的babel,兼容更多的浏览器
import babel from '@rollup/plugin-babel'
// 引入配置别名的插件
import alias from '@rollup/plugin-alias'
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.cjs.js',
format: 'cjs',
name:"myModuleName",
},
plugins:[
commonjs(), //直接使用
nodeResolve(),
babel({
exclude:"node_modules/**", //将node_modules中的文件排除
babelHelpers: 'runtime'
}),
// 配置别名的插件
alias({
entries:[
{
find:'@',replacement:path.resolve(__dirname,'./src/modules')
}
]
})
],
external:['lodash']
};
在执行打包命令后:npm run build 打包成功
5.使用ts,需要插件 @rollup/plugin-typescript
安装 npm i @rollup/plugin-typescript -D
在src目录下的modules下新建helloRollup.ts文件,代码如下:
const helloRollup=function(str:string):void{
console.log(str+Math.random())
}
export default helloRollup
修改main.js代码如下:
// 我们还是使用es6的方式引入:
import a from '@/myModule'
//引入ts文件
import helloRollup from '@/helloRollup.ts'
// import _ from 'lodash'
// const arr=_.chunk([2,3,4,5],2)
const arr=[1,2,3,4].map(item=>(item++))
console.log(a,arr)
helloRollup()
配置rollup.config.js文件:
import path from 'path'
const __dirname = path.resolve()
// 引入可以解决引入commonjs模块的插件
import commonjs from '@rollup/plugin-commonjs'
// 引入允许我们使用第三方插件的插件
import nodeResolve from '@rollup/plugin-node-resolve'
// 引入转化语法的babel,兼容更多的浏览器
import babel from '@rollup/plugin-babel'
// 引入配置别名的插件
import alias from '@rollup/plugin-alias'
// 引入可以编译ts的插件
import typescript from '@rollup/plugin-typescript'
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.cjs.js',
format: 'cjs',
name:"myModuleName",
},
plugins:[
commonjs(), //直接使用
nodeResolve(),
babel({
exclude:"node_modules/**", //将node_modules中的文件排除
babelHelpers: 'runtime'
}),
// 配置别名的插件
alias({
entries:[
{
find:'@',replacement:path.resolve(__dirname,'./src/modules')
}
]
}),
typescript() //使用插件
],
external:['lodash']
};
执行打包命令 npm run build:发现报错如下,意思就是需要安装tslib插件
安装 npm i tslib -D
不需要加配置代码,再次执行打包命令,成功打包
此处我们没有配置tsconfig.json文件(后面学习记录)
6.rollup也可以给我们自动生成html文件,自动引入打包后的js文件
需要插件 @rollup/plugin-html
安装 npm i @rollup/plugin-html -D
配置:
// 引入自动生成html文件的插件
import html from '@rollup/plugin-html'
....
plugins:[
html({}) //使用插件
]
执行打包命令后:就会在dist目录下生成一个html文件
7.像webpack一样,rollup也是需要处理css文件的 rollup和postcss是无缝衔接的
用到的插件有 rollup-plugin-postcss
安装 npm i rollup-plugin-postcss -D npm i sass -D
在src目录下新建index.scss文件,代码如下:
body{
background-color: aqua;
.title{
color:red;
}
}
配置:
// 引入处理css的插件
import postcss from 'rollup-plugin-postcss'
plugins:[
postcss({
extract:true,//css通过链接引入
use:['sass'] //编译sass
})
]
执行打包命令:
可以看到dist目录下生成一个css文件,代码如下:
body {
background-color: aqua;
}
body .title {
color: red;
}
8.处理图片需要什么插件呢? @rollup/plugin-url
安装: npm i @rollup/plugin-url -D
配置:
// 引入处理图片的插件
import url from '@rollup/plugin-url'
plugins:[
url()
]
9.代码的压缩
需要的插件是:npm i @rollup/plugin-terser -D
配置:
// 引入压缩代码的插件
import terser from '@rollup/plugin-terser'
plugins:[
terser() //直接使用
]
执行打包命令后,发现js文件已经被压缩
10.我们如何起本地服务呢?
需要的插件有:npm i rollup-plugin-serve -D
配置:
// 引入启动本地服务的插件
import serve from 'rollup-plugin-serve'
plugins:[
// 开启本地服务
serve({
open: true, // 自动打开页面
port: 8000,
openPage: '/dist/index.html', // 打开的页面
contentBase: ''
})
]
11.开启热更新的插件
需要的插件是: npm i rollup-plugin-livereload -D
配置:
// 引入实现热更新的插件
import livereload from 'rollup-plugin-livereload'
plugins:[
livereload() //直接使用
]
12.rollup也是可以区分环境的
和webpack一样的,不同的环境需要不同的配置
在开发环境我们需要sourcemap开启,配置热更新和本地服务,在生产环境我们需要sourcemap关闭,不需要热更新和本地服务,需要代码压缩等;
在根目录下新建:build文件 在build文件下新建rollup.dev.js(开发环境的配置) 和rollup.prod.js (生产环境的配置)
修改package.json中的代码:
{
"name": "rollup-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"dev": "rollup --config build/rollup.dev.js -w", //开发环境
"build": "rollup --config build/rollup.prod.js" //生产环境
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": { //安装插件以及版本信息
"@babel/core": "^7.20.2",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/preset-env": "^7.20.2",
"@babel/runtime-corejs3": "^7.20.1",
"@rollup/plugin-alias": "^4.0.2",
"@rollup/plugin-babel": "^6.0.2",
"@rollup/plugin-commonjs": "^23.0.2",
"@rollup/plugin-html": "^1.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-terser": "^0.1.0",
"@rollup/plugin-typescript": "^9.0.2",
"@rollup/plugin-url": "^8.0.1",
"lodash": "^4.17.21",
"rollup": "^3.2.3",
"rollup-plugin-livereload": "^2.0.5",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-serve": "^2.0.1",
"sass": "^1.56.0",
"tslib": "^2.4.1"
}
}
rollup.config.js中的代码如下:
import path from 'path'
const __dirname = path.resolve()
// 引入可以解决引入commonjs模块的插件
import commonjs from '@rollup/plugin-commonjs'
// 引入允许我们使用第三方插件的插件
import nodeResolve from '@rollup/plugin-node-resolve'
// 引入转化语法的babel,兼容更多的浏览器
import babel from '@rollup/plugin-babel'
// 引入配置别名的插件
import alias from '@rollup/plugin-alias'
// 引入可以编译ts的插件
import typescript from '@rollup/plugin-typescript'
// 引入自动生成html文件的插件
import html from '@rollup/plugin-html'
// 引入处理css的插件
import postcss from 'rollup-plugin-postcss'
// 引入处理图片的插件
import url from '@rollup/plugin-url'
// 引入压缩代码的插件
import terser from '@rollup/plugin-terser'
// 引入启动本地服务的插件
import serve from 'rollup-plugin-serve'
// 引入实现热更新的插件
import livereload from 'rollup-plugin-livereload'
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.cjs.js',
format: 'esm',
name:"myModuleName",
},
plugins:[
commonjs(), //直接使用
nodeResolve(),
babel({
exclude:"node_modules/**", //将node_modules中的文件排除
babelHelpers: 'runtime'
}),
// 配置别名的插件
alias({
entries:[
{
find:'@',replacement:path.resolve(__dirname,'./src/modules')
}
]
}),
typescript(), //使用插件
html({
format:"cjs"
}),
postcss({
extract:true,//css通过链接引入
use:['sass'] //编译sass
}),
url(),
terser(),
// 开启本地服务
serve({
open: true, // 自动打开页面
port: 8000,
openPage: '/dist/index.html', // 打开的页面
contentBase: ''
}),
livereload()
],
external:['lodash']
};
我们根据环境的不同配置不同的插件即可。加油学习前端的每一天!!!