这次主要简单实现用rollup打包react组件,组件的话简单写了一个弹窗组件,效果如下:
点击打开弹框,点击关闭按钮关闭弹框
首先创建react项目,这边还是用mfex-project脚手架创建
mfex-project create react-demo
然后编写dialog组件
代码如下:
components/dialog/index.tsx
import './index.scss';
import closeIcon from '@/assets/close-black.png'
interface IProps {
show: boolean;
title?:string;
handleCloseAction: () => void
}
function Dialog(props: IProps) {
const handleClose = () => {
props.handleCloseAction()
}
return (
props.show ? <div className='dialog'>
<div className='dialog-content'>
<img src={closeIcon} alt="" className='dialog-content-close' onClick={handleClose}/>
<h1 className='dialog-content-title'>{props.title}</h1>
</div>
</div> : <></>
)
}
export default Dialog;
components/dialog/index.scss
.dialog{
position: fixed;
left: 0;
top: 0;
bottom: 0;
right: 0;
background: rgba(0,0,0,.6);
z-index: 990;
&-content{
width: 500px;
height: 300px;
background: #fff;
border-radius: 25px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
&-close{
width: 30px;
height: 30px;
position: absolute;
right: 20px;
top: 20px;
}
&-title{
margin-top: 20px;
text-align: center;
}
}
}
引入使用组件:
import './index.scss';
import Dialog from '@/components/dialog'
import { useState } from 'react'
function Index() {
const [dialogShow, setDialogShow] = useState<boolean>(false)
const handleCloseAction = () => {
setDialogShow(false)
}
return (
<>
<div className='index'></div>
<div className='w-100px h-100px bg-blue-300' onClick={()=>setDialogShow(true)}>打开dialog</div>
<Dialog show={dialogShow} title='rollup' handleCloseAction={handleCloseAction}/>
</>
)
}
export default Index;
接下来用rollup把组件封装
1、创建文件夹,命名为react-dialog,初始化项目
npm init -y
2、安装rollup
npm i rollup -D
3、安装插件
-
@rollup/plugin-node-resolve:帮助 rollup 识别外部模块
-
@rollup/plugin-babel:ES6转ES5
-
@rollup/plugin-commonjs:将commonjs模块转为es模块
-
@rollup/plugin-terser:代码压缩
-
rollup-plugin-img:处理图片
-
rollup-plugin-postcss:处理css
-
@rollup/plugin-json:处理json
-
@rollup/plugin-typescript:处理typescript
-
rollup-plugin-dts:打包ts声明文件,d.ts
npm i @rollup/plugin-node-resolve
@rollup/plugin-babel
@rollup/plugin-commonjs
@rollup/plugin-terser
rollup-plugin-img
rollup-plugin-postcss
@rollup/plugin-json
@rollup/plugin-typescript
rollup-plugin-dts -D
4、安装css和babel对应的包
npm i autoprefixer core-js @babel/core @babel/plugin-transform-runtime @babel/preset-env -D
根目录下新建.babelrc,内容如下
{
"presets": [
[
"@babel/preset-env",
{
"modules": false, // 对ES6的模块文件不做转化,以便使用tree shaking、sideEffects等
"useBuiltIns": "entry", // browserslist环境不支持的所有垫片都导入
// https://babeljs.io/docs/en/babel-preset-env#usebuiltins
// https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md
"corejs": {
"version": 3, // 使用core-js@3
"proposals": true
}
}
]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": false // 解决 helper 函数重复引入
}
]
],
"ignore": [
"node_modules/**"
]
}
需要指定 browserslist 来确定我们程序运行的目标环境,避免去兼容程序不考虑的浏览器环境
在package.json添加:
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
5、由于是使用typescript,所以安装typescript,并初始化tsconfig.json
npm i typescript -D
npx tsc --init
tsconfig.json内容如下:
{
"compilerOptions": {
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
"jsx": "react-jsx", /* Specify what JSX code is generated. */
/* Modules */
"module": "ESNext", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
/* Emit */
"declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
"emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
"sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
"outDir": "dist", /* Specify an output folder for all emitted files. */
"allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
}
}
6、接下来把react组件copy到项目中
7、由于使用了png后缀的文件,所以要定义文件类型, 不然ts会报错
在根目录下新疆index.d.ts
declare module '*.png'
8、修改package.json
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"type": "module",
"types": "dist/index.d.ts",
"files": [
"dist",
"package.json"
],
"scripts": {
"build": "rimraf dist && rollup -c"
},
9、编写rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import babel from '@rollup/plugin-babel';
import commonjs from '@rollup/plugin-commonjs';
import terser from '@rollup/plugin-terser';
import image from 'rollup-plugin-img';
import postcss from 'rollup-plugin-postcss'
import json from '@rollup/plugin-json';
import typescript from '@rollup/plugin-typescript';
import dts from "rollup-plugin-dts";
import autoprefixer from 'autoprefixer'
import path from 'path'
// 讲require转换为模块
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const pkg = require(path.resolve(`package.json`))
export default[
{
input:'./src/index.tsx',
output:[
{
file:pkg.main,
format:"cjs",
sourcemap:true,
name:"react-dialog-lib"
},
{
file:pkg.module,
format:"es",
sourcemap:true,
}
],
plugins:[
resolve(),
typescript(),
terser(),
babel({
exclude: "**/node_modules/**",
runtimeHelpers: true,
}),
commonjs(),
postcss({
plugins:[autoprefixer()]
}),
json(),
image({
limit: 8192, // default 8192(8k)
exclude: 'node_modules/**'
})
]
},
{
input:"dist/esm/index.d.ts",
output:[
{
file:"dist/index.d.ts",
format:"es"
}
],
external: [/\.scss$/],
plugins:[
dts()
]
}
]
10、运行打包命令,后续可以发布到npm上,这里只是作为演示
npm run build
打包成功
11、在之前的项目的使用
引入包
npm i
然后
正常显示
遇到的问题:
- 在编写包项目时,编辑器会无法识别react的语法
React' refers to a UMD global, but the current file is a module. Consider adding an import instead 在tsconfig.json中加上 "jsx": "react-jsx",
-
Cannot find module 'react/jsx-runtime' or its corresponding type declarations. JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists. 需要安装@types/react
npm i @types/react -D