Rollup.js | 解决打包react项目报错

最近写了一个九宫格抽奖的一个react的组件,想着写都写完了,顺便在回顾下rollup打包一个组件,并且来发布出来。主要就用到了react 和rollup。rollup 适合打包 js 库,不适合打包 css,如果想制作 基于 react 和antd 的组件首选 webpack

一、初始化项目

1
2
3
mkdir lottery-react
cd lottery-react
npm init

我的package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
{
"name": "lottery-react",
"version": "1.0.2",
"description": "lottery-react",
"main": "lib/index.js",
"module": "es/index.js",
"unpkg": "dist/lottery.min.js",
"files": [
"dist",
"lib",
"es"
],
"sideEffects": [
"dist/*",
"es/**/style/*",
"lib/**/style/*",
"*.scss"
],
"scripts": {
"clean": "rimraf lib es dist",
"build:cjs": "babel src --out-dir lib",
"build:es": "cross-env BABEL_ENV=jsnext babel src --out-dir es",
"build:umd": "cross-env BABEL_ENV=rollup NODE_ENV=development rollup -c -f umd -o dist/lottery.js",
"build:umd:min": "cross-env BABEL_ENV=rollup NODE_ENV=production rollup -c -f umd -o dist/lottery.min.js",
"build": "npm run clean && npm run build:cjs && npm run build:es && npm run build:umd && npm run build:umd:min",
"build:cjs2": "cross-env BABEL_ENV=rollup NODE_ENV=development rollup -c -f umd -o lib/index.js",
"build:es2": "cross-env BABEL_ENV=rollup NODE_ENV=development rollup -c -f umd -o es/index.js",
"build:all": "npm run clean && npm run build:cjs2 && npm run build:es2 && npm run build:umd && npm run build:umd:min",
"examples": "npm-run-all --parallel examples:watch examples:start",
"examples:clean": "rimraf example/dist",
"examples:start": "serve example/dist",
"examples:watch": "rollup -c example/rollup.config.js -w",
"examples:build": "rollup -c example/rollup.config.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/sailormillet/lottery-react.git"
},
"keywords": [
"Lottery",
"lucky draw",
"lotto",
"sweepstake",
"react"
],
"author": "Amy",
"license": "ISC",
"bugs": {
"url": "https://github.com/sailormillet/lottery-react/issues"
},
"homepage": "https://github.com/sailormillet/lottery-react#readme",
"peerDependencies": {
"react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0",
"react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
},
"devDependencies": {
"@babel/cli": "^7.12.10",
"@babel/core": "^7.12.10",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/preset-env": "^7.12.11",
"@babel/preset-react": "^7.12.10",
"@rollup/plugin-alias": "^3.1.1",
"@rollup/plugin-babel": "^5.2.2",
"@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-node-resolve": "^11.1.0",
"@rollup/plugin-replace": "^2.3.4",
"cross-env": "^7.0.3",
"fs": "^0.0.1-security",
"npm-run-all": "^4.1.5",
"path": "^0.12.7",
"postcss": "^8.2.4",
"postcss-cssnext": "^3.1.0",
"postcss-nested": "^5.0.3",
"postcss-preset-env": "^6.7.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"rollup": "^2.36.1",
"rollup-plugin-generate-html-template": "^1.7.0",
"rollup-plugin-includepaths": "^0.2.4",
"rollup-plugin-postcss": "^4.0.0",
"rollup-plugin-scss": "^2.6.1",
"rollup-plugin-uglify": "^6.0.4",
"serve": "^11.3.2"
},
"dependencies": {}
}

目录结构描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
├── dist                      
├── es
├── lib
├── example
│ ├── dist
│ ├── src
│ │ ├── components
│ │ ├── index.html
│ │ └── index.js
│ ├── rollup.config.js
├── src
│ ├── styles
│ │ └── index.scss
│ └── index.js
├── README.md // 开发文档
├── .gitignore
├── .babelrc // babel配置
├── .eslintrc // ESLint 配置文件
├── .editorconfig // IDE定义配置
├── package.json // 模块描述文件
├── rollup.config.js // 模块描述文件
└── yarn.lock // 依赖文件

外层rollup.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

import resolve from '@rollup/plugin-node-resolve';
import babel from '@rollup/plugin-babel';
import commonjs from '@rollup/plugin-commonjs';
import { uglify } from 'rollup-plugin-uglify';
import replace from '@rollup/plugin-replace';
import postcss from 'rollup-plugin-postcss';
const env = process.env.NODE_ENV;

const config = {
input: 'src/index.js',
//告诉rollup不要将此lodash打包,而作为外部依赖
external: ["react"],
// 是否开启代码分割
experimentalCodeSplitting: true,
output: {
// dir: "lib",
name: 'LuckDraw',
format: 'umd',
sourcemap: true,
globals: {
react: 'React'
},
exports: 'named',
},
plugins: [
resolve(),
babel({
babelHelpers: 'bundled',
exclude: '**/node_modules/**',
}),
commonjs(),
postcss({
minimize: env === 'production',
extract: true,
extensions: ["scss", "less", "css"],
// plugins: [nested(), cssnext({ warnForDuplicates: false }), cssnano()],
// extract: false // 无论是 dev 还是其他环境这个配置项都不做 样式的抽离
}),
],
};


