项目结构
pp-react-ui
├── README.md
├── package-lock.json
├── package.json
└── src //项目源码
└── components //组件目录
├── button
│ ├── index.js
│ └── style.css
├── hello
│ ├── index.js
│ └── style.css
└── index.js
实现组件
1、安装依赖
npm install react react-dom
2、编写 button 组件
// src/components/button/index.js
import * as React from "react";
import "./style.css";
const Button = (props) => {
const handleClick = () => {
props.onClick && props.onClick();
};
return (
<button className="pp-button" onClick={handleClick}>
{props.children}
</button>
);
};
export default Button;
// src/components/button/style.css
.pp-button {
border: none;
padding: 10px 15px;
font-size: 14px;
}
3、编写 hello 组件
// src/components/hello/index.js
import * as React from "react";
import "./style.css";
const Hello = (props) => {
return (
<div className="pp-hello">
hello <span className="pp-name">{props.name}</span>
</div>
);
};
export default Hello;
// src/components/hello/style.css
.pp-hello {
font-size: 16px;
}
.pp-hello .pp-name {
color: red;
}
4、导出组件
// src/components/index.js
export { default as Button } from "./button";
export { default as Hello } from "./hello";
使用 parcel 运行项目
1、安装依赖
npm install parcel-bundler --save-dev
npm install @babel/preset-react --save-dev
2、创建 .babelrc 文件
{
"presets": ["@babel/preset-react"]
}
3、创建入口文件
// src/index.html
<html>
<body>
<div id="root"></div>
<script src="./index.js"></script>
</body>
</html>
// src/index.js
import React from "react";
import ReactDOM from "react-dom";
import { Button, Hello } from "./components";
const App = () => {
return (
<>
<section>
<Button onClick={() => alert('click')}>click me</Button>
</section>
<section>
<Hello name="jack" />
</section>
</>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
4、更新package.json
"scripts": {
"dev": "parcel src/index.html",
},
5、运行项目
npm run dev
使用 rollup 打包项目
1、安装 rollup
npm install rollup --save-dev
2、安装 rollup 插件
npm install @rollup/plugin-node-resolve --save-dev
npm install @rollup/plugin-commonjs --save-dev
npm install rollup-plugin-babel --save-dev
npm intall rollup-plugin-postcss --save-dev
rollup插件
1、插件 @rollup/plugin-node-resolve
@rollup/plugin-node-resolve,告诉Rollup如何查找外部模块。如果引入第三方模块,会将第三方模块一起打包。
未使用 @rollup/plugin-node-resolve时,会报一个警告
我们打包出来的文件里,react并没有包含在内。
使用 @rollup/plugin-node-resolve 的配置:
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: [resolve()]
};
2、@rollup/plugin-commonjs
@rollup/plugin-commonjs,将CommonJS转换为ES2015。
有些库公开了ES模块,您可以按原样导入这些模块。但目前,NPM上的大多数包都是以CommonJS模块的形式公开的。在此之前,我们需要先将CommonJS转换为ES2015,然后Rollup才能处理它们。
@rollup/plugin-commonjs插件就是这样做的。
请注意,大多数时候@rollup/plugin-commonjs应该在其他插件转换模块之前使用——这是为了防止其他插件做出破坏CommonJS检测的更改。这个规则的一个例外是Babel插件,如果你正在使用它,那么把它放在commonjs之前。
未使用 @rollup/plugin-commonjs时,打包会报错
使用 @rollup/plugin-commonjs 的配置:
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from "@rollup/plugin-commonjs";
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: [
commonjs(),
resolve()
]
};
3、 rollup-plugin-postcss
rollup-plugin-postcss,rollup与postcss的无缝集成。
未使用rollup-plugin-postcss,打包会报错
使用 rollup-plugin-postcss 的配置:
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from "@rollup/plugin-commonjs";
import postcss from 'rollup-plugin-postcss';
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: [
commonjs(),
resolve(),
postcss()
]
};
4、rollup-plugin-babel
rollup-plugin-babel,rollup与babel的无缝集成。
未使用 rollup-plugin-babel,打包会报错
使用 rollup-plugin-babel 的配置:
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from "@rollup/plugin-commonjs";
import postcss from 'rollup-plugin-postcss';
import babel from "rollup-plugin-babel";
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: [
babel({
exclude: "node_modules/**",
presets: ["@babel/preset-react"],
}),
commonjs(),
resolve(),
postcss()
]
};
rollup 配置文件
rollup.config.js
import commonjs from "@rollup/plugin-commonjs";
import resolve from "@rollup/plugin-node-resolve";
import postcss from 'rollup-plugin-postcss';
import babel from "rollup-plugin-babel";
export default {
input: "./src/components/index.js",
output: [
{
format: "cjs",
dir: "cjs",
name: "index.js",
},
{
format: "es",
exports: "named",
dir: "es",
name: "index.js",
},
],
plugins: [
babel({
exclude: "node_modules/**",
presets: ["@babel/preset-react"],
}),
commonjs(),
resolve(),
postcss()
],
};
output核心参数:
// required (can be an array, for multiple outputs)
output: {
// core output options
dir,
file,
format, // required
globals,
name,
plugins,
}
按组件打包
rollup.config.js
import commonjs from "@rollup/plugin-commonjs";
import resolve from "@rollup/plugin-node-resolve";
import postcss from "rollup-plugin-postcss";
import babel from "rollup-plugin-babel";
import path from "path";
import fs from "fs-extra";
const plugins = [
babel({
exclude: "node_modules/**",
presets: ["@babel/preset-react"],
}),
commonjs(),
resolve(),
postcss(),
];
//获取所有组件
const getComponents = async () => {
const componentsPath = path.join(__dirname, "src/components");
//读取目录下的内容
const files = await fs.readdir(componentsPath);
// console.log(files); //[ 'button', 'hello', 'index.js' ]
const components = await Promise.all(
files.map(async (name) => {
//组件目录
const comPath = path.join(componentsPath, name);
//组件入口文件
const entry = path.join(comPath, "index.js");
//获取当前文件信息
const stat = await fs.stat(comPath);
//不是目录,直接返回
if (!stat.isDirectory()) {
return null;
}
//判断文件是否存在
const hasFile = await fs.pathExists(entry);
if (!hasFile) {
return null;
}
const result = { name, url: entry };
// console.log(result);
// {
// name: 'button',
// url: '/pp-ui/src/components/button/index.js'
// }
return result;
})
);
return components;
};
export default async () => {
//删除打包目录
await fs.remove(path.join(__dirname, "es"));
await fs.remove(path.join(__dirname, "cjs"));
await fs.remove(path.join(__dirname, "dist"));
//获取组件列表
const components = await getComponents();
//组件目录文件打包
const componentList = components
.filter((comp) => comp)
.map(({ name, url }) => ({
input: { [name]: url },
output: [
{
format: "cjs",
dir: "cjs",
entryFileNames: "[name]/index.js",
exports: "named",
},
{
format: "es",
dir: "es",
entryFileNames: "[name]/index.js",
exports: "named",
},
],
plugins,
}));
//组件入口文件打包
const componetIndex = {
input: "./src/components/index.js",
output: [
{
format: "cjs",
dir: "cjs",
name: "index.js",
},
{
format: "es",
dir: "es",
name: "index.js",
},
],
plugins,
};
return [...componentList, componetIndex];
};
公共依赖不打包
const external = (id) => /^react|react-dom|classnames/.test(id);
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: [],
// indicate which modules should be treated as external
external
};
更新package.json
"peerDependencies": {
"classnames": "^2.3.1",
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
按环境打包
1、安装 cross-env
npm install --save-dev cross-env
2、生产环境 压缩 代码
npm install rollup-plugin-terser --save-dev
3、更新 package.json
"scripts": {
"build": "npm run build:prod",
"build:dev": "cross-env BUILD_ENV=development rollup -c",
"build:prod": "cross-env BUILD_ENV=production rollup -c"
},
4、更新rollup.config.js
import { terser } from 'rollup-plugin-terser';
const isProd = process.env.BUILD_ENV === 'production';
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: [
isProd ? terser() : null
],
};
提取CSS文件
import postcss from "rollup-plugin-postcss";
const isProd = process.env.BUILD_ENV === "production";
export default {
input: "src/main.js",
output: {
file: "bundle.js",
format: "cjs",
},
plugins: [
isProd
? postcss({
extract: true,
minimize: true,
})
: postcss(),
],
};
配置package.json
1、配置入口文件
{
"main": "dist/index.js",
"module": "es/index.js",
}
pkg.main 字段指向的是commonjs模块; pkg.module 字段指向的是es6模块;
2、发布文件配置(files)
files 字段用于描述我们使用 npm publish 命令后推送到 npm 服务器的文件列表,如果指定文件夹,则文件夹内的所有内容都会包含进来
{
"files": [
"/dist",
"/es"
]
}
聊聊 package.json 文件中的 module 字段 zhuanlan.zhihu.com/p/34164963
package.json 中的 Module 字段是干嘛的 github.com/sunyongjian…
package.json 文件详解 zhuanlan.zhihu.com/p/148089474
发布npm
1、注册账号 www.npmjs.com/signup
2、进入项目目录,执行 npm login,输入用户名和密码;
登录成功会输出:
Logged in as pengjielee on https://registry.npmjs.org/
3、执行 npm publish
npm常见发布错误
1、发布包名已存在
发布之前,可以先查找 www.npmjs.com/一下是否存在
2、注册邮箱未核验