首先先初始化一下项目:
yarn init -y
mkdir src
touch src/index.js rollup.config.js
yarn -D add rollup
再把我们项目的的文件都初始化一下:
// filename: src/index.js
function sum(a, b) {
return a + b;
}
export {
sum
}
// filename: rollup.config.js
export default {
input: "src/index.js",
output: {
file: 'dist/bundle.js',
format: 'cjs',
},
}
// filename: package.json
{
"name": "rollup-demo",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"build": "npx rollup -c rollup.config.js"
},
"license": "MIT",
"devDependencies": {
"rollup": "^2.55.1"
}
}
做完上面的工作之后,运行 yarn build
,我们会在根目录的 dist
文件夹找到打包后的 bundle.js
,这样我们就很轻松的完成了最基本的功能:打包普通的 JavaScript 文件。
接下来我们在 src/button.jsx
使用 React 写一个 Button 组件,并在 src/index.js
中导出一下:
// filename: button.jsx
import React from 'react';
function Button() {
return <button>按钮</button>
}
此时直接打包,会报错。
不仅仅是因为我们没有安装 React,还因为在这里,我们写了 import React from 'react'
这一行代码,而在 Rollup 中,我们要想使用 node_modules 里面的包,必须使用 node-resolve 这个插件才行,这一点和 Webpack 很不一样,在 Webpack,我们可以无需任何配置,就能直接使用 node_modules 的包。
import resolve from '@rollup/plugin-node-resolve';
export default {
input: "src/index.js",
plugins: [resolve()],
output: {
file: 'dist/bundle.js',
format: 'cjs',
},
}
除此之外,还有一个坑,如果我们去看 React 源码的入口文件 index.js
,会发现它是以 CommonJS 规范导出的。
Rollup 默认不支持引入 CommonJS 规范导出的包,因此,我们还要安装一个叫做 @rollup/plugin-commonjs的插件
// 这是 React 的入口文件
'use strict';
if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react.production.min.js');
} else {
module.exports = require('./cjs/react.development.js');
}
PS: 顺便提一句,React 这么分情况导出是为了方便我们开发环境 Debugger 它的源码。如果你也想让使用者在开发环境调试类库的源码,可以参考它的这种思路。
你以为到这里就完了吗,别着急,还有呢。因为 Rollup 不认识 JSX 语法,所以我们还要添加编译 JSX 语法的插件,这一点倒是和 Webpack 中是一样,我们使用 Babel 就好了:
import babel, { getBabelOutputPlugin } from '@rollup/plugin-babel';
export default {
input: 'main.js',
// 为了把 JSX 专为 JS
plugins: [babel({ presets: ['@babel/preset-react'] })],
output: [
{
file: 'bundle.js',
format: 'esm',
// 为了兼容新语法,使用 babel 转译一下
plugins: [getBabelOutputPlugin({ presets: ['@babel/preset-env'] })]
}
]
};
其实关于上面提的几点,说是坑也不合适,只是因为很多同学使用 Webpack 久了,就把它的一些东西想成自然而然的,想成了「常识」,而 Rollup 可能在某些方面会和我们的「常识」冲突。就会让我们在刚使用的时候有些不舒服。
最后,我们的 rollup.config.js
更新为:
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel, { getBabelOutputPlugin } from '@rollup/plugin-babel';
export default {
input: "src/index.js",
plugins: [
resolve(),
commonjs(),
babel({
presets: ['@babel/preset-react'],
babelHelpers: 'bundled'
})
],
output: {
file: 'dist/bundle.js',
format: 'esm',
plugins: [
getBabelOutputPlugin({
presets: ['@babel/preset-env'],
})
]
},
}
这样子我们就可以顺利的打包出来了。
接下来我们需要添加对 TypeScript 的支持,此时我们需要引入的包有 acorn-jsx 和 @rollup/plugin-typescript。如果二者单独使用的话,会是这样子:
import jsx from 'acorn-jsx';
import typescript from '@rollup/plugin-typescript';
export default {
// … other options …
acornInjectPlugins: [jsx()],
plugins: [typescript({ jsx: 'preserve' })]
};
在 Rollup 中,插件的执行顺序是按数组的索引顺序的,如果把二者加到我们配置文件中去,最后的 rollup.config.js
是这样子的:
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import babel, { getBabelOutputPlugin } from '@rollup/plugin-babel';
import jsx from 'acorn-jsx';
export default {
input: "src/index.ts",
acornInjectPlugins: [jsx()],
plugins: [
resolve(),
commonjs(),
typescript({ jsx: 'preserve' }),
babel({
presets: ['@babel/preset-react'],
babelHelpers: 'bundled',
extensions: ['.js', '.jsx', '.es6', '.es', '.mjs', '.ts', '.tsx']
})
],
output: {
file: 'dist/bundle.js',
format: 'esm',
plugins: [
getBabelOutputPlugin({
presets: ['@babel/preset-env'],
})
]
},
}
这样之后,我们就能顺利的打包 React + TypeScript 的项目了。不过,作为一个类库,一般是不需要安装 React 的,这应该是使用我们项目的人安装的,所以,我们要把 React 从我们的打包结果中排出去,这里使用到了 Rollup 的一个配置:
export default {
input: "src/index.ts",
acornInjectPlugins: [jsx()],
external: ['react'] // 增加了这一行。
}
做到这里,我们就基本完成了脚手架的搭建,如何您想更方便的管理您的类库,可以考虑使用 release-it 、lerna 这样的包。
以上就是全部啦,撒花。