vite-plugin-ops 0.1.2 → 1.0.0
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/dist/deps.d.ts +14 -0
- package/dist/deps.d.ts.map +1 -0
- package/dist/index.cjs +139 -84
- package/dist/index.d.cts +14 -2
- package/dist/index.d.ts +9 -36
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +139 -84
- package/dist/matcher.d.ts +43 -0
- package/dist/matcher.d.ts.map +1 -0
- package/dist/presets.d.ts +15 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/types.d.ts +43 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +29 -16
package/dist/deps.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 读取项目依赖列表
|
|
3
|
+
* @param cwd 项目根目录
|
|
4
|
+
* @returns 依赖名称集合
|
|
5
|
+
*/
|
|
6
|
+
export declare function readProjectDependencies(cwd: string): Set<string>;
|
|
7
|
+
/**
|
|
8
|
+
* 检查模式列表是否匹配项目依赖
|
|
9
|
+
* 改进的匹配逻辑:避免误匹配(如 vue 匹配到 vuex)
|
|
10
|
+
* @param patterns 匹配模式列表
|
|
11
|
+
* @param depsArray 依赖数组
|
|
12
|
+
*/
|
|
13
|
+
export declare function hasDependencyMatch(patterns: string[], depsArray: string[]): boolean;
|
|
14
|
+
//# sourceMappingURL=deps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../src/deps.ts"],"names":[],"mappings":"AAwBA;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CA8BhE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAmBnF"}
|
package/dist/index.cjs
CHANGED
|
@@ -8,7 +8,9 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
8
8
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
9
9
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
10
10
|
|
|
11
|
-
// src/
|
|
11
|
+
// src/deps.ts
|
|
12
|
+
|
|
13
|
+
// src/presets.ts
|
|
12
14
|
var COMMON_LARGE_LIBS = {
|
|
13
15
|
// UI Frameworks
|
|
14
16
|
react: ["react", "react-dom"],
|
|
@@ -51,16 +53,46 @@ var MEDIUM_LIB_GROUPS = {
|
|
|
51
53
|
"form": ["react-hook-form", "formik", "async-validator"],
|
|
52
54
|
"i18n": ["i18next", "react-i18next", "vue-i18n"]
|
|
53
55
|
};
|
|
54
|
-
var
|
|
56
|
+
var VERY_LARGE_LIBS = ["react", "vue", "angular", "antd", "element-plus", "echarts", "three"];
|
|
57
|
+
|
|
58
|
+
// src/matcher.ts
|
|
59
|
+
var PRIORITIES = {
|
|
60
|
+
CUSTOM: 100,
|
|
61
|
+
// 用户自定义分组
|
|
62
|
+
DETECTED: 90,
|
|
63
|
+
// 插件检测到的框架
|
|
64
|
+
LARGE_LIB: 80,
|
|
65
|
+
// 大型库
|
|
66
|
+
MEDIUM_LIB: 70,
|
|
67
|
+
// 中型库
|
|
68
|
+
ALL_DEPS: 50
|
|
69
|
+
// 所有依赖(aggressive 模式)
|
|
70
|
+
};
|
|
55
71
|
var MAX_PATH_LENGTH = 2e3;
|
|
72
|
+
var MAX_CACHE_SIZE = 100;
|
|
73
|
+
var patternCache = /* @__PURE__ */ new Map();
|
|
74
|
+
var cacheKeys = [];
|
|
75
|
+
var logger = {
|
|
76
|
+
warn: (msg) => console.warn(`[vite-plugin-ops] ${msg}`),
|
|
77
|
+
error: (msg) => console.error(`[vite-plugin-ops] ERROR: ${msg}`),
|
|
78
|
+
debug: (msg) => process.env.DEBUG && console.log(`[vite-plugin-ops] DEBUG: ${msg}`)
|
|
79
|
+
};
|
|
56
80
|
function normalizeId(id) {
|
|
57
81
|
return id.replace(/\\/g, "/").replace(/%5C/g, "/");
|
|
58
82
|
}
|
|
83
|
+
function manageCache() {
|
|
84
|
+
while (cacheKeys.length >= MAX_CACHE_SIZE) {
|
|
85
|
+
const oldestKey = cacheKeys.shift();
|
|
86
|
+
if (oldestKey) {
|
|
87
|
+
patternCache.delete(oldestKey);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
59
91
|
function makeNodeModulesPattern(pkg) {
|
|
60
92
|
if (pkg instanceof RegExp) {
|
|
61
93
|
return (id) => {
|
|
62
94
|
if (id.length > MAX_PATH_LENGTH) {
|
|
63
|
-
|
|
95
|
+
logger.warn(`Path too long (${id.length} chars), skipping: ${id.slice(0, 50)}...`);
|
|
64
96
|
return false;
|
|
65
97
|
}
|
|
66
98
|
return pkg.test(id);
|
|
@@ -68,55 +100,27 @@ function makeNodeModulesPattern(pkg) {
|
|
|
68
100
|
}
|
|
69
101
|
let re = patternCache.get(pkg);
|
|
70
102
|
if (!re) {
|
|
103
|
+
manageCache();
|
|
71
104
|
const scoped = pkg.startsWith("@");
|
|
72
105
|
const escaped = pkg.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
|
|
73
106
|
const base = scoped ? escaped : `(?:@[^/]+/)?${escaped}`;
|
|
74
|
-
|
|
107
|
+
const flags = process.platform === "win32" ? "i" : "";
|
|
108
|
+
re = new RegExp(`/node_modules/(?:[.]pnpm/)?(?:${base})(?:/|@|$)`, flags);
|
|
75
109
|
patternCache.set(pkg, re);
|
|
110
|
+
cacheKeys.push(pkg);
|
|
76
111
|
}
|
|
77
112
|
return (id) => {
|
|
78
113
|
if (id.length > MAX_PATH_LENGTH) {
|
|
79
|
-
|
|
114
|
+
logger.warn(`Path too long (${id.length} chars), skipping: ${id.slice(0, 50)}...`);
|
|
80
115
|
return false;
|
|
81
116
|
}
|
|
82
117
|
return re.test(id);
|
|
83
118
|
};
|
|
84
119
|
}
|
|
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;
|
|
95
|
-
}
|
|
96
|
-
function readProjectDependencies(cwd) {
|
|
97
|
-
try {
|
|
98
|
-
const pkgPath = path__default.default.join(cwd, "package.json");
|
|
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
|
-
}
|
|
105
|
-
return new Set(Object.keys(json.dependencies || {}));
|
|
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
|
-
}
|
|
114
|
-
return /* @__PURE__ */ new Set();
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
120
|
function buildGroupMatchers(options, projectDeps, pluginHints) {
|
|
118
121
|
const matchers = [];
|
|
119
|
-
const strategy = options.strategy
|
|
122
|
+
const strategy = options.strategy;
|
|
123
|
+
const depsArray = Array.from(projectDeps);
|
|
120
124
|
if (options.groups) {
|
|
121
125
|
for (const [name, patterns] of Object.entries(options.groups)) {
|
|
122
126
|
if (patterns && patterns.length) {
|
|
@@ -129,7 +133,7 @@ function buildGroupMatchers(options, projectDeps, pluginHints) {
|
|
|
129
133
|
matchers.push({
|
|
130
134
|
name,
|
|
131
135
|
test: (id) => testers.some((t) => t(id)),
|
|
132
|
-
priority:
|
|
136
|
+
priority: PRIORITIES.CUSTOM
|
|
133
137
|
});
|
|
134
138
|
}
|
|
135
139
|
}
|
|
@@ -146,63 +150,49 @@ function buildGroupMatchers(options, projectDeps, pluginHints) {
|
|
|
146
150
|
matchers.push({
|
|
147
151
|
name,
|
|
148
152
|
test: (id) => testers.some((t) => t(id)),
|
|
149
|
-
priority:
|
|
153
|
+
priority: PRIORITIES.DETECTED
|
|
150
154
|
});
|
|
151
155
|
}
|
|
152
156
|
if (strategy === "aggressive") {
|
|
153
|
-
for (const dep of
|
|
157
|
+
for (const dep of depsArray) {
|
|
154
158
|
if (!dep.startsWith("@types/")) {
|
|
155
159
|
matchers.push({
|
|
156
160
|
name: dep,
|
|
157
161
|
test: makeNodeModulesPattern(dep),
|
|
158
|
-
priority:
|
|
162
|
+
priority: PRIORITIES.ALL_DEPS
|
|
159
163
|
});
|
|
160
164
|
}
|
|
161
165
|
}
|
|
162
166
|
} else if (strategy === "balanced") {
|
|
163
167
|
for (const [groupName, patterns] of Object.entries(COMMON_LARGE_LIBS)) {
|
|
164
|
-
|
|
165
|
-
const pkgName = p.replace(/\//g, "");
|
|
166
|
-
return Array.from(projectDeps).some((dep) => dep.includes(pkgName));
|
|
167
|
-
});
|
|
168
|
-
if (hasAny) {
|
|
168
|
+
if (hasDependencyMatch(patterns, depsArray)) {
|
|
169
169
|
const testers = patterns.map(makeNodeModulesPattern);
|
|
170
170
|
matchers.push({
|
|
171
171
|
name: groupName,
|
|
172
172
|
test: (id) => testers.some((t) => t(id)),
|
|
173
|
-
priority:
|
|
173
|
+
priority: PRIORITIES.LARGE_LIB
|
|
174
174
|
});
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
177
|
for (const [groupName, patterns] of Object.entries(MEDIUM_LIB_GROUPS)) {
|
|
178
|
-
|
|
179
|
-
return Array.from(projectDeps).some(
|
|
180
|
-
(dep) => dep.includes(p.replace(/\//g, "").replace(/\*/g, ""))
|
|
181
|
-
);
|
|
182
|
-
});
|
|
183
|
-
if (hasAny) {
|
|
178
|
+
if (hasDependencyMatch(patterns, depsArray)) {
|
|
184
179
|
const testers = patterns.map(makeNodeModulesPattern);
|
|
185
180
|
matchers.push({
|
|
186
181
|
name: groupName,
|
|
187
182
|
test: (id) => testers.some((t) => t(id)),
|
|
188
|
-
priority:
|
|
183
|
+
priority: PRIORITIES.MEDIUM_LIB
|
|
189
184
|
});
|
|
190
185
|
}
|
|
191
186
|
}
|
|
192
187
|
} else if (strategy === "conservative") {
|
|
193
|
-
const veryLargeLibs = ["react", "vue", "angular", "antd", "element-plus", "echarts", "three"];
|
|
194
188
|
for (const [groupName, patterns] of Object.entries(COMMON_LARGE_LIBS)) {
|
|
195
|
-
if (
|
|
196
|
-
|
|
197
|
-
const pkgName = p.replace(/\//g, "");
|
|
198
|
-
return Array.from(projectDeps).some((dep) => dep.includes(pkgName));
|
|
199
|
-
});
|
|
200
|
-
if (hasAny) {
|
|
189
|
+
if (VERY_LARGE_LIBS.includes(groupName)) {
|
|
190
|
+
if (hasDependencyMatch(patterns, depsArray)) {
|
|
201
191
|
const testers = patterns.map(makeNodeModulesPattern);
|
|
202
192
|
matchers.push({
|
|
203
193
|
name: groupName,
|
|
204
194
|
test: (id) => testers.some((t) => t(id)),
|
|
205
|
-
priority:
|
|
195
|
+
priority: PRIORITIES.LARGE_LIB
|
|
206
196
|
});
|
|
207
197
|
}
|
|
208
198
|
}
|
|
@@ -210,6 +200,61 @@ function buildGroupMatchers(options, projectDeps, pluginHints) {
|
|
|
210
200
|
}
|
|
211
201
|
return matchers.sort((a, b) => b.priority - a.priority);
|
|
212
202
|
}
|
|
203
|
+
|
|
204
|
+
// src/deps.ts
|
|
205
|
+
var MAX_PACKAGE_JSON_SIZE = 1024 * 1024;
|
|
206
|
+
function isValidPackageJson(obj) {
|
|
207
|
+
if (typeof obj !== "object" || obj === null) return false;
|
|
208
|
+
const json = obj;
|
|
209
|
+
if (json.dependencies !== void 0) {
|
|
210
|
+
if (typeof json.dependencies !== "object" || json.dependencies === null) return false;
|
|
211
|
+
for (const val of Object.values(json.dependencies)) {
|
|
212
|
+
if (typeof val !== "string") return false;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
function readProjectDependencies(cwd) {
|
|
218
|
+
try {
|
|
219
|
+
const pkgPath = path__default.default.join(cwd, "package.json");
|
|
220
|
+
const stats = fs__default.default.statSync(pkgPath);
|
|
221
|
+
if (stats.size > MAX_PACKAGE_JSON_SIZE) {
|
|
222
|
+
logger.warn(`package.json too large (${stats.size} bytes), skipping`);
|
|
223
|
+
return /* @__PURE__ */ new Set();
|
|
224
|
+
}
|
|
225
|
+
const content = fs__default.default.readFileSync(pkgPath, "utf8");
|
|
226
|
+
const json = JSON.parse(content);
|
|
227
|
+
if (!isValidPackageJson(json)) {
|
|
228
|
+
logger.warn("Invalid package.json format: dependencies field is malformed");
|
|
229
|
+
return /* @__PURE__ */ new Set();
|
|
230
|
+
}
|
|
231
|
+
return new Set(Object.keys(json.dependencies || {}));
|
|
232
|
+
} catch (error) {
|
|
233
|
+
if (error instanceof SyntaxError) {
|
|
234
|
+
logger.warn("Failed to parse package.json: Invalid JSON format");
|
|
235
|
+
} else if (error.code === "ENOENT") {
|
|
236
|
+
logger.warn(`package.json not found in: ${cwd}`);
|
|
237
|
+
} else if (process.env.DEBUG) {
|
|
238
|
+
logger.debug(`Failed to read package.json: ${error}`);
|
|
239
|
+
}
|
|
240
|
+
return /* @__PURE__ */ new Set();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function hasDependencyMatch(patterns, depsArray) {
|
|
244
|
+
const depsSet = new Set(depsArray);
|
|
245
|
+
return patterns.some((pattern) => {
|
|
246
|
+
if (pattern.includes("/")) {
|
|
247
|
+
return depsArray.some((dep) => dep.startsWith(pattern));
|
|
248
|
+
}
|
|
249
|
+
return depsSet.has(pattern) || depsArray.some((dep) => {
|
|
250
|
+
if (dep === pattern) return true;
|
|
251
|
+
if (dep.startsWith(`@${pattern}/`)) return true;
|
|
252
|
+
return false;
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// src/index.ts
|
|
213
258
|
function OPS(opts = {}) {
|
|
214
259
|
const options = {
|
|
215
260
|
override: opts.override ?? false,
|
|
@@ -219,22 +264,32 @@ function OPS(opts = {}) {
|
|
|
219
264
|
};
|
|
220
265
|
let groupsRef = [];
|
|
221
266
|
const manualChunks = (id) => {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
267
|
+
try {
|
|
268
|
+
const nid = normalizeId(id);
|
|
269
|
+
if (!/\/node_modules\//.test(nid)) return void 0;
|
|
270
|
+
for (const g of groupsRef) {
|
|
271
|
+
if (g.test(nid)) return g.name;
|
|
272
|
+
}
|
|
273
|
+
return "vendor";
|
|
274
|
+
} catch (error) {
|
|
275
|
+
logger.warn(`Error in manualChunks for ${id}: ${error}`);
|
|
276
|
+
return "vendor";
|
|
226
277
|
}
|
|
227
|
-
return "vendor";
|
|
228
278
|
};
|
|
229
279
|
const assetFileNamesFn = (assetInfo) => {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
280
|
+
try {
|
|
281
|
+
const name = assetInfo.name ?? "";
|
|
282
|
+
const ext = name.split(".").pop()?.toLowerCase();
|
|
283
|
+
if (ext === "css") return "css/[name]-[hash][extname]";
|
|
284
|
+
if (["png", "jpg", "jpeg", "gif", "svg", "webp", "avif"].includes(ext ?? ""))
|
|
285
|
+
return "img/[name]-[hash][extname]";
|
|
286
|
+
if (["woff", "woff2", "eot", "ttf", "otf"].includes(ext ?? ""))
|
|
287
|
+
return "fonts/[name]-[hash][extname]";
|
|
288
|
+
return "assets/[name]-[hash][extname]";
|
|
289
|
+
} catch (error) {
|
|
290
|
+
logger.warn(`Error in assetFileNames: ${error}`);
|
|
291
|
+
return "assets/[name]-[hash][extname]";
|
|
292
|
+
}
|
|
238
293
|
};
|
|
239
294
|
return {
|
|
240
295
|
name: "vite-plugin-ops",
|
|
@@ -250,14 +305,14 @@ function OPS(opts = {}) {
|
|
|
250
305
|
manualChunks
|
|
251
306
|
};
|
|
252
307
|
let output;
|
|
253
|
-
if (shouldMerge) {
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
308
|
+
if (shouldMerge && existingOutput) {
|
|
309
|
+
const existing = existingOutput;
|
|
310
|
+
output = {
|
|
311
|
+
entryFileNames: existing?.entryFileNames ?? injected.entryFileNames,
|
|
312
|
+
chunkFileNames: existing?.chunkFileNames ?? injected.chunkFileNames,
|
|
313
|
+
assetFileNames: existing?.assetFileNames ?? injected.assetFileNames,
|
|
314
|
+
manualChunks: existing?.manualChunks ?? injected.manualChunks
|
|
315
|
+
};
|
|
261
316
|
} else {
|
|
262
317
|
output = injected;
|
|
263
318
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +2,6 @@ import { Plugin } from 'vite';
|
|
|
2
2
|
export { Plugin as OPSPlugin } from 'vite';
|
|
3
3
|
|
|
4
4
|
type SplitStrategy = 'aggressive' | 'balanced' | 'conservative';
|
|
5
|
-
|
|
6
5
|
type OPSOptions = {
|
|
7
6
|
/**
|
|
8
7
|
* If true, overwrite existing `build.rollupOptions.output.*` fields.
|
|
@@ -31,6 +30,19 @@ type OPSOptions = {
|
|
|
31
30
|
*/
|
|
32
31
|
groups?: Record<string, (string | RegExp)[]>;
|
|
33
32
|
};
|
|
33
|
+
type ResolvedOptions = Required<Pick<OPSOptions, 'override' | 'strategy' | 'minSize'>> & {
|
|
34
|
+
groups?: OPSOptions['groups'];
|
|
35
|
+
};
|
|
36
|
+
type GroupMatcher = {
|
|
37
|
+
name: string;
|
|
38
|
+
test: (id: string) => boolean;
|
|
39
|
+
priority: number;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* OPS - Optimized Packaging Strategy
|
|
44
|
+
* 一个智能的 Vite 分包优化插件
|
|
45
|
+
*/
|
|
34
46
|
declare function OPS(opts?: OPSOptions): Plugin;
|
|
35
47
|
|
|
36
|
-
export { type OPSOptions, type SplitStrategy, OPS as default };
|
|
48
|
+
export { type GroupMatcher, type OPSOptions, type ResolvedOptions, type SplitStrategy, OPS as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,36 +1,9 @@
|
|
|
1
|
-
import { Plugin } from 'vite';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* Default: false
|
|
11
|
-
*/
|
|
12
|
-
override?: boolean;
|
|
13
|
-
/**
|
|
14
|
-
* Chunking strategy:
|
|
15
|
-
* - 'aggressive': Split almost all dependencies into separate chunks
|
|
16
|
-
* - 'balanced': Split large dependencies and common frameworks (default)
|
|
17
|
-
* - 'conservative': Minimal splitting, only very large dependencies
|
|
18
|
-
* Default: 'balanced'
|
|
19
|
-
*/
|
|
20
|
-
strategy?: SplitStrategy;
|
|
21
|
-
/**
|
|
22
|
-
* Minimum size (in KB) for a dependency to be split into its own chunk.
|
|
23
|
-
* Only applies when strategy is 'balanced' or 'conservative'.
|
|
24
|
-
* Default: 50
|
|
25
|
-
*/
|
|
26
|
-
minSize?: number;
|
|
27
|
-
/**
|
|
28
|
-
* Additional custom chunk groups. Keys are chunk names; values are string or RegExp
|
|
29
|
-
* matchers to detect a module path in node_modules. Example:
|
|
30
|
-
* { three: ['three'], lodash: [/node_modules\\/lodash(?!-)/] }
|
|
31
|
-
*/
|
|
32
|
-
groups?: Record<string, (string | RegExp)[]>;
|
|
33
|
-
};
|
|
34
|
-
declare function OPS(opts?: OPSOptions): Plugin;
|
|
35
|
-
|
|
36
|
-
export { type OPSOptions, type SplitStrategy, OPS as default };
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
import type { OPSOptions } from './types';
|
|
3
|
+
export type { OPSPlugin, OPSOptions, SplitStrategy, ResolvedOptions, GroupMatcher } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* OPS - Optimized Packaging Strategy
|
|
6
|
+
* 一个智能的 Vite 分包优化插件
|
|
7
|
+
*/
|
|
8
|
+
export default function OPS(opts?: OPSOptions): Plugin;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,MAAM,CAAA;AAC9C,OAAO,KAAK,EAAE,UAAU,EAA2E,MAAM,SAAS,CAAA;AAIlH,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAUlG;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,IAAI,GAAE,UAAe,GAAG,MAAM,CAgHzD"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
|
-
// src/
|
|
4
|
+
// src/deps.ts
|
|
5
|
+
|
|
6
|
+
// src/presets.ts
|
|
5
7
|
var COMMON_LARGE_LIBS = {
|
|
6
8
|
// UI Frameworks
|
|
7
9
|
react: ["react", "react-dom"],
|
|
@@ -44,16 +46,46 @@ var MEDIUM_LIB_GROUPS = {
|
|
|
44
46
|
"form": ["react-hook-form", "formik", "async-validator"],
|
|
45
47
|
"i18n": ["i18next", "react-i18next", "vue-i18n"]
|
|
46
48
|
};
|
|
47
|
-
var
|
|
49
|
+
var VERY_LARGE_LIBS = ["react", "vue", "angular", "antd", "element-plus", "echarts", "three"];
|
|
50
|
+
|
|
51
|
+
// src/matcher.ts
|
|
52
|
+
var PRIORITIES = {
|
|
53
|
+
CUSTOM: 100,
|
|
54
|
+
// 用户自定义分组
|
|
55
|
+
DETECTED: 90,
|
|
56
|
+
// 插件检测到的框架
|
|
57
|
+
LARGE_LIB: 80,
|
|
58
|
+
// 大型库
|
|
59
|
+
MEDIUM_LIB: 70,
|
|
60
|
+
// 中型库
|
|
61
|
+
ALL_DEPS: 50
|
|
62
|
+
// 所有依赖(aggressive 模式)
|
|
63
|
+
};
|
|
48
64
|
var MAX_PATH_LENGTH = 2e3;
|
|
65
|
+
var MAX_CACHE_SIZE = 100;
|
|
66
|
+
var patternCache = /* @__PURE__ */ new Map();
|
|
67
|
+
var cacheKeys = [];
|
|
68
|
+
var logger = {
|
|
69
|
+
warn: (msg) => console.warn(`[vite-plugin-ops] ${msg}`),
|
|
70
|
+
error: (msg) => console.error(`[vite-plugin-ops] ERROR: ${msg}`),
|
|
71
|
+
debug: (msg) => process.env.DEBUG && console.log(`[vite-plugin-ops] DEBUG: ${msg}`)
|
|
72
|
+
};
|
|
49
73
|
function normalizeId(id) {
|
|
50
74
|
return id.replace(/\\/g, "/").replace(/%5C/g, "/");
|
|
51
75
|
}
|
|
76
|
+
function manageCache() {
|
|
77
|
+
while (cacheKeys.length >= MAX_CACHE_SIZE) {
|
|
78
|
+
const oldestKey = cacheKeys.shift();
|
|
79
|
+
if (oldestKey) {
|
|
80
|
+
patternCache.delete(oldestKey);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
52
84
|
function makeNodeModulesPattern(pkg) {
|
|
53
85
|
if (pkg instanceof RegExp) {
|
|
54
86
|
return (id) => {
|
|
55
87
|
if (id.length > MAX_PATH_LENGTH) {
|
|
56
|
-
|
|
88
|
+
logger.warn(`Path too long (${id.length} chars), skipping: ${id.slice(0, 50)}...`);
|
|
57
89
|
return false;
|
|
58
90
|
}
|
|
59
91
|
return pkg.test(id);
|
|
@@ -61,55 +93,27 @@ function makeNodeModulesPattern(pkg) {
|
|
|
61
93
|
}
|
|
62
94
|
let re = patternCache.get(pkg);
|
|
63
95
|
if (!re) {
|
|
96
|
+
manageCache();
|
|
64
97
|
const scoped = pkg.startsWith("@");
|
|
65
98
|
const escaped = pkg.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
|
|
66
99
|
const base = scoped ? escaped : `(?:@[^/]+/)?${escaped}`;
|
|
67
|
-
|
|
100
|
+
const flags = process.platform === "win32" ? "i" : "";
|
|
101
|
+
re = new RegExp(`/node_modules/(?:[.]pnpm/)?(?:${base})(?:/|@|$)`, flags);
|
|
68
102
|
patternCache.set(pkg, re);
|
|
103
|
+
cacheKeys.push(pkg);
|
|
69
104
|
}
|
|
70
105
|
return (id) => {
|
|
71
106
|
if (id.length > MAX_PATH_LENGTH) {
|
|
72
|
-
|
|
107
|
+
logger.warn(`Path too long (${id.length} chars), skipping: ${id.slice(0, 50)}...`);
|
|
73
108
|
return false;
|
|
74
109
|
}
|
|
75
110
|
return re.test(id);
|
|
76
111
|
};
|
|
77
112
|
}
|
|
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;
|
|
88
|
-
}
|
|
89
|
-
function readProjectDependencies(cwd) {
|
|
90
|
-
try {
|
|
91
|
-
const pkgPath = path.join(cwd, "package.json");
|
|
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
|
-
}
|
|
98
|
-
return new Set(Object.keys(json.dependencies || {}));
|
|
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
|
-
}
|
|
107
|
-
return /* @__PURE__ */ new Set();
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
113
|
function buildGroupMatchers(options, projectDeps, pluginHints) {
|
|
111
114
|
const matchers = [];
|
|
112
|
-
const strategy = options.strategy
|
|
115
|
+
const strategy = options.strategy;
|
|
116
|
+
const depsArray = Array.from(projectDeps);
|
|
113
117
|
if (options.groups) {
|
|
114
118
|
for (const [name, patterns] of Object.entries(options.groups)) {
|
|
115
119
|
if (patterns && patterns.length) {
|
|
@@ -122,7 +126,7 @@ function buildGroupMatchers(options, projectDeps, pluginHints) {
|
|
|
122
126
|
matchers.push({
|
|
123
127
|
name,
|
|
124
128
|
test: (id) => testers.some((t) => t(id)),
|
|
125
|
-
priority:
|
|
129
|
+
priority: PRIORITIES.CUSTOM
|
|
126
130
|
});
|
|
127
131
|
}
|
|
128
132
|
}
|
|
@@ -139,63 +143,49 @@ function buildGroupMatchers(options, projectDeps, pluginHints) {
|
|
|
139
143
|
matchers.push({
|
|
140
144
|
name,
|
|
141
145
|
test: (id) => testers.some((t) => t(id)),
|
|
142
|
-
priority:
|
|
146
|
+
priority: PRIORITIES.DETECTED
|
|
143
147
|
});
|
|
144
148
|
}
|
|
145
149
|
if (strategy === "aggressive") {
|
|
146
|
-
for (const dep of
|
|
150
|
+
for (const dep of depsArray) {
|
|
147
151
|
if (!dep.startsWith("@types/")) {
|
|
148
152
|
matchers.push({
|
|
149
153
|
name: dep,
|
|
150
154
|
test: makeNodeModulesPattern(dep),
|
|
151
|
-
priority:
|
|
155
|
+
priority: PRIORITIES.ALL_DEPS
|
|
152
156
|
});
|
|
153
157
|
}
|
|
154
158
|
}
|
|
155
159
|
} else if (strategy === "balanced") {
|
|
156
160
|
for (const [groupName, patterns] of Object.entries(COMMON_LARGE_LIBS)) {
|
|
157
|
-
|
|
158
|
-
const pkgName = p.replace(/\//g, "");
|
|
159
|
-
return Array.from(projectDeps).some((dep) => dep.includes(pkgName));
|
|
160
|
-
});
|
|
161
|
-
if (hasAny) {
|
|
161
|
+
if (hasDependencyMatch(patterns, depsArray)) {
|
|
162
162
|
const testers = patterns.map(makeNodeModulesPattern);
|
|
163
163
|
matchers.push({
|
|
164
164
|
name: groupName,
|
|
165
165
|
test: (id) => testers.some((t) => t(id)),
|
|
166
|
-
priority:
|
|
166
|
+
priority: PRIORITIES.LARGE_LIB
|
|
167
167
|
});
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
for (const [groupName, patterns] of Object.entries(MEDIUM_LIB_GROUPS)) {
|
|
171
|
-
|
|
172
|
-
return Array.from(projectDeps).some(
|
|
173
|
-
(dep) => dep.includes(p.replace(/\//g, "").replace(/\*/g, ""))
|
|
174
|
-
);
|
|
175
|
-
});
|
|
176
|
-
if (hasAny) {
|
|
171
|
+
if (hasDependencyMatch(patterns, depsArray)) {
|
|
177
172
|
const testers = patterns.map(makeNodeModulesPattern);
|
|
178
173
|
matchers.push({
|
|
179
174
|
name: groupName,
|
|
180
175
|
test: (id) => testers.some((t) => t(id)),
|
|
181
|
-
priority:
|
|
176
|
+
priority: PRIORITIES.MEDIUM_LIB
|
|
182
177
|
});
|
|
183
178
|
}
|
|
184
179
|
}
|
|
185
180
|
} else if (strategy === "conservative") {
|
|
186
|
-
const veryLargeLibs = ["react", "vue", "angular", "antd", "element-plus", "echarts", "three"];
|
|
187
181
|
for (const [groupName, patterns] of Object.entries(COMMON_LARGE_LIBS)) {
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
const pkgName = p.replace(/\//g, "");
|
|
191
|
-
return Array.from(projectDeps).some((dep) => dep.includes(pkgName));
|
|
192
|
-
});
|
|
193
|
-
if (hasAny) {
|
|
182
|
+
if (VERY_LARGE_LIBS.includes(groupName)) {
|
|
183
|
+
if (hasDependencyMatch(patterns, depsArray)) {
|
|
194
184
|
const testers = patterns.map(makeNodeModulesPattern);
|
|
195
185
|
matchers.push({
|
|
196
186
|
name: groupName,
|
|
197
187
|
test: (id) => testers.some((t) => t(id)),
|
|
198
|
-
priority:
|
|
188
|
+
priority: PRIORITIES.LARGE_LIB
|
|
199
189
|
});
|
|
200
190
|
}
|
|
201
191
|
}
|
|
@@ -203,6 +193,61 @@ function buildGroupMatchers(options, projectDeps, pluginHints) {
|
|
|
203
193
|
}
|
|
204
194
|
return matchers.sort((a, b) => b.priority - a.priority);
|
|
205
195
|
}
|
|
196
|
+
|
|
197
|
+
// src/deps.ts
|
|
198
|
+
var MAX_PACKAGE_JSON_SIZE = 1024 * 1024;
|
|
199
|
+
function isValidPackageJson(obj) {
|
|
200
|
+
if (typeof obj !== "object" || obj === null) return false;
|
|
201
|
+
const json = obj;
|
|
202
|
+
if (json.dependencies !== void 0) {
|
|
203
|
+
if (typeof json.dependencies !== "object" || json.dependencies === null) return false;
|
|
204
|
+
for (const val of Object.values(json.dependencies)) {
|
|
205
|
+
if (typeof val !== "string") return false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
function readProjectDependencies(cwd) {
|
|
211
|
+
try {
|
|
212
|
+
const pkgPath = path.join(cwd, "package.json");
|
|
213
|
+
const stats = fs.statSync(pkgPath);
|
|
214
|
+
if (stats.size > MAX_PACKAGE_JSON_SIZE) {
|
|
215
|
+
logger.warn(`package.json too large (${stats.size} bytes), skipping`);
|
|
216
|
+
return /* @__PURE__ */ new Set();
|
|
217
|
+
}
|
|
218
|
+
const content = fs.readFileSync(pkgPath, "utf8");
|
|
219
|
+
const json = JSON.parse(content);
|
|
220
|
+
if (!isValidPackageJson(json)) {
|
|
221
|
+
logger.warn("Invalid package.json format: dependencies field is malformed");
|
|
222
|
+
return /* @__PURE__ */ new Set();
|
|
223
|
+
}
|
|
224
|
+
return new Set(Object.keys(json.dependencies || {}));
|
|
225
|
+
} catch (error) {
|
|
226
|
+
if (error instanceof SyntaxError) {
|
|
227
|
+
logger.warn("Failed to parse package.json: Invalid JSON format");
|
|
228
|
+
} else if (error.code === "ENOENT") {
|
|
229
|
+
logger.warn(`package.json not found in: ${cwd}`);
|
|
230
|
+
} else if (process.env.DEBUG) {
|
|
231
|
+
logger.debug(`Failed to read package.json: ${error}`);
|
|
232
|
+
}
|
|
233
|
+
return /* @__PURE__ */ new Set();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function hasDependencyMatch(patterns, depsArray) {
|
|
237
|
+
const depsSet = new Set(depsArray);
|
|
238
|
+
return patterns.some((pattern) => {
|
|
239
|
+
if (pattern.includes("/")) {
|
|
240
|
+
return depsArray.some((dep) => dep.startsWith(pattern));
|
|
241
|
+
}
|
|
242
|
+
return depsSet.has(pattern) || depsArray.some((dep) => {
|
|
243
|
+
if (dep === pattern) return true;
|
|
244
|
+
if (dep.startsWith(`@${pattern}/`)) return true;
|
|
245
|
+
return false;
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// src/index.ts
|
|
206
251
|
function OPS(opts = {}) {
|
|
207
252
|
const options = {
|
|
208
253
|
override: opts.override ?? false,
|
|
@@ -212,22 +257,32 @@ function OPS(opts = {}) {
|
|
|
212
257
|
};
|
|
213
258
|
let groupsRef = [];
|
|
214
259
|
const manualChunks = (id) => {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
260
|
+
try {
|
|
261
|
+
const nid = normalizeId(id);
|
|
262
|
+
if (!/\/node_modules\//.test(nid)) return void 0;
|
|
263
|
+
for (const g of groupsRef) {
|
|
264
|
+
if (g.test(nid)) return g.name;
|
|
265
|
+
}
|
|
266
|
+
return "vendor";
|
|
267
|
+
} catch (error) {
|
|
268
|
+
logger.warn(`Error in manualChunks for ${id}: ${error}`);
|
|
269
|
+
return "vendor";
|
|
219
270
|
}
|
|
220
|
-
return "vendor";
|
|
221
271
|
};
|
|
222
272
|
const assetFileNamesFn = (assetInfo) => {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
273
|
+
try {
|
|
274
|
+
const name = assetInfo.name ?? "";
|
|
275
|
+
const ext = name.split(".").pop()?.toLowerCase();
|
|
276
|
+
if (ext === "css") return "css/[name]-[hash][extname]";
|
|
277
|
+
if (["png", "jpg", "jpeg", "gif", "svg", "webp", "avif"].includes(ext ?? ""))
|
|
278
|
+
return "img/[name]-[hash][extname]";
|
|
279
|
+
if (["woff", "woff2", "eot", "ttf", "otf"].includes(ext ?? ""))
|
|
280
|
+
return "fonts/[name]-[hash][extname]";
|
|
281
|
+
return "assets/[name]-[hash][extname]";
|
|
282
|
+
} catch (error) {
|
|
283
|
+
logger.warn(`Error in assetFileNames: ${error}`);
|
|
284
|
+
return "assets/[name]-[hash][extname]";
|
|
285
|
+
}
|
|
231
286
|
};
|
|
232
287
|
return {
|
|
233
288
|
name: "vite-plugin-ops",
|
|
@@ -243,14 +298,14 @@ function OPS(opts = {}) {
|
|
|
243
298
|
manualChunks
|
|
244
299
|
};
|
|
245
300
|
let output;
|
|
246
|
-
if (shouldMerge) {
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
301
|
+
if (shouldMerge && existingOutput) {
|
|
302
|
+
const existing = existingOutput;
|
|
303
|
+
output = {
|
|
304
|
+
entryFileNames: existing?.entryFileNames ?? injected.entryFileNames,
|
|
305
|
+
chunkFileNames: existing?.chunkFileNames ?? injected.chunkFileNames,
|
|
306
|
+
assetFileNames: existing?.assetFileNames ?? injected.assetFileNames,
|
|
307
|
+
manualChunks: existing?.manualChunks ?? injected.manualChunks
|
|
308
|
+
};
|
|
254
309
|
} else {
|
|
255
310
|
output = injected;
|
|
256
311
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { GroupMatcher, ResolvedOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* 优先级常量:确保分组匹配的优先级顺序
|
|
4
|
+
*/
|
|
5
|
+
export declare const PRIORITIES: {
|
|
6
|
+
readonly CUSTOM: 100;
|
|
7
|
+
readonly DETECTED: 90;
|
|
8
|
+
readonly LARGE_LIB: 80;
|
|
9
|
+
readonly MEDIUM_LIB: 70;
|
|
10
|
+
readonly ALL_DEPS: 50;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* 统一的日志系统
|
|
14
|
+
*/
|
|
15
|
+
declare const logger: {
|
|
16
|
+
warn: (msg: string) => void;
|
|
17
|
+
error: (msg: string) => void;
|
|
18
|
+
debug: (msg: string) => void | "" | undefined;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* 路径标准化:统一使用正斜杠
|
|
22
|
+
*/
|
|
23
|
+
export declare function normalizeId(id: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* 创建 node_modules 匹配函数
|
|
26
|
+
* @param pkg 包名或正则表达式
|
|
27
|
+
* @returns 匹配函数
|
|
28
|
+
*/
|
|
29
|
+
export declare function makeNodeModulesPattern(pkg: string | RegExp): (id: string) => boolean;
|
|
30
|
+
/**
|
|
31
|
+
* 构建分组匹配器
|
|
32
|
+
* @param options 插件选项
|
|
33
|
+
* @param projectDeps 项目依赖集合
|
|
34
|
+
* @param pluginHints 插件检测提示
|
|
35
|
+
* @returns 排序后的匹配器数组
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildGroupMatchers(options: Pick<ResolvedOptions, 'groups' | 'strategy' | 'minSize'>, projectDeps: Set<string>, pluginHints: Set<string>): GroupMatcher[];
|
|
38
|
+
/**
|
|
39
|
+
* 清除缓存(用于测试)
|
|
40
|
+
*/
|
|
41
|
+
export declare function clearCache(): void;
|
|
42
|
+
export { logger };
|
|
43
|
+
//# sourceMappingURL=matcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matcher.d.ts","sourceRoot":"","sources":["../src/matcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAM5D;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;;CAMb,CAAA;AAgBV;;GAEG;AACH,QAAA,MAAM,MAAM;gBACE,MAAM;iBACL,MAAM;iBACN,MAAM;CACpB,CAAA;AAID;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE9C;AAcD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAuCpF;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC,EACjE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,GACvB,YAAY,EAAE,CAmGhB;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAGjC;AAGD,OAAO,EAAE,MAAM,EAAE,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 预设配置:大型库分组
|
|
3
|
+
* Common large libraries that should typically be split
|
|
4
|
+
*/
|
|
5
|
+
export declare const COMMON_LARGE_LIBS: Record<string, string[]>;
|
|
6
|
+
/**
|
|
7
|
+
* 预设配置:中型库分组
|
|
8
|
+
* Medium-sized libraries that should be grouped together
|
|
9
|
+
*/
|
|
10
|
+
export declare const MEDIUM_LIB_GROUPS: Record<string, string[]>;
|
|
11
|
+
/**
|
|
12
|
+
* 保守策略下只分离的超大型库
|
|
13
|
+
*/
|
|
14
|
+
export declare const VERY_LARGE_LIBS: readonly ["react", "vue", "angular", "antd", "element-plus", "echarts", "three"];
|
|
15
|
+
//# sourceMappingURL=presets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAyCtD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAKtD,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,kFAAmF,CAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Plugin, UserConfig } from 'vite';
|
|
2
|
+
export type SplitStrategy = 'aggressive' | 'balanced' | 'conservative';
|
|
3
|
+
export type OPSOptions = {
|
|
4
|
+
/**
|
|
5
|
+
* If true, overwrite existing `build.rollupOptions.output.*` fields.
|
|
6
|
+
* If false, only fill in fields that are not already provided by the user.
|
|
7
|
+
* Default: false
|
|
8
|
+
*/
|
|
9
|
+
override?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Chunking strategy:
|
|
12
|
+
* - 'aggressive': Split almost all dependencies into separate chunks
|
|
13
|
+
* - 'balanced': Split large dependencies and common frameworks (default)
|
|
14
|
+
* - 'conservative': Minimal splitting, only very large dependencies
|
|
15
|
+
* Default: 'balanced'
|
|
16
|
+
*/
|
|
17
|
+
strategy?: SplitStrategy;
|
|
18
|
+
/**
|
|
19
|
+
* Minimum size (in KB) for a dependency to be split into its own chunk.
|
|
20
|
+
* Only applies when strategy is 'balanced' or 'conservative'.
|
|
21
|
+
* Default: 50
|
|
22
|
+
*/
|
|
23
|
+
minSize?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Additional custom chunk groups. Keys are chunk names; values are string or RegExp
|
|
26
|
+
* matchers to detect a module path in node_modules. Example:
|
|
27
|
+
* { three: ['three'], lodash: [/node_modules\\/lodash(?!-)/] }
|
|
28
|
+
*/
|
|
29
|
+
groups?: Record<string, (string | RegExp)[]>;
|
|
30
|
+
};
|
|
31
|
+
export type ResolvedOptions = Required<Pick<OPSOptions, 'override' | 'strategy' | 'minSize'>> & {
|
|
32
|
+
groups?: OPSOptions['groups'];
|
|
33
|
+
};
|
|
34
|
+
export type GroupMatcher = {
|
|
35
|
+
name: string;
|
|
36
|
+
test: (id: string) => boolean;
|
|
37
|
+
priority: number;
|
|
38
|
+
};
|
|
39
|
+
type OutputOptions = NonNullable<NonNullable<UserConfig['build']>['rollupOptions']>['output'] extends infer O ? O extends any[] ? O[number] : O : never;
|
|
40
|
+
export type ManualChunksOption = NonNullable<OutputOptions>['manualChunks'];
|
|
41
|
+
export type AssetFileNamesOption = NonNullable<OutputOptions>['assetFileNames'];
|
|
42
|
+
export type { Plugin as OPSPlugin };
|
|
43
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,MAAM,CAAA;AAE9C,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,UAAU,GAAG,cAAc,CAAA;AAEtE,MAAM,MAAM,UAAU,GAAG;IACvB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAA;IACxB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,CAAA;CAC7C,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC,CAAC,GAAG;IAC9F,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAA;IAC7B,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAGD,KAAK,aAAa,GAChB,WAAW,CAAC,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,MAAM,CAAC,GACtF,CAAC,SAAS,GAAG,EAAE,GACf,CAAC,CAAC,MAAM,CAAC,GACT,CAAC,GACD,KAAK,CAAA;AAET,MAAM,MAAM,kBAAkB,GAAG,WAAW,CAAC,aAAa,CAAC,CAAC,cAAc,CAAC,CAAA;AAC3E,MAAM,MAAM,oBAAoB,GAAG,WAAW,CAAC,aAAa,CAAC,CAAC,gBAAgB,CAAC,CAAA;AAG/E,YAAY,EAAE,MAAM,IAAI,SAAS,EAAE,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-ops",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Vite plugin to organize build outputs and vendor chunking.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "suileyan",
|
|
8
|
-
|
|
9
8
|
"exports": {
|
|
10
9
|
".": {
|
|
11
10
|
"types": "./dist/index.d.ts",
|
|
@@ -16,39 +15,53 @@
|
|
|
16
15
|
},
|
|
17
16
|
"main": "dist/index.cjs",
|
|
18
17
|
"types": "dist/index.d.ts",
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
22
23
|
"sideEffects": false,
|
|
23
24
|
"engines": {
|
|
24
25
|
"node": ">=20.19"
|
|
25
26
|
},
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
"keywords": [
|
|
28
|
+
"vite",
|
|
29
|
+
"vite-plugin",
|
|
30
|
+
"rollup",
|
|
31
|
+
"chunks",
|
|
32
|
+
"vendor",
|
|
33
|
+
"build"
|
|
34
|
+
],
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/suileyan/vite-plugin-ops.git"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/suileyan/vite-plugin-ops/issues"
|
|
41
|
+
},
|
|
31
42
|
"homepage": "https://github.com/suileyan/vite-plugin-ops#readme",
|
|
32
|
-
|
|
33
43
|
"peerDependencies": {
|
|
34
44
|
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
|
|
35
45
|
},
|
|
36
46
|
"devDependencies": {
|
|
37
47
|
"@types/node": "^24.6.0",
|
|
38
48
|
"rimraf": "^6.0.1",
|
|
49
|
+
"rollup": "^4.0.0",
|
|
39
50
|
"tsup": "^8.5.0",
|
|
40
51
|
"typescript": "^5.9.2",
|
|
41
52
|
"vite": "^7.3.1",
|
|
42
|
-
"
|
|
53
|
+
"vitest": "^3.0.0"
|
|
43
54
|
},
|
|
44
|
-
|
|
45
55
|
"scripts": {
|
|
46
|
-
"build": "tsup",
|
|
56
|
+
"build": "tsup && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
57
|
+
"build:js": "tsup",
|
|
47
58
|
"dev": "tsup --watch --sourcemap",
|
|
48
59
|
"clean": "rimraf dist || rmdir /s /q dist",
|
|
49
|
-
"prepublishOnly": "npm run clean && npm run build"
|
|
60
|
+
"prepublishOnly": "npm run clean && npm run build",
|
|
61
|
+
"test": "vitest run",
|
|
62
|
+
"test:watch": "vitest",
|
|
63
|
+
"test:coverage": "vitest run --coverage"
|
|
50
64
|
},
|
|
51
|
-
|
|
52
65
|
"publishConfig": {
|
|
53
66
|
"access": "public",
|
|
54
67
|
"registry": "https://registry.npmjs.org/"
|