发布npm之前增加打包工具构建

master
LiuJiaNan 2025-12-25 14:30:17 +08:00
parent e9ce2d0b98
commit 69f83b0adc
152 changed files with 379 additions and 11 deletions

View File

@ -0,0 +1,15 @@
{
"permissions": {
"allow": [
"Bash(npm install:*)",
"Bash(npm run build)",
"Bash(wait:*)",
"Bash(tree:*)",
"Bash(cat:*)",
"Bash(git rm:*)",
"Bash(git check-ignore:*)"
],
"deny": [],
"ask": []
}
}

14
.gitignore vendored
View File

@ -1,7 +1,21 @@
# 源文件测试目录
/src/test/
/target/
# 构建输出(根目录的构建产物)
/components/
/hooks/
/utils/
/regular/
/enum/
/json/
/css/
# IDE
.idea
# 依赖
/node_modules
*.local
package-lock.json
yarn.lock

View File

@ -1,3 +1,7 @@
# 源文件目录(不要发布)
src/
rollup.config.js
# 开发相关文件
.eslintrc.cjs
.eslintignore

View File

@ -11,4 +11,8 @@ yarn add zy-react-library
### v1.0.0 (2025-10-22)
- 🎉 初始版本发布
- 🎉 初始版本发布
### v1.1.2 (2025-12-25)
- 🎉 优化编译效果

View File

@ -20,6 +20,9 @@
"node": ">=18.0.0"
},
"scripts": {
"build": "rollup -c",
"build:watch": "rollup -c -w",
"prepublishOnly": "npm run build",
"postinstall": "echo 'Thanks for using our component library!'"
},
"dependencies": {
@ -37,5 +40,15 @@
"react": "^18.3.1",
"react-pdf": "^10.2.0",
"react-signature-canvas": "^1.1.0-alpha.2"
},
"devDependencies": {
"@babel/core": "^7.28.5",
"@babel/preset-react": "^7.28.5",
"@rollup/plugin-babel": "^6.1.0",
"@rollup/plugin-commonjs": "^29.0.0",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^16.0.3",
"glob": "^13.0.0",
"rollup": "^4.54.0"
}
}

288
rollup.config.js Normal file
View File

