vite-plugin-ops 0.1.1 → 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/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
 
4
- // src/index.ts
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,31 +46,74 @@ var MEDIUM_LIB_GROUPS = {
44
46
  "form": ["react-hook-form", "formik", "async-validator"],
45
47
  "i18n": ["i18next", "react-i18next", "vue-i18n"]
46
48
  };
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
+ };
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
+ };
47
73
  function normalizeId(id) {
48
74
  return id.replace(/\\/g, "/").replace(/%5C/g, "/");
49
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
+ }
50
84
  function makeNodeModulesPattern(pkg) {
51
85
  if (pkg instanceof RegExp) {
52
- return (id) => pkg.test(id);
86
+ return (id) => {
87
+ if (id.length > MAX_PATH_LENGTH) {
88
+ logger.warn(`Path too long (${id.length} chars), skipping: ${id.slice(0, 50)}...`);
89
+ return false;
90
+ }
91
+ return pkg.test(id);
92
+ };
53
93
  }
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);
59
- }
60
- function readProjectDependencies(cwd) {
61
- try {
62
- const pkgPath = path.join(cwd, "package.json");
63
- const json = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
64
- return new Set(Object.keys(json.dependencies || {}));
65
- } catch {
66
- return /* @__PURE__ */ new Set();
94
+ let re = patternCache.get(pkg);
95
+ if (!re) {
96
+ manageCache();
97
+ const scoped = pkg.startsWith("@");
98
+ const escaped = pkg.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
99
+ const base = scoped ? escaped : `(?:@[^/]+/)?${escaped}`;
100
+ const flags = process.platform === "win32" ? "i" : "";
101
+ re = new RegExp(`/node_modules/(?:[.]pnpm/)?(?:${base})(?:/|@|$)`, flags);
102
+ patternCache.set(pkg, re);
103
+ cacheKeys.push(pkg);
67
104
  }
105
+ return (id) => {
106
+ if (id.length > MAX_PATH_LENGTH) {
107
+ logger.warn(`Path too long (${id.length} chars), skipping: ${id.slice(0, 50)}...`);
108
+ return false;
109
+ }
110
+ return re.test(id);
111
+ };
68
112
  }
69
113
  function buildGroupMatchers(options, projectDeps, pluginHints) {
70
114
  const matchers = [];
71
- const strategy = options.strategy || "balanced";
115
+ const strategy = options.strategy;
116
+ const depsArray = Array.from(projectDeps);
72
117
  if (options.groups) {
73
118
  for (const [name, patterns] of Object.entries(options.groups)) {
74
119
  if (patterns && patterns.length) {
@@ -81,7 +126,7 @@ function buildGroupMatchers(options, projectDeps, pluginHints) {
81
126
  matchers.push({
82
127
  name,
83
128
  test: (id) => testers.some((t) => t(id)),
84
- priority: 100
129
+ priority: PRIORITIES.CUSTOM
85
130
  });
86
131
  }
87
132
  }
@@ -98,63 +143,49 @@ function buildGroupMatchers(options, projectDeps, pluginHints) {
98
143
  matchers.push({
99
144
  name,
100
145
  test: (id) => testers.some((t) => t(id)),
101
- priority: 90
146
+ priority: PRIORITIES.DETECTED
102
147
  });
103
148
  }
104
149
  if (strategy === "aggressive") {
105
- for (const dep of projectDeps) {
150
+ for (const dep of depsArray) {
106
151
  if (!dep.startsWith("@types/")) {
107
152
  matchers.push({
108
153
  name: dep,
109
154
  test: makeNodeModulesPattern(dep),
110
- priority: 50
155
+ priority: PRIORITIES.ALL_DEPS
111
156
  });
112
157
  }
113
158
  }
114
159
  } else if (strategy === "balanced") {
115
160
  for (const [groupName, patterns] of Object.entries(COMMON_LARGE_LIBS)) {
116
- const hasAny = patterns.some((p) => {
117
- const pkgName = p.replace(/\//g, "");
118
- return Array.from(projectDeps).some((dep) => dep.includes(pkgName));
119
- });
120
- if (hasAny) {
161
+ if (hasDependencyMatch(patterns, depsArray)) {
121
162
  const testers = patterns.map(makeNodeModulesPattern);
122
163
  matchers.push({
123
164
  name: groupName,
124
165
  test: (id) => testers.some((t) => t(id)),
125
- priority: 80
166
+ priority: PRIORITIES.LARGE_LIB
126
167
  });
127
168
  }
128
169
  }
129
170
  for (const [groupName, patterns] of Object.entries(MEDIUM_LIB_GROUPS)) {
130
- const hasAny = patterns.some((p) => {
131
- return Array.from(projectDeps).some(
132
- (dep) => dep.includes(p.replace(/\//g, "").replace(/\*/g, ""))
133
- );
134
- });
135
- if (hasAny) {
171
+ if (hasDependencyMatch(patterns, depsArray)) {
136
172
  const testers = patterns.map(makeNodeModulesPattern);
137
173
  matchers.push({
138
174
  name: groupName,
139
175
  test: (id) => testers.some((t) => t(id)),
140
- priority: 70
176
+ priority: PRIORITIES.MEDIUM_LIB
141
177
  });
142
178
  }
143
179
  }
144
180
  } else if (strategy === "conservative") {
145
- const veryLargeLibs = ["react", "vue", "angular", "antd", "element-plus", "echarts", "three"];
146
181
  for (const [groupName, patterns] of Object.entries(COMMON_LARGE_LIBS)) {
147
- if (veryLargeLibs.includes(groupName)) {
148
- const hasAny = patterns.some((p) => {
149
- const pkgName = p.replace(/\//g, "");
150
- return Array.from(projectDeps).some((dep) => dep.includes(pkgName));
151
- });
152
- if (hasAny) {
182
+ if (VERY_LARGE_LIBS.includes(groupName)) {
183
+ if (hasDependencyMatch(patterns, depsArray)) {
153
184
  const testers = patterns.map(makeNodeModulesPattern);
154
185
  matchers.push({
155
186
  name: groupName,
156
187
  test: (id) => testers.some((t) => t(id)),
157
- priority: 80
188
+ priority: PRIORITIES.LARGE_LIB
158
189
  });
159
190
  }
160
191
  }
@@ -162,6 +193,61 @@ function buildGroupMatchers(options, projectDeps, pluginHints) {
162
193
  }
163
194
  return matchers.sort((a, b) => b.priority - a.priority);
164
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
165
251
  function OPS(opts = {}) {
166
252
  const options = {
167
253
  override: opts.override ?? false,
@@ -171,22 +257,32 @@ function OPS(opts = {}) {
171
257
  };
172
258
  let groupsRef = [];
173
259
  const manualChunks = (id) => {
174
- const nid = normalizeId(id);
175
- if (!/\/node_modules\//.test(nid)) return void 0;
176
- for (const g of groupsRef) {
177
- if (g.test(nid)) return g.name;
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";
178
270
  }
179
- return "vendor";
180
271
  };
181
272
  const assetFileNamesFn = (assetInfo) => {
182
- const name = assetInfo.name ?? "";
183
- const ext = name.split(".").pop()?.toLowerCase();
184
- if (ext === "css") return "css/[name]-[hash][extname]";
185
- if (["png", "jpg", "jpeg", "gif", "svg", "webp", "avif"].includes(ext ?? ""))
186
- return "img/[name]-[hash][extname]";
187
- if (["woff", "woff2", "eot", "ttf", "otf"].includes(ext ?? ""))
188
- return "fonts/[name]-[hash][extname]";
189
- return "assets/[name]-[hash][extname]";
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
+ }
190
286
  };
191
287
  return {
192
288
  name: "vite-plugin-ops",
@@ -202,14 +298,14 @@ function OPS(opts = {}) {
202
298
  manualChunks
203
299
  };
204
300
  let output;
205
- if (shouldMerge) {
206
- const base = existingOutput;
207
- const merged = { ...base };
208
- if (!("entryFileNames" in merged)) merged["entryFileNames"] = injected.entryFileNames;
209
- if (!("chunkFileNames" in merged)) merged["chunkFileNames"] = injected.chunkFileNames;
210
- if (!("assetFileNames" in merged)) merged["assetFileNames"] = injected.assetFileNames;
211
- if (!("manualChunks" in merged)) merged["manualChunks"] = injected.manualChunks;
212
- output = merged;
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
+ };
213
309
  } else {
214
310
  output = injected;
215
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"}
@@ -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,56 +1,69 @@
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": "1.0.0",
4
+ "description": "Vite plugin to organize build outputs and vendor chunking.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "suileyan",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs"
13
+ },
14
+ "./package.json": "./package.json"
15
+ },
16
+ "main": "dist/index.cjs",
17
+ "types": "dist/index.d.ts",
18
+ "files": [
19
+ "dist",
20
+ "README.md",
21
+ "LICENSE"
22
+ ],
23
+ "sideEffects": false,
24
+ "engines": {
25
+ "node": ">=20.19"
26
+ },
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
+ },
42
+ "homepage": "https://github.com/suileyan/vite-plugin-ops#readme",
43
+ "peerDependencies": {
44
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^24.6.0",
48
+ "rimraf": "^6.0.1",
49
+ "rollup": "^4.0.0",
50
+ "tsup": "^8.5.0",
51
+ "typescript": "^5.9.2",
52
+ "vite": "^7.3.1",
53
+ "vitest": "^3.0.0"
54
+ },
55
+ "scripts": {
56
+ "build": "tsup && tsc --emitDeclarationOnly --declaration --outDir dist",
57
+ "build:js": "tsup",
58
+ "dev": "tsup --watch --sourcemap",
59
+ "clean": "rimraf dist || rmdir /s /q dist",
60
+ "prepublishOnly": "npm run clean && npm run build",
61
+ "test": "vitest run",
62
+ "test:watch": "vitest",
63
+ "test:coverage": "vitest run --coverage"
64
+ },
65
+ "publishConfig": {
66
+ "access": "public",
67
+ "registry": "https://registry.npmjs.org/"
68
+ }
69
+ }