vite-plugin-ops 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) suileyan
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) suileyan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,409 +1,409 @@
1
- # vite-plugin-ops
2
-
3
- **O**ptimized **P**ackaging **S**trategy - 一个智能的 Vite 分包优化插件
4
-
5
- [![npm version](https://img.shields.io/npm/v/vite-plugin-ops.svg)](https://www.npmjs.com/package/vite-plugin-ops)
6
- [![License](https://img.shields.io/npm/l/vite-plugin-ops.svg)](https://github.com/suileyan/vite-plugin-ops/blob/main/LICENSE)
7
-
8
- ## 特性
9
-
10
- - **智能分包策略** - 三种预设策略适配不同场景
11
- - **自动识别依赖** - 无需手动配置,自动读取 package.json
12
- - **框架预设** - 内置主流框架和库的最佳分包方案
13
- - **高度可配置** - 支持自定义分包规则
14
- - **优先级系统** - 灵活的匹配优先级机制
15
- - **资源分类** - 自动将 CSS、图片、字体分类存放
16
- - **零配置可用** - 开箱即用,合理的默认配置
17
-
18
- ## 安装
19
-
20
- ```bash
21
- npm install vite-plugin-ops -D
22
- # 或
23
- pnpm add vite-plugin-ops -D
24
- # 或
25
- yarn add vite-plugin-ops -D
26
- ```
27
-
28
- ## 快速开始
29
-
30
- ### 基础使用
31
-
32
- ```typescript
33
- // vite.config.ts
34
- import { defineConfig } from 'vite'
35
- import vue from '@vitejs/plugin-vue'
36
- import OPS from 'vite-plugin-ops'
37
-
38
- export default defineConfig({
39
- plugins: [
40
- vue(),
41
- OPS() // 使用默认配置
42
- ]
43
- })
44
- ```
45
-
46
- 插件会自动:
47
- - 将 node_modules 中的依赖智能分包
48
- - 将 CSS 文件放入 `css/` 目录
49
- - 将图片放入 `img/` 目录
50
- - 将字体放入 `fonts/` 目录
51
- - 将其他资源放入 `assets/` 目录
52
-
53
- ## 分包策略
54
-
55
- 插件提供三种分包策略,适用于不同场景:
56
-
57
- ### 1. Balanced(平衡 - 默认推荐)
58
-
59
- 适合大多数生产环境,平衡构建速度和加载性能。
60
-
61
- ```typescript
62
- OPS({
63
- strategy: 'balanced' // 默认值,可省略
64
- })
65
- ```
66
-
67
- **特点:**
68
- - 大型库独立分包(React、Vue、Antd、Echarts 等)
69
- - 中型库按类型分组(工具库、图标库、表单库等)
70
- - 小型库合并到 vendor
71
- - 典型输出:5-15 个 chunk
72
-
73
- **适用场景:** 生产环境、中大型项目
74
-
75
- ### 2. Aggressive(激进)
76
-
77
- 每个依赖都独立分包,适合开发调试。
78
-
79
- ```typescript
80
- OPS({
81
- strategy: 'aggressive'
82
- })
83
- ```
84
-
85
- **特点:**
86
- - 每个依赖独立成一个 chunk
87
- - 便于查看单个依赖的体积
88
- - 可能产生大量小文件
89
- - 典型输出:20-50+ 个 chunk
90
-
91
- **适用场景:** 开发环境、依赖分析
92
-
93
- ### 3. Conservative(保守)
94
-
95
- 最小化分包,减少 HTTP 请求。
96
-
97
- ```typescript
98
- OPS({
99
- strategy: 'conservative'
100
- })
101
- ```
102
-
103
- **特点:**
104
- - 只分离超大型库(React、Vue、Antd、Echarts 等)
105
- - 其他库合并到 vendor
106
- - 减少 HTTP 请求数量
107
- - 典型输出:3-8 个 chunk
108
-
109
- **适用场景:** 小型项目、HTTP/1.x 环境
110
-
111
- ## 配置选项
112
-
113
- ### 完整配置示例
114
-
115
- ```typescript
116
- OPS({
117
- // 分包策略
118
- strategy: 'balanced', // 'aggressive' | 'balanced' | 'conservative'
119
-
120
- // 是否覆盖用户已有的 rollupOptions.output 配置
121
- override: false,
122
-
123
- // 最小分包大小(KB),仅在 balanced 和 conservative 策略下生效
124
- minSize: 50,
125
-
126
- // 自定义分组规则
127
- groups: {
128
- // 将 lodash 相关库独立分包
129
- 'lodash': ['lodash', 'lodash-es'],
130
-
131
- // 使用正则匹配
132
- 'my-ui': [/my-ui-library/],
133
-
134
- // 将多个相关库分到一组
135
- 'charts': ['echarts', 'chart.js', 'd3']
136
- }
137
- })
138
- ```
139
-
140
- ### 配置项说明
141
-
142
- | 参数 | 类型 | 默认值 | 说明 |
143
- |------|------|--------|------|
144
- | `strategy` | `'aggressive' \| 'balanced' \| 'conservative'` | `'balanced'` | 分包策略 |
145
- | `override` | `boolean` | `false` | 是否覆盖已有配置 |
146
- | `minSize` | `number` | `50` | 最小分包大小(KB) |
147
- | `groups` | `Record<string, (string \| RegExp)[]>` | - | 自定义分组规则 |
148
-
149
- ## 内置预设
150
-
151
- 插件内置了主流框架和库的分包预设:
152
-
153
- ### UI 框架
154
- - **React**: react, react-dom
155
- - **Vue**: vue, @vue/*
156
- - **Angular**: @angular/*
157
- - **Svelte**: svelte
158
-
159
- ### UI 组件库
160
- - **Ant Design**: antd, @ant-design/*
161
- - **Element Plus**: element-plus
162
- - **Element UI**: element-ui
163
- - **Naive UI**: naive-ui
164
- - **Arco Design**: @arco-design/*
165
- - **Material-UI**: @mui/*, @material-ui/*
166
- - **Chakra UI**: @chakra-ui/*
167
-
168
- ### 工具库
169
- - **Lodash**: lodash, lodash-es
170
- - **Axios**: axios
171
- - **Moment**: moment
172
- - **Day.js**: dayjs
173
-
174
- ### 可视化库
175
- - **Echarts**: echarts
176
- - **D3**: d3
177
- - **Chart.js**: chart.js
178
-
179
- ### 3D/游戏引擎
180
- - **Three.js**: three
181
- - **Babylon.js**: @babylonjs/*
182
-
183
- ### 其他分组
184
- - **工具组**: @vueuse/*, ahooks, react-use
185
- - **图标组**: @iconify/*, @ant-design/icons, lucide-react
186
- - **表单组**: react-hook-form, formik, async-validator
187
- - **国际化**: i18next, react-i18next, vue-i18n
188
-
189
- ## 输出结构
190
-
191
- 构建后的文件结构:
192
-
193
- ```
194
- dist/
195
- ├── js/
196
- │ ├── index-[hash].js # 入口文件
197
- │ ├── vendor-[hash].js # 通用依赖
198
- │ ├── vue-[hash].js # Vue 相关
199
- │ ├── antd-[hash].js # Ant Design
200
- │ └── echarts-[hash].js # Echarts
201
- ├── css/
202
- │ └── index-[hash].css # 样式文件
203
- ├── img/
204
- │ └── logo-[hash].png # 图片资源
205
- ├── fonts/
206
- │ └── roboto-[hash].woff2 # 字体文件
207
- └── assets/
208
- └── data-[hash].json # 其他资源
209
- ```
210
-
211
- ## 使用场景
212
-
213
- ### 场景 1: React + Ant Design 项目
214
-
215
- ```typescript
216
- import OPS from 'vite-plugin-ops'
217
-
218
- export default {
219
- plugins: [
220
- react(),
221
- OPS({
222
- strategy: 'balanced',
223
- groups: {
224
- // 将 Ant Design 图标单独分包
225
- 'antd-icons': ['@ant-design/icons']
226
- }
227
- })
228
- ]
229
- }
230
- ```
231
-
232
- ### 场景 2: Vue 3 + Element Plus 项目
233
-
234
- ```typescript
235
- import OPS from 'vite-plugin-ops'
236
-
237
- export default {
238
- plugins: [
239
- vue(),
240
- OPS({
241
- strategy: 'balanced'
242
- // 插件会自动检测 Vue 并创建 vue 分组
243
- })
244
- ]
245
- }
246
- ```
247
-
248
- ### 场景 3: 数据可视化项目
249
-
250
- ```typescript
251
- import OPS from 'vite-plugin-ops'
252
-
253
- export default {
254
- plugins: [
255
- OPS({
256
- strategy: 'balanced',
257
- groups: {
258
- // 将所有图表库分到一组
259
- 'charts': ['echarts', 'd3', 'chart.js', '@antv/g2']
260
- }
261
- })
262
- ]
263
- }
264
- ```
265
-
266
- ### 场景 4: 多页面应用
267
-
268
- ```typescript
269
- import OPS from 'vite-plugin-ops'
270
-
271
- export default {
272
- build: {
273
- rollupOptions: {
274
- input: {
275
- main: 'index.html',
276
- admin: 'admin.html'
277
- }
278
- }
279
- },
280
- plugins: [
281
- OPS({
282
- strategy: 'conservative', // 减少公共依赖重复
283
- override: false // 不覆盖多入口配置
284
- })
285
- ]
286
- }
287
- ```
288
-
289
- ## 高级用法
290
-
291
- ### 自定义分组优先级
292
-
293
- 插件使用优先级系统来处理分组匹配:
294
-
295
- 1. **优先级 100**: 自定义 `groups` 配置
296
- 2. **优先级 90**: 插件自动检测(如 Vue)
297
- 3. **优先级 80**: 大型库预设
298
- 4. **优先级 70**: 中型库分组
299
- 5. **优先级 50**: aggressive 策略的单独依赖
300
- 6. **默认**: vendor 组
301
-
302
- ### 与现有配置合并
303
-
304
- ```typescript
305
- export default {
306
- build: {
307
- rollupOptions: {
308
- output: {
309
- // 你的自定义配置
310
- entryFileNames: 'my-entry-[hash].js'
311
- }
312
- }
313
- },
314
- plugins: [
315
- OPS({
316
- override: false // 保留你的 entryFileNames 配置
317
- })
318
- ]
319
- }
320
- ```
321
-
322
- ### 正则表达式匹配
323
-
324
- ```typescript
325
- OPS({
326
- groups: {
327
- // 匹配所有 @babel 开头的包
328
- 'babel': [/\/@babel\//],
329
-
330
- // 匹配 lodash 但不包括 lodash-es
331
- 'lodash': [/\/lodash(?!-es)/],
332
-
333
- // 组合字符串和正则
334
- 'ui-libs': ['antd', /element-/]
335
- }
336
- })
337
- ```
338
-
339
- ## 最佳实践
340
-
341
- ### 1. 开发环境使用 aggressive
342
-
343
- ```typescript
344
- export default defineConfig(({ mode }) => ({
345
- plugins: [
346
- OPS({
347
- strategy: mode === 'development' ? 'aggressive' : 'balanced'
348
- })
349
- ]
350
- }))
351
- ```
352
-
353
- ### 2. 分析构建产物
354
-
355
- 使用 `rollup-plugin-visualizer` 查看分包效果:
356
-
357
- ```typescript
358
- import { visualizer } from 'rollup-plugin-visualizer'
359
- import OPS from 'vite-plugin-ops'
360
-
361
- export default {
362
- plugins: [
363
- OPS({ strategy: 'balanced' }),
364
- visualizer({ open: true })
365
- ]
366
- }
367
- ```
368
-
369
- ### 3. 监控构建信息
370
-
371
- 插件会在构建时输出分包信息:
372
-
373
- ```bash
374
- 📦 OPS Chunking Strategy: Balanced (split large libraries)
375
- 📊 Detected 12 chunk groups
376
- ```
377
-
378
- ### 4. 针对性能优化
379
-
380
- 根据实际加载性能调整策略:
381
-
382
- - **首屏加载慢** → 使用 `conservative` 减少请求数
383
- - **大依赖更新频繁** → 使用 `balanced` 独立缓存
384
- - **需要精细控制** → 使用 `aggressive` + 自定义 `groups`
385
-
386
- ## 注意事项
387
-
388
- 1. **仅适用于 Vite 项目** - 此插件基于 Vite 插件系统
389
- 2. **不支持 Webpack** - 需要 Webpack 版本请使用其他工具
390
- 3. **Type 类型包** - 自动忽略 `@types/*` 包
391
- 4. **Monorepo** - 确保在正确的 package.json 位置读取依赖
392
-
393
- ## 贡献
394
-
395
- 欢迎提交 Issue 和 Pull Request!
396
-
397
- ## 许可
398
-
399
- MIT License
400
-
401
- ## 相关链接
402
-
403
- - [Vite 官方文档](https://vitejs.dev/)
404
- - [Rollup 文档](https://rollupjs.org/)
405
- - [问题反馈](https://github.com/suileyan/vite-plugin-ops/issues)
406
-
407
- ---
408
-
409
- Made with by suileyan
1
+ # vite-plugin-ops [![zread](https://img.shields.io/badge/Ask_Zread-_.svg?style=flat&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff)](https://zread.ai/suileyan/vite-plugin-ops)
2
+
3
+ **O**ptimized **P**ackaging **S**trategy - 一个智能的 Vite 分包优化插件
4
+
5
+ [![npm version](https://img.shields.io/npm/v/vite-plugin-ops.svg)](https://www.npmjs.com/package/vite-plugin-ops)
6
+ [![License](https://img.shields.io/npm/l/vite-plugin-ops.svg)](https://github.com/suileyan/vite-plugin-ops/blob/main/LICENSE)
7
+
8
+ ## 特性
9
+
10
+ - **智能分包策略** - 三种预设策略适配不同场景
11
+ - **自动识别依赖** - 无需手动配置,自动读取 package.json
12
+ - **框架预设** - 内置主流框架和库的最佳分包方案
13
+ - **高度可配置** - 支持自定义分包规则
14
+ - **优先级系统** - 灵活的匹配优先级机制
15
+ - **资源分类** - 自动将 CSS、图片、字体分类存放
16
+ - **零配置可用** - 开箱即用,合理的默认配置
17
+
18
+ ## 安装
19
+
20
+ ```bash
21
+ npm install vite-plugin-ops -D
22
+ # 或
23
+ pnpm add vite-plugin-ops -D
24
+ # 或
25
+ yarn add vite-plugin-ops -D
26
+ ```
27
+
28
+ ## 快速开始
29
+
30
+ ### 基础使用
31
+
32
+ ```typescript
33
+ // vite.config.ts
34
+ import { defineConfig } from 'vite'
35
+ import vue from '@vitejs/plugin-vue'
36
+ import OPS from 'vite-plugin-ops'
37
+
38
+ export default defineConfig({
39
+ plugins: [
40
+ vue(),
41
+ OPS() // 使用默认配置
42
+ ]
43
+ })
44
+ ```
45
+
46
+ 插件会自动:
47
+ - 将 node_modules 中的依赖智能分包
48
+ - 将 CSS 文件放入 `css/` 目录
49
+ - 将图片放入 `img/` 目录
50
+ - 将字体放入 `fonts/` 目录
51
+ - 将其他资源放入 `assets/` 目录
52
+
53
+ ## 分包策略
54
+
55
+ 插件提供三种分包策略,适用于不同场景:
56
+
57
+ ### 1. Balanced(平衡 - 默认推荐)
58
+
59
+ 适合大多数生产环境,平衡构建速度和加载性能。
60
+
61
+ ```typescript
62
+ OPS({
63
+ strategy: 'balanced' // 默认值,可省略
64
+ })
65
+ ```
66
+
67
+ **特点:**
68
+ - 大型库独立分包(React、Vue、Antd、Echarts 等)
69
+ - 中型库按类型分组(工具库、图标库、表单库等)
70
+ - 小型库合并到 vendor
71
+ - 典型输出:5-15 个 chunk
72
+
73
+ **适用场景:** 生产环境、中大型项目
74
+
75
+ ### 2. Aggressive(激进)
76
+
77
+ 每个依赖都独立分包,适合开发调试。
78
+
79
+ ```typescript
80
+ OPS({
81
+ strategy: 'aggressive'
82
+ })
83
+ ```
84
+
85
+ **特点:**
86
+ - 每个依赖独立成一个 chunk
87
+ - 便于查看单个依赖的体积
88
+ - 可能产生大量小文件
89
+ - 典型输出:20-50+ 个 chunk
90
+
91
+ **适用场景:** 开发环境、依赖分析
92
+
93
+ ### 3. Conservative(保守)
94
+
95
+ 最小化分包,减少 HTTP 请求。
96
+
97
+ ```typescript
98
+ OPS({
99
+ strategy: 'conservative'
100
+ })
101
+ ```
102
+
103
+ **特点:**
104
+ - 只分离超大型库(React、Vue、Antd、Echarts 等)
105
+ - 其他库合并到 vendor
106
+ - 减少 HTTP 请求数量
107
+ - 典型输出:3-8 个 chunk
108
+
109
+ **适用场景:** 小型项目、HTTP/1.x 环境
110
+
111
+ ## 配置选项
112
+
113
+ ### 完整配置示例
114
+
115
+ ```typescript
116
+ OPS({
117
+ // 分包策略
118
+ strategy: 'balanced', // 'aggressive' | 'balanced' | 'conservative'
119
+
120
+ // 是否覆盖用户已有的 rollupOptions.output 配置
121
+ override: false,
122
+
123
+ // 最小分包大小(KB),仅在 balanced 和 conservative 策略下生效
124
+ minSize: 50,
125
+
126
+ // 自定义分组规则
127
+ groups: {
128
+ // 将 lodash 相关库独立分包
129
+ 'lodash': ['lodash', 'lodash-es'],
130
+
131
+ // 使用正则匹配
132
+ 'my-ui': [/my-ui-library/],
133
+
134
+ // 将多个相关库分到一组
135
+ 'charts': ['echarts', 'chart.js', 'd3']
136
+ }
137
+ })
138
+ ```
139
+
140
+ ### 配置项说明
141
+
142
+ | 参数 | 类型 | 默认值 | 说明 |
143
+ |------|------|--------|------|
144
+ | `strategy` | `'aggressive' \| 'balanced' \| 'conservative'` | `'balanced'` | 分包策略 |
145
+ | `override` | `boolean` | `false` | 是否覆盖已有配置 |
146
+ | `minSize` | `number` | `50` | 最小分包大小(KB) |
147
+ | `groups` | `Record<string, (string \| RegExp)[]>` | - | 自定义分组规则 |
148
+
149
+ ## 内置预设
150
+
151
+ 插件内置了主流框架和库的分包预设:
152
+
153
+ ### UI 框架
154
+ - **React**: react, react-dom
155
+ - **Vue**: vue, @vue/*
156
+ - **Angular**: @angular/*
157
+ - **Svelte**: svelte
158
+
159
+ ### UI 组件库
160
+ - **Ant Design**: antd, @ant-design/*
161
+ - **Element Plus**: element-plus
162
+ - **Element UI**: element-ui
163
+ - **Naive UI**: naive-ui
164
+ - **Arco Design**: @arco-design/*
165
+ - **Material-UI**: @mui/*, @material-ui/*
166
+ - **Chakra UI**: @chakra-ui/*
167
+
168
+ ### 工具库
169
+ - **Lodash**: lodash, lodash-es
170
+ - **Axios**: axios
171
+ - **Moment**: moment
172
+ - **Day.js**: dayjs
173
+
174
+ ### 可视化库
175
+ - **Echarts**: echarts
176
+ - **D3**: d3
177
+ - **Chart.js**: chart.js
178
+
179
+ ### 3D/游戏引擎
180
+ - **Three.js**: three
181
+ - **Babylon.js**: @babylonjs/*
182
+
183
+ ### 其他分组
184
+ - **工具组**: @vueuse/*, ahooks, react-use
185
+ - **图标组**: @iconify/*, @ant-design/icons, lucide-react
186
+ - **表单组**: react-hook-form, formik, async-validator
187
+ - **国际化**: i18next, react-i18next, vue-i18n
188
+
189
+ ## 输出结构
190
+
191
+ 构建后的文件结构:
192
+
193
+ ```
194
+ dist/
195
+ ├── js/
196
+ │ ├── index-[hash].js # 入口文件
197
+ │ ├── vendor-[hash].js # 通用依赖
198
+ │ ├── vue-[hash].js # Vue 相关
199
+ │ ├── antd-[hash].js # Ant Design
200
+ │ └── echarts-[hash].js # Echarts
201
+ ├── css/
202
+ │ └── index-[hash].css # 样式文件
203
+ ├── img/
204
+ │ └── logo-[hash].png # 图片资源
205
+ ├── fonts/
206
+ │ └── roboto-[hash].woff2 # 字体文件
207
+ └── assets/
208
+ └── data-[hash].json # 其他资源
209
+ ```
210
+
211
+ ## 使用场景
212
+
213
+ ### 场景 1: React + Ant Design 项目
214
+
215
+ ```typescript
216
+ import OPS from 'vite-plugin-ops'
217
+
218
+ export default {
219
+ plugins: [
220
+ react(),
221
+ OPS({
222
+ strategy: 'balanced',
223
+ groups: {
224
+ // 将 Ant Design 图标单独分包
225
+ 'antd-icons': ['@ant-design/icons']
226
+ }
227
+ })
228
+ ]
229
+ }
230
+ ```
231
+
232
+ ### 场景 2: Vue 3 + Element Plus 项目
233
+
234
+ ```typescript
235
+ import OPS from 'vite-plugin-ops'
236
+
237
+ export default {
238
+ plugins: [
239
+ vue(),
240
+ OPS({
241
+ strategy: 'balanced'
242
+ // 插件会自动检测 Vue 并创建 vue 分组
243
+ })
244
+ ]
245
+ }
246
+ ```
247
+
248
+ ### 场景 3: 数据可视化项目
249
+
250
+ ```typescript
251
+ import OPS from 'vite-plugin-ops'
252
+
253
+ export default {
254
+ plugins: [
255
+ OPS({
256
+ strategy: 'balanced',
257
+ groups: {
258
+ // 将所有图表库分到一组
259
+ 'charts': ['echarts', 'd3', 'chart.js', '@antv/g2']
260
+ }
261
+ })
262
+ ]
263
+ }
264
+ ```
265
+
266
+ ### 场景 4: 多页面应用
267
+
268
+ ```typescript
269
+ import OPS from 'vite-plugin-ops'
270
+
271
+ export default {
272
+ build: {
273
+ rollupOptions: {
274
+ input: {
275
+ main: 'index.html',
276
+ admin: 'admin.html'
277
+ }
278
+ }
279
+ },
280
+ plugins: [
281
+ OPS({
282
+ strategy: 'conservative', // 减少公共依赖重复
283
+ override: false // 不覆盖多入口配置
284
+ })
285
+ ]
286
+ }
287
+ ```
288
+
289
+ ## 高级用法
290
+
291
+ ### 自定义分组优先级
292
+
293
+ 插件使用优先级系统来处理分组匹配:
294
+
295
+ 1. **优先级 100**: 自定义 `groups` 配置
296
+ 2. **优先级 90**: 插件自动检测(如 Vue)
297
+ 3. **优先级 80**: 大型库预设
298
+ 4. **优先级 70**: 中型库分组
299
+ 5. **优先级 50**: aggressive 策略的单独依赖
300
+ 6. **默认**: vendor 组
301
+
302
+ ### 与现有配置合并
303
+
304
+ ```typescript
305
+ export default {
306
+ build: {
307
+ rollupOptions: {
308
+ output: {
309
+ // 你的自定义配置
310
+ entryFileNames: 'my-entry-[hash].js'
311
+ }
312
+ }
313
+ },
314
+ plugins: [
315
+ OPS({
316
+ override: false // 保留你的 entryFileNames 配置
317
+ })
318
+ ]
319
+ }
320
+ ```
321
+
322
+ ### 正则表达式匹配
323
+
324
+ ```typescript
325
+ OPS({
326
+ groups: {
327
+ // 匹配所有 @babel 开头的包
328
+ 'babel': [/\/@babel\//],
329
+
330
+ // 匹配 lodash 但不包括 lodash-es
331
+ 'lodash': [/\/lodash(?!-es)/],
332
+
333
+ // 组合字符串和正则
334
+ 'ui-libs': ['antd', /element-/]
335
+ }
336
+ })
337
+ ```
338
+
339
+ ## 最佳实践
340
+
341
+ ### 1. 开发环境使用 aggressive
342
+
343
+ ```typescript
344
+ export default defineConfig(({ mode }) => ({
345
+ plugins: [
346
+ OPS({
347
+ strategy: mode === 'development' ? 'aggressive' : 'balanced'
348
+ })
349
+ ]
350
+ }))
351
+ ```
352
+
353
+ ### 2. 分析构建产物
354
+
355
+ 使用 `rollup-plugin-visualizer` 查看分包效果:
356
+
357
+ ```typescript
358
+ import { visualizer } from 'rollup-plugin-visualizer'
359
+ import OPS from 'vite-plugin-ops'
360
+
361
+ export default {
362
+ plugins: [
363
+ OPS({ strategy: 'balanced' }),
364
+ visualizer({ open: true })
365
+ ]
366
+ }
367
+ ```
368
+
369
+ ### 3. 监控构建信息
370
+
371
+ 插件会在构建时输出分包信息:
372
+
373
+ ```bash
374
+ 📦 OPS Chunking Strategy: Balanced (split large libraries)
375
+ 📊 Detected 12 chunk groups
376
+ ```
377
+
378
+ ### 4. 针对性能优化
379
+
380
+ 根据实际加载性能调整策略:
381
+
382
+ - **首屏加载慢** → 使用 `conservative` 减少请求数
383
+ - **大依赖更新频繁** → 使用 `balanced` 独立缓存
384
+ - **需要精细控制** → 使用 `aggressive` + 自定义 `groups`
385
+
386
+ ## 注意事项
387
+
388
+ 1. **仅适用于 Vite 项目** - 此插件基于 Vite 插件系统
389
+ 2. **不支持 Webpack** - 需要 Webpack 版本请使用其他工具
390
+ 3. **Type 类型包** - 自动忽略 `@types/*` 包
391
+ 4. **Monorepo** - 确保在正确的 package.json 位置读取依赖
392
+
393
+ ## 贡献
394
+
395
+ 欢迎提交 Issue 和 Pull Request!
396
+
397
+ ## 许可
398
+
399
+ MIT License
400
+
401
+ ## 相关链接
402
+
403
+ - [Vite 官方文档](https://vitejs.dev/)
404
+ - [Rollup 文档](https://rollupjs.org/)
405
+ - [问题反馈](https://github.com/suileyan/vite-plugin-ops/issues)
406
+
407
+ ---
408
+
409
+ Made with by suileyan
package/dist/index.cjs CHANGED
@@ -51,25 +51,66 @@ var MEDIUM_LIB_GROUPS = {
51
51
  "form": ["react-hook-form", "formik", "async-validator"],
52
52
  "i18n": ["i18next", "react-i18next", "vue-i18n"]
53
53
  };
54
+ var patternCache = /* @__PURE__ */ new Map();
55
+ var MAX_PATH_LENGTH = 2e3;
54
56
  function normalizeId(id) {
55
57
  return id.replace(/\\/g, "/").replace(/%5C/g, "/");
56
58
  }
57
59
  function makeNodeModulesPattern(pkg) {
58
60
  if (pkg instanceof RegExp) {
59
- return (id) => pkg.test(id);
61
+ return (id) => {
62
+ if (id.length > MAX_PATH_LENGTH) {
63
+ console.warn(`[vite-plugin-ops] Path too long (${id.length} chars), skipping: ${id.slice(0, 50)}...`);
64
+ return false;
65
+ }
66
+ return pkg.test(id);
67
+ };
68
+ }
69
+ let re = patternCache.get(pkg);
70
+ if (!re) {
71
+ const scoped = pkg.startsWith("@");
72
+ const escaped = pkg.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
73
+ const base = scoped ? escaped : `(?:@[^/]+/)?${escaped}`;
74
+ re = new RegExp(`/node_modules/(?:[.]pnpm/)?(?:${base})(?:/|@|$)`, "i");
75
+ patternCache.set(pkg, re);
60
76
  }
61
- const scoped = pkg.startsWith("@");
62
- const escaped = pkg.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
63
- const base = scoped ? escaped : `(?:@[^/]+/)?${escaped}`;
64
- const re = new RegExp(`/node_modules/(?:[.]pnpm/)?(?:${base})(?:/|@|$)`, "i");
65
- return (id) => re.test(id);
77
+ return (id) => {
78
+ if (id.length > MAX_PATH_LENGTH) {
79
+ console.warn(`[vite-plugin-ops] Path too long (${id.length} chars), skipping: ${id.slice(0, 50)}...`);
80
+ return false;
81
+ }
82
+ return re.test(id);
83
+ };
84
+ }
85
+ function isValidPackageJson(obj) {
86
+ if (typeof obj !== "object" || obj === null) return false;
87
+ const json = obj;
88
+ if (json.dependencies !== void 0) {
89
+ if (typeof json.dependencies !== "object" || json.dependencies === null) return false;
90
+ for (const val of Object.values(json.dependencies)) {
91
+ if (typeof val !== "string") return false;
92
+ }
93
+ }
94
+ return true;
66
95
  }
67
96
  function readProjectDependencies(cwd) {
68
97
  try {
69
98
  const pkgPath = path__default.default.join(cwd, "package.json");
70
- const json = JSON.parse(fs__default.default.readFileSync(pkgPath, "utf8"));
99
+ const content = fs__default.default.readFileSync(pkgPath, "utf8");
100
+ const json = JSON.parse(content);
101
+ if (!isValidPackageJson(json)) {
102
+ console.warn("[vite-plugin-ops] Invalid package.json format: dependencies field is malformed");
103
+ return /* @__PURE__ */ new Set();
104
+ }
71
105
  return new Set(Object.keys(json.dependencies || {}));
72
- } catch {
106
+ } catch (error) {
107
+ if (error instanceof SyntaxError) {
108
+ console.warn("[vite-plugin-ops] Failed to parse package.json: Invalid JSON format");
109
+ } else if (error.code === "ENOENT") {
110
+ console.warn("[vite-plugin-ops] package.json not found in:", cwd);
111
+ } else if (process.env.DEBUG) {
112
+ console.warn("[vite-plugin-ops] Failed to read package.json:", error);
113
+ }
73
114
  return /* @__PURE__ */ new Set();
74
115
  }
75
116
  }
package/dist/index.d.cts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { Plugin } from 'vite';
2
+ export { Plugin as OPSPlugin } from 'vite';
2
3
 
3
4
  type SplitStrategy = 'aggressive' | 'balanced' | 'conservative';
5
+
4
6
  type OPSOptions = {
5
7
  /**
6
8
  * If true, overwrite existing `build.rollupOptions.output.*` fields.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { Plugin } from 'vite';
2
+ export { Plugin as OPSPlugin } from 'vite';
2
3
 
3
4
  type SplitStrategy = 'aggressive' | 'balanced' | 'conservative';
5
+
4
6
  type OPSOptions = {
5
7
  /**
6
8
  * If true, overwrite existing `build.rollupOptions.output.*` fields.
package/dist/index.js CHANGED
@@ -44,25 +44,66 @@ var MEDIUM_LIB_GROUPS = {
44
44
  "form": ["react-hook-form", "formik", "async-validator"],
45
45
  "i18n": ["i18next", "react-i18next", "vue-i18n"]
46
46
  };
47
+ var patternCache = /* @__PURE__ */ new Map();
48
+ var MAX_PATH_LENGTH = 2e3;
47
49
  function normalizeId(id) {
48
50
  return id.replace(/\\/g, "/").replace(/%5C/g, "/");
49
51
  }
50
52
  function makeNodeModulesPattern(pkg) {
51
53
  if (pkg instanceof RegExp) {
52
- return (id) => pkg.test(id);
54
+ return (id) => {
55
+ if (id.length > MAX_PATH_LENGTH) {
56
+ console.warn(`[vite-plugin-ops] Path too long (${id.length} chars), skipping: ${id.slice(0, 50)}...`);
57
+ return false;
58
+ }
59
+ return pkg.test(id);
60
+ };
61
+ }
62
+ let re = patternCache.get(pkg);
63
+ if (!re) {
64
+ const scoped = pkg.startsWith("@");
65
+ const escaped = pkg.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
66
+ const base = scoped ? escaped : `(?:@[^/]+/)?${escaped}`;
67
+ re = new RegExp(`/node_modules/(?:[.]pnpm/)?(?:${base})(?:/|@|$)`, "i");
68
+ patternCache.set(pkg, re);
53
69
  }
54
- const scoped = pkg.startsWith("@");
55
- const escaped = pkg.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
56
- const base = scoped ? escaped : `(?:@[^/]+/)?${escaped}`;
57
- const re = new RegExp(`/node_modules/(?:[.]pnpm/)?(?:${base})(?:/|@|$)`, "i");
58
- return (id) => re.test(id);
70
+ return (id) => {
71
+ if (id.length > MAX_PATH_LENGTH) {
72
+ console.warn(`[vite-plugin-ops] Path too long (${id.length} chars), skipping: ${id.slice(0, 50)}...`);
73
+ return false;
74
+ }
75
+ return re.test(id);
76
+ };
77
+ }
78
+ function isValidPackageJson(obj) {
79
+ if (typeof obj !== "object" || obj === null) return false;
80
+ const json = obj;
81
+ if (json.dependencies !== void 0) {
82
+ if (typeof json.dependencies !== "object" || json.dependencies === null) return false;
83
+ for (const val of Object.values(json.dependencies)) {
84
+ if (typeof val !== "string") return false;
85
+ }
86
+ }
87
+ return true;
59
88
  }
60
89
  function readProjectDependencies(cwd) {
61
90
  try {
62
91
  const pkgPath = path.join(cwd, "package.json");
63
- const json = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
92
+ const content = fs.readFileSync(pkgPath, "utf8");
93
+ const json = JSON.parse(content);
94
+ if (!isValidPackageJson(json)) {
95
+ console.warn("[vite-plugin-ops] Invalid package.json format: dependencies field is malformed");
96
+ return /* @__PURE__ */ new Set();
97
+ }
64
98
  return new Set(Object.keys(json.dependencies || {}));
65
- } catch {
99
+ } catch (error) {
100
+ if (error instanceof SyntaxError) {
101
+ console.warn("[vite-plugin-ops] Failed to parse package.json: Invalid JSON format");
102
+ } else if (error.code === "ENOENT") {
103
+ console.warn("[vite-plugin-ops] package.json not found in:", cwd);
104
+ } else if (process.env.DEBUG) {
105
+ console.warn("[vite-plugin-ops] Failed to read package.json:", error);
106
+ }
66
107
  return /* @__PURE__ */ new Set();
67
108
  }
68
109
  }
package/package.json CHANGED
@@ -1,56 +1,56 @@
1
- {
2
- "name": "vite-plugin-ops",
3
- "version": "0.1.1",
4
- "description": "Vite plugin to organize build outputs and vendor chunking.",
5
- "type": "module",
6
- "license": "MIT",
7
- "author": "suileyan",
8
-
9
- "exports": {
10
- ".": {
11
- "types": "./dist/index.d.ts",
12
- "import": "./dist/index.js",
13
- "require": "./dist/index.cjs"
14
- },
15
- "./package.json": "./package.json"
16
- },
17
- "main": "dist/index.cjs",
18
- "types": "dist/index.d.ts",
19
-
20
- "files": ["dist", "README.md", "LICENSE"],
21
-
22
- "sideEffects": false,
23
- "engines": {
24
- "node": ">=20.19"
25
- },
26
-
27
- "keywords": ["vite", "vite-plugin", "rollup", "chunks", "vendor", "build"],
28
-
29
- "repository": { "type": "git", "url": "git+https://github.com/suileyan/vite-plugin-ops.git" },
30
- "bugs": { "url": "https://github.com/suileyan/vite-plugin-ops/issues" },
31
- "homepage": "https://github.com/suileyan/vite-plugin-ops#readme",
32
-
33
- "peerDependencies": {
34
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
35
- },
36
- "devDependencies": {
37
- "@types/node": "^24.6.0",
38
- "rimraf": "^6.0.1",
39
- "tsup": "^8.5.0",
40
- "typescript": "^5.9.2",
41
- "vite": "^7.1.7",
42
- "rollup": "^4.0.0"
43
- },
44
-
45
- "scripts": {
46
- "build": "tsup",
47
- "dev": "tsup --watch --sourcemap",
48
- "clean": "rimraf dist || rmdir /s /q dist",
49
- "prepublishOnly": "npm run clean && npm run build"
50
- },
51
-
52
- "publishConfig": {
53
- "access": "public",
54
- "registry": "https://registry.npmjs.org/"
55
- }
56
- }
1
+ {
2
+ "name": "vite-plugin-ops",
3
+ "version": "0.1.2",
4
+ "description": "Vite plugin to organize build outputs and vendor chunking.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "suileyan",
8
+
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
17
+ "main": "dist/index.cjs",
18
+ "types": "dist/index.d.ts",
19
+
20
+ "files": ["dist", "README.md", "LICENSE"],
21
+
22
+ "sideEffects": false,
23
+ "engines": {
24
+ "node": ">=20.19"
25
+ },
26
+
27
+ "keywords": ["vite", "vite-plugin", "rollup", "chunks", "vendor", "build"],
28
+
29
+ "repository": { "type": "git", "url": "git+https://github.com/suileyan/vite-plugin-ops.git" },
30
+ "bugs": { "url": "https://github.com/suileyan/vite-plugin-ops/issues" },
31
+ "homepage": "https://github.com/suileyan/vite-plugin-ops#readme",
32
+
33
+ "peerDependencies": {
34
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^24.6.0",
38
+ "rimraf": "^6.0.1",
39
+ "tsup": "^8.5.0",
40
+ "typescript": "^5.9.2",
41
+ "vite": "^7.3.1",
42
+ "rollup": "^4.0.0"
43
+ },
44
+
45
+ "scripts": {
46
+ "build": "tsup",
47
+ "dev": "tsup --watch --sourcemap",
48
+ "clean": "rimraf dist || rmdir /s /q dist",
49
+ "prepublishOnly": "npm run clean && npm run build"
50
+ },
51
+
52
+ "publishConfig": {
53
+ "access": "public",
54
+ "registry": "https://registry.npmjs.org/"
55
+ }
56
+ }