@ -0,0 +1,288 @@
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
import babel from '@rollup/plugin-babel';
import { readFileSync, existsSync } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { glob } from 'glob';
// 获取当前文件所在目录的绝对路径
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// 读取 package.json用于获取依赖列表
const pkg = JSON.parse(readFileSync('./package.json', 'utf-8'));
/**
* 收集所有的入口文件
*
* 遍历指定目录查找所有 .js 文件作为打包入口
* 注意json 目录被排除因为 JSON 文件直接复制不作为入口处理
*
* @returns {Object} 入口文件对象格式{ 'components/Table/index.js': '/absolute/path/Table/index.js' }
*/
function getEntryFiles() {
const entries = {};
const baseDir = __dirname;
const srcDir = path.join(baseDir, 'src');
// 定义需要处理的目录排除jsonjson文件直接复制不转换
const dirs = ['components', 'hooks', 'utils', 'regular', 'enum'];
dirs.forEach(dir => {
const dirPath = path.join(srcDir, dir);
if (existsSync(dirPath)) {
// 递归查找当前目录下所有 .js 文件
const files = glob.sync('**/*.js', {
cwd: dirPath, // 在 src/xxx 目录中查找
absolute: false // 返回相对路径
});
// 为每个文件创建入口映射
files.forEach(file => {
// key: 保留源文件的相对路径(包括目录和文件名),如 'components/Table/index.js'
// value: src 目录下文件的绝对路径
const key = path.join(dir, file);
entries[key] = path.join(srcDir, dir, file);
});
}
});
return entries;
}
/**
* Babel 配置
*
* 只转换 JSX 语法不转译 ES6+ 语法
* 这样可以保持代码的现代性减少构建时间
*/
const babelConfig = {
// 将 Babel helpers 捆绑到每个文件中(避免重复引用)
babelHelpers: 'bundled',
// 排除 node_modules 目录,不进行处理
exclude: 'node_modules/**',
// 支持的文件扩展名
extensions: ['.js', '.jsx', '.ts', '.tsx'],
// 使用的预设和插件
presets: [
['@babel/preset-react', {
// 使用新的 JSX 转换方式,自动导入 JSX
runtime: 'automatic'
}]
],
plugins: []
};
/**
* 自定义插件复制类型声明文件和样式文件
*
* 功能
* 1. 复制 .d.ts 类型声明文件
* 2. 复制 .less/.css 等样式文件保持原始格式
* 3. 复制 .json 数据文件保持原始格式
* 4. 复制 css 文件夹
*
* 注意所有源文件都在 src/ 目录构建输出到根目录
*/
const copyTypesPlugin = () => ({
name: 'copy-types',
// 在生成 bundle 时执行
generateBundle() {
const srcDir = path.join(__dirname, 'src');
const dirs = ['components', 'hooks', 'utils', 'regular', 'enum', 'json'];
const this$1 = this;
// 处理每个目录
dirs.forEach(dir => {
const dirPath = path.join(srcDir, dir);
if (existsSync(dirPath)) {
// ===== 1. 复制类型声明文件 (.d.ts) =====
const dtsFiles = glob.sync('**/*.d.ts', {
cwd: dirPath,
absolute: true
});
dtsFiles.forEach(file => {
const relativePath = path.relative(dirPath, file);
const content = readFileSync(file, 'utf-8');
// 将文件添加到根目录
this$1.emitFile({
type: 'asset',
fileName: path.join(dir, relativePath),
source: content
});
});
// ===== 2. 复制样式文件 (.less, .css, .scss, .sass) =====
const styleFiles = glob.sync('**/*.{less,css,scss,sass}', {
cwd: dirPath,
absolute: true
});
styleFiles.forEach(file => {
const relativePath = path.relative(dirPath, file);
const content = readFileSync(file, 'utf-8');
// 将样式文件添加到根目录,保持原始格式
this$1.emitFile({
type: 'asset',
fileName: path.join(dir, relativePath),
source: content
});
});
}
});
// ===== 3. 复制 json 文件夹(保持原始格式,不转换) =====
const jsonDir = path.join(srcDir, 'json');
if (existsSync(jsonDir)) {
const jsonFiles = glob.sync('**/*.json', {
cwd: jsonDir,
absolute: true
});
jsonFiles.forEach(file => {
const relativePath = path.relative(jsonDir, file);
const content = readFileSync(file, 'utf-8');
// 将 JSON 文件添加到根目录
this$1.emitFile({
type: 'asset',
fileName: path.join('json', relativePath),
source: content
});
});
}
// ===== 4. 复制 css 文件夹 =====
const cssDir = path.join(srcDir, 'css');
if (existsSync(cssDir)) {
const cssFiles = glob.sync('**/*', {
cwd: cssDir,
absolute: true,
nodir: true // 不包括目录本身
});
cssFiles.forEach(file => {
const relativePath = path.relative(cssDir, file);
const content = readFileSync(file, 'utf-8');
this$1.emitFile({
type: 'asset',
fileName: path.join('css', relativePath),
source: content
});
});
}
}
});
/**
* Rollup 插件列表
*
* 按照执行顺序排列
* 1. resolve - 解析模块路径
* 2. babel - 转换 JSX
* 3. commonjs - 转换 CommonJS 模块
* 4. json - 解析 JSON 导入但被标记为 external不会实际转换
* 5. copyTypesPlugin - 复制类型和样式文件
*/
const plugins = [
// 模块解析插件 - 解析 node_modules 中的模块
resolve({
extensions: ['.js', '.jsx', '.ts', '.tsx'],
browser: true // 浏览器环境优先
}),
// Babel 转换插件 - 只转换 JSX
babel(babelConfig),
// CommonJS 转换插件 - 允许导入 CommonJS 模块
commonjs({
transformMixedEsModules: true // 转换混合的 ES 模块
}),
// JSON 插件 - 处理 JSON 导入(配合 external 使用)
json(),
// 自定义插件 - 复制类型和样式文件
copyTypesPlugin()
];
/**
* External 函数
*
* 判断模块是否应该标记为"外部依赖"
* 外部依赖不会被打包进 bundle而是保留 import 语句
*
* @param {string} id - 模块标识符
* @returns {boolean} - true 表示外部依赖不打包
*/
const external = (id) => {
// 1. 样式文件标记为外部 -> 保留 import 语句
// 原因:样式文件需要消费者项目配置自己的加载器来处理
// 保持 Less 变量(如 @{ant-prefix})不被替换
if (id.endsWith('.less') || id.endsWith('.css') || id.endsWith('.scss') || id.endsWith('.sass')) {
return true;
}
// 2. JSON 文件标记为外部 -> 直接使用原始 .json 文件
// 原因:避免将 JSON 转换成 JS 模块,保持原始格式
// 例如35MB 的 area.json 不会被转换成 56MB 的 area.json.js
if (id.endsWith('.json')) {
return true;
}
// 3. npm 依赖包标记为外部 -> 不打包到 bundle 中
// 原因:减少 bundle 体积,避免版本冲突,让消费者项目自己管理依赖
// 从 package.json 的 dependencies 中读取依赖列表
const dependencies = Object.keys(pkg.dependencies || {});
return dependencies.some(dep => id === dep || id.startsWith(dep + '/'));
};
/**
* 创建 Rollup 配置的辅助函数
*
* @param {string} outputDir - 输出目录
* @param {string} format - 输出格式'esm' 'cjs'
* @param {Array} plugins - 插件列表
* @returns {Object} Rollup 配置对象
*/
function createConfig(outputDir, format, plugins) {
return {
// 入口文件对象
input: getEntryFiles(),
// 输出配置
output: {
dir: outputDir, // 输出目录
format: format, // 输出格式:'esm' 或 'cjs'
preserveModules: true, // 保留模块结构,不打包成单个文件
preserveModulesRoot: './', // 保留模块结构的根目录
entryFileNames: '[name]', // 入口文件名:[name] 保留原始文件名(包括 .js 后缀)
exports: 'named' // 导出命名导出
},
// 外部依赖判断函数
external,
// 插件列表
plugins
};
}
/**
* 导出配置
*
* 只输出 ESM 格式到根目录components/, hooks/, utils/
*/
export default createConfig('.', 'esm', plugins);

