Bootstrap

rollup打包react组件

这次主要简单实现用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

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;