if (env === 'production') {
config.plugins.push(
uglify({
compress: {
pure_getters: true,
unsafe: true,
unsafe_comps: true,
},
warnings: false
})
);

config.plugins.push(
replace({
'process.env.NODE_ENV': JSON.stringify('production')
})
)
}

export default config;

src/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import React from 'react'
import './styles/index.scss'
class LuckDraw extends React.PureComponent {
constructor(props) {
super(props)
this.state = {
active_index: null, // 奖品是否被选中,选中时,值为奖品index, 例如0,1,2,3...
times: 'times' in props ? props.times * 1 : 1, // 抽奖次数
is_rolling: false, // 正在抽奖时,禁止重复点击
roll_map_list: [0, 1, 2, 7, 8, 3, 6, 5, 4], // 运动顺序,数据映射
};
this.lotteryTimer = null;
this.current_index = 0;
this.CYCLE_TIMES = 0;
this.speed = 50;
}
componentWillUnmount() {
clearTimeout(this.lotteryTimer);
clearTimeout(this.callbacktimer)
}
data_format(data) {
if (data) {
// let gift_list = data.slice(0, 8);
let gift_list = data.slice(0);
gift_list.splice(gift_list.length / 2, 0, {
name: "立即抽奖",
image: "",
id: "",
startBtn: true
})
return gift_list
} else {
console.error('未获取到奖品信息!');
return []
}
}
start = () => {
const { roll_map_list, times } = this.state;
const { gift, giftList, speed = 120, cycle_times = 3 } = this.props
const gift_list = this.data_format(giftList)
this.setState(
{
active_index: this.current_index,
},
() => {
let act_item = gift_list[roll_map_list.indexOf(this.current_index)] || {}
if (this.speed > speed && (act_item.id * 1 === gift.id * 1)) {
clearTimeout(this.lotteryTimer);
this.lotteryTimer = null;
this.CYCLE_TIMES = 0;
this.speed = 50;
this.callbacktimer = setTimeout(() => {
this.setState({ is_rolling: false, times: times - 1 })
this.props.callback && this.props.callback({ ...act_item, ...gift }, this)
}, 500);
return
}
this.current_index = ++this.current_index % gift_list.length;
this.current_index === 0 && this.CYCLE_TIMES++;
this.lotteryTimer = setTimeout(() => {
this.start();
}, this.speed);
if (this.CYCLE_TIMES > cycle_times) this.speed += 10;
}
);
};
reset = () => {
this.setState({
active_index: null,
})
this.lotteryTimer = null;
this.current_index = 0;
this.CYCLE_TIMES = 0;
this.speed = 50;
}
handlePlay = () => {
if (!this.state.times) return this.props.finishCallback && this.props.finishCallback(this);
if (this.state.is_rolling) return;
this.current_index = 0;
this.CYCLE_TIMES = 0;
this.speed = 50;
if (this.props.beforeStart) {
this.props.beforeStart().then(() => {
this.setState({
is_rolling: true,
}, () => {
this.start();
})
})
} else {
this.setState({
is_rolling: true,
}, () => {
this.start();
})
}
};
render() {
const { active_index, roll_map_list } = this.state;
const gift_list = this.data_format(this.props.giftList)
if (gift_list.length < 8) return null;
return (
<div className={`lottery pos-r`}>
<div className={`lottery_content`}>
{gift_list.map((item, index) => {
let content = (
<div key={index} className={`lottery_item ${active_index === roll_map_list[index] ? 'lottery_item-active' : ''}`} >
{item.ele ? item.ele : <div className={`lottery_item_main`}>{item.name}</div>}
</div>
);
if (item.startBtn) {
content = (
<div key={index} className={`lottery_item`} onClick={this.handlePlay} >
{typeof this.props.playBtn === 'object' ? this.props.playBtn : <div className={`lottery_item_main`} >{this.props.playBtn || item.name}</div>}
</div>
);
}
return content;
})}
</div>
</div>
);
}
}
export default LuckDraw

1、rollup-plugin-commonjs这个包一定要引入好,并且注意使用
//告诉rollup不要将此lodash打包,而作为外部依赖,否则会报

不识别或者 React 的Component 各种错

1
2
external: ["react"],//告诉rollup不要将此react打包,而作为外部依赖
commonjs(),

2、npm 和 git 使用共同的 version和 tags
3、npm 发布用下面的,添加包用上面的

1
2
npm set registry https://registry.npm.taobao.org
npm set registry http://registry.npmjs.org

发布到 npm

1
2
3
4
npm login
npm version new-version
npm publish
git push origin --tags

配置.npmignore

如果项目中没有编写 .npmignore 文件,则需要在 package.json 中新增 files 字段,用于申明将要发布到 NPM 的文件。如果省略掉这一项,所有文件包括源代码会被一起上传到 NPM。
本文采用写 .npmignore 文件的方式,实现仅发布打包后的组件代码。 .npmignore 文件的具体内容如下:

指定发布 npm 的时候需要忽略的文件和文件夹

npm 默认不会把 node_modules 发上去

1
2
3
4
config # webpack配置
example # 开发时预览代码
src # 组件源代码目录
.babelrc # babel 配置