View File

@ -51,11 +51,11 @@ const FormBuilder = (props) => {
/>
</Row>
{showActionButtons && (
<>
<div style={{ transform: 'scale(1)', margin: '0px -44px' }}>
<div style={{ height: "52px" }}></div>
<Row
gutter={gutter}
style={{ textAlign: "center", backgroundColor: "rgb(241, 241, 242)", margin: "0px -44px", padding: "10px 0", position: "fixed", bottom: "0", width: "100%" }}
style={{ textAlign: "center", backgroundColor: "rgb(241, 241, 242)", padding: "10px 0", position: "fixed", bottom: "0", width: "100%" }}
>
<Col span={24} style={{ textAlign: "center" }}>
{customActionButtons || (
@ -75,7 +75,7 @@ const FormBuilder = (props) => {
)}
</Col>
</Row>
</>
</div>
)}
</Form>
</Spin>

View File

@ -36,7 +36,15 @@ const MapSelector = (props) => {
// 初始化地图
const initMap = async () => {
if (!window.BMapGL) {
await dynamicLoadJs("https://api.map.baidu.com/api?v=1.0&type=webgl&ak=OElqFYoKiAH8KFtph8ftLKF5NlNrbCUr&callback=initialize");
if (window?.base?.loadDynamicResource) {
await window.base.loadDynamicResource({
url: "https://api.map.baidu.com/api?v=1.0&type=webgl&ak=OElqFYoKiAH8KFtph8ftLKF5NlNrbCUr&callback=initialize",
type: "script",
});
}
else {
await dynamicLoadJs("https://api.map.baidu.com/api?v=1.0&type=webgl&ak=OElqFYoKiAH8KFtph8ftLKF5NlNrbCUr&callback=initialize");
}
}
setLoading(true);

View File

@ -26,9 +26,9 @@ function Page(props) {
</div>
{
(isShowAllAction && isShowFooter) && (
<>
<div style={{ transform: 'scale(1)', margin: '0px -44px' }}>
<div style={{ height: "52px" }}></div>
<div style={{ textAlign: "center", backgroundColor: "rgb(241, 241, 242)", margin: "0 -20px", padding: "10px 0", position: "fixed", bottom: "0", width: "100%" }}>
<div style={{ textAlign: "center", backgroundColor: "rgb(241, 241, 242)", padding: "10px 0", position: "fixed", bottom: "0", width: "100%" }}>
{customActionButtons || (
<Space>
{extraActionButtons}
@ -38,7 +38,7 @@ function Page(props) {
</Space>
)}
</div>
</>
</div>
)
}
</div>

Some files were not shown because too many files have changed in this diff Show More