@infly/vue2-vite 1.0.0 → 1.0.1

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.
@@ -1,261 +1,261 @@
1
- /**
2
- * 配置发现编排器
3
- *
4
- * 按优先级(从低到高)加载所有配置源并合并:
5
- * 1. 包安全默认值
6
- * 2. 项目 vue.config.js 标准字段
7
- * 3. package.json 的 inflyVite 字段
8
- * 4. infly.vite.config.js / .cjs / .mjs
9
- * 5. CLI 参数
10
- *
11
- * 规范 §9.1
12
- */
13
-
14
- import fs from 'node:fs';
15
- import path from 'node:path';
16
- import { createRequire } from 'node:module';
17
- import { createDefaultConfig } from './project-config.mjs';
18
- import { loadVueCliConfig, extractAdditionalVueConfigInfo } from './vue-cli-reader.mjs';
19
- import { loadEnvFiles, resolveTarget, buildDefine } from './env.mjs';
20
- import { deepMerge } from './merge.mjs';
21
- import { validateStrictCompatibility, diagnoseCompatIssues } from './validation.mjs';
22
-
23
- /**
24
- * 可选的 infly.vite.config 文件名(按优先级)
25
- */
26
- const CONFIG_FILES = [
27
- 'infly.vite.config.mjs',
28
- 'infly.vite.config.js',
29
- 'infly.vite.config.cjs',
30
- ];
31
-
32
- /**
33
- * @param {object} options
34
- * @param {string} options.command - 'serve' | 'build'
35
- * @param {string} options.mode - 模式
36
- * @param {string} [options.target] - CLI target
37
- * @param {string} options.projectRoot - 项目根目录
38
- * @param {object} [options.cliOptions] - CLI 额外选项
39
- * @returns {Promise<object>} 归一化配置 + 元信息
40
- */
41
- export async function discoverConfig(options = {}) {
42
- const {
43
- command = 'build',
44
- mode = 'production',
45
- target: cliTarget,
46
- projectRoot = process.cwd(),
47
- cliOptions = {},
48
- } = options;
49
-
50
- // test 命令复用 build 的配置语义(mode=test,读取 .env.test 等)
51
- const isBuild = command === 'build' || command === 'test';
52
- const isServe = command === 'serve';
53
-
54
- // 1. 包默认值
55
- const defaults = createDefaultConfig({ command, mode, target: cliTarget, projectRoot, isBuild, isServe });
56
-
57
- // 2. 环境变量(解析 target)
58
- const { target: envTarget, define } = buildDefine({
59
- projectRoot,
60
- mode,
61
- target: cliTarget,
62
- defaultTarget: defaults.context.target || 'DEFAULT',
63
- });
64
- const resolvedTarget = cliTarget || envTarget || 'DEFAULT';
65
-
66
- // 3. vue.config.js 标准字段
67
- const { vueConfig: vueCli, warnings: vueCliWarnings } = loadVueCliConfig(projectRoot, mode);
68
- const extraInfo = extractAdditionalVueConfigInfo(projectRoot);
69
-
70
- // 4. package.json inflyVite 字段
71
- const pkgConfig = loadPackageJsonConfig(projectRoot);
72
-
73
- // 5. infly.vite.config.js / .cjs / .mjs
74
- const { config: fileConfig, errors: fileErrors } = await loadInflyViteConfig(projectRoot, {
75
- command, mode, target: resolvedTarget, projectRoot, isBuild, isServe,
76
- });
77
-
78
- // 开始合并
79
- const merged = deepMerge(
80
- defaults,
81
- // vue.config.js → 标准字段映射
82
- {
83
- base: vueCli.base,
84
- outputDir: vueCli.outputDir,
85
- assetsDir: vueCli.assetsDir,
86
- productionSourceMap: vueCli.productionSourceMap,
87
- server: {
88
- port: vueCli.server?.port,
89
- proxy: vueCli.server?.proxy,
90
- },
91
- css: {
92
- additionalData: vueCli.css?.additionalData,
93
- },
94
- resolve: {
95
- alias: vueCli.resolve?.alias,
96
- },
97
- html: {
98
- title: vueCli.html?.title,
99
- },
100
- mock: extraInfo.mockEntry ? {
101
- enabled: true,
102
- entry: extraInfo.mockEntry,
103
- } : undefined,
104
- },
105
- // package.json inflyVite
106
- pkgConfig,
107
- // infly.vite.config.js
108
- fileConfig || {},
109
- // CLI 参数
110
- {
111
- context: { target: resolvedTarget },
112
- server: {
113
- port: cliOptions.port,
114
- host: cliOptions.host,
115
- open: cliOptions.open,
116
- strictPort: cliOptions.strictPort,
117
- },
118
- }
119
- );
120
-
121
- // Mock 默认值:serve 且存在 mock 入口时启用
122
- if (merged.mock.entry) {
123
- const mockFullPath = path.resolve(projectRoot, merged.mock.entry);
124
- if (fs.existsSync(mockFullPath)) {
125
- merged.mock.enabled = merged.mock.enabled !== false && isServe;
126
- } else if (merged.mock.enabled) {
127
- // mock 明确启用但文件不存在 → 记录但由 runner 决定
128
- }
129
- }
130
-
131
- // 严格兼容性验证
132
- let validation = { valid: true, errors: [] };
133
- let diagnoses = [];
134
-
135
- if (merged.strictCompatibility) {
136
- validation = validateStrictCompatibility(merged, {
137
- hasChainWebpack: vueCli.hasChainWebpack,
138
- hasFunctionConfigureWebpack: vueCli.hasFunctionConfigureWebpack,
139
- projectRoot,
140
- targets: Object.keys(fileConfig?.targets || {}),
141
- });
142
- } else {
143
- diagnoses = diagnoseCompatIssues(merged, {
144
- hasChainWebpack: vueCli.hasChainWebpack,
145
- hasFunctionConfigureWebpack: vueCli.hasFunctionConfigureWebpack,
146
- });
147
- }
148
-
149
- // 路径规范化
150
- if (merged.outputDir && !path.isAbsolute(merged.outputDir)) {
151
- merged.outputDir = path.resolve(projectRoot, merged.outputDir);
152
- }
153
-
154
- return {
155
- config: merged,
156
- env: { define, target: resolvedTarget, envVars: {} },
157
- meta: {
158
- vueCliWarnings,
159
- fileErrors,
160
- validation,
161
- diagnoses,
162
- resolvedTarget,
163
- },
164
- };
165
- }
166
-
167
- /**
168
- * 从 package.json 读取 inflyVite 字段
169
- */
170
- function loadPackageJsonConfig(projectRoot) {
171
- const pkgPath = path.join(projectRoot, 'package.json');
172
- if (!fs.existsSync(pkgPath)) return {};
173
-
174
- try {
175
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
176
- return pkg.inflyVite || {};
177
- } catch (_) {
178
- return {};
179
- }
180
- }
181
-
182
- /**
183
- * 加载 infly.vite.config.{mjs,js,cjs}
184
- *
185
- * @param {string} projectRoot
186
- * @param {object} context - { command, mode, target, projectRoot, isBuild, isServe }
187
- * @returns {Promise<{ config: object|null, errors: string[] }>}
188
- */
189
- async function loadInflyViteConfig(projectRoot, context) {
190
- // 检测多文件冲突
191
- const found = CONFIG_FILES.filter((name) =>
192
- fs.existsSync(path.join(projectRoot, name))
193
- );
194
-
195
- if (found.length > 1) {
196
- return {
197
- config: null,
198
- errors: [
199
- `检测到多个 infly.vite.config 文件: ${found.join(', ')}。请只保留一个。`
200
- ],
201
- };
202
- }
203
-
204
- if (found.length === 0) {
205
- return { config: null, errors: [] };
206
- }
207
-
208
- const configPath = path.join(projectRoot, found[0]);
209
- const ext = path.extname(found[0]);
210
-
211
- try {
212
- let rawConfig;
213
-
214
- if (ext === '.mjs') {
215
- // ESM 动态导入
216
- const imported = await import(`file://${configPath}`);
217
- rawConfig = imported.default || imported;
218
- } else if (ext === '.js' || ext === '.cjs') {
219
- // CJS require
220
- const projectRequire = createRequire(path.join(projectRoot, 'package.json'));
221
- rawConfig = projectRequire(configPath);
222
- } else {
223
- return { config: null, errors: [`不支持的配置文件扩展名: ${ext}`] };
224
- }
225
-
226
- // 函数形式
227
- if (typeof rawConfig === 'function') {
228
- rawConfig = rawConfig(context);
229
- }
230
-
231
- if (!rawConfig || typeof rawConfig !== 'object') {
232
- return { config: null, errors: [`${found[0]} 必须导出配置对象或函数`] };
233
- }
234
-
235
- return { config: rawConfig, errors: [] };
236
- } catch (err) {
237
- return {
238
- config: null,
239
- errors: [`无法加载 ${found[0]}: ${err.message}`],
240
- };
241
- }
242
- }
243
-
244
- /**
245
- * 读取 package.json 信息(用于获取项目名称等元数据)
246
- */
247
- export function readProjectMeta(projectRoot) {
248
- const pkgPath = path.join(projectRoot, 'package.json');
249
- if (!fs.existsSync(pkgPath)) return { name: 'unknown', version: '0.0.0' };
250
-
251
- try {
252
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
253
- return {
254
- name: pkg.name || path.basename(projectRoot),
255
- version: pkg.version || '0.0.0',
256
- description: pkg.description || '',
257
- };
258
- } catch (_) {
259
- return { name: path.basename(projectRoot), version: '0.0.0' };
260
- }
261
- }
1
+ /**
2
+ * 配置发现编排器
3
+ *
4
+ * 按优先级(从低到高)加载所有配置源并合并:
5
+ * 1. 包安全默认值
6
+ * 2. 项目 vue.config.js 标准字段
7
+ * 3. package.json 的 inflyVite 字段
8
+ * 4. infly.vite.config.js / .cjs / .mjs
9
+ * 5. CLI 参数
10
+ *
11
+ * 规范 §9.1
12
+ */
13
+
14
+ import fs from 'node:fs';
15
+ import path from 'node:path';
16
+ import { createRequire } from 'node:module';
17
+ import { createDefaultConfig } from './project-config.mjs';
18
+ import { loadVueCliConfig, extractAdditionalVueConfigInfo } from './vue-cli-reader.mjs';
19
+ import { buildDefine } from './env.mjs';
20
+ import { deepMerge } from './merge.mjs';
21
+ import { validateStrictCompatibility, diagnoseCompatIssues } from './validation.mjs';
22
+
23
+ /**
24
+ * 可选的 infly.vite.config 文件名(按优先级)
25
+ */
26
+ const CONFIG_FILES = [
27
+ 'infly.vite.config.mjs',
28
+ 'infly.vite.config.js',
29
+ 'infly.vite.config.cjs',
30
+ ];
31
+
32
+ /**
33
+ * @param {object} options
34
+ * @param {string} options.command - 'serve' | 'build'
35
+ * @param {string} options.mode - 模式
36
+ * @param {string} [options.target] - CLI target
37
+ * @param {string} options.projectRoot - 项目根目录
38
+ * @param {object} [options.cliOptions] - CLI 额外选项
39
+ * @returns {Promise<object>} 归一化配置 + 元信息
40
+ */
41
+ export async function discoverConfig(options = {}) {
42
+ const {
43
+ command = 'build',
44
+ mode = 'production',
45
+ target: cliTarget,
46
+ projectRoot = process.cwd(),
47
+ cliOptions = {},
48
+ } = options;
49
+
50
+ // test 命令复用 build 的配置语义(mode=test,读取 .env.test 等)
51
+ const isBuild = command === 'build' || command === 'test';
52
+ const isServe = command === 'serve';
53
+
54
+ // 1. 包默认值
55
+ const defaults = createDefaultConfig({ command, mode, target: cliTarget, projectRoot, isBuild, isServe });
56
+
57
+ // 2. 环境变量(解析 target)
58
+ const { target: envTarget, define } = buildDefine({
59
+ projectRoot,
60
+ mode,
61
+ target: cliTarget,
62
+ defaultTarget: defaults.context.target || 'DEFAULT',
63
+ });
64
+ const resolvedTarget = cliTarget || envTarget || 'DEFAULT';
65
+
66
+ // 3. vue.config.js 标准字段
67
+ const { vueConfig: vueCli, warnings: vueCliWarnings } = loadVueCliConfig(projectRoot, mode);
68
+ const extraInfo = extractAdditionalVueConfigInfo(projectRoot);
69
+
70
+ // 4. package.json inflyVite 字段
71
+ const pkgConfig = loadPackageJsonConfig(projectRoot);
72
+
73
+ // 5. infly.vite.config.js / .cjs / .mjs
74
+ const { config: fileConfig, errors: fileErrors } = await loadInflyViteConfig(projectRoot, {
75
+ command, mode, target: resolvedTarget, projectRoot, isBuild, isServe,
76
+ });
77
+
78
+ // 开始合并
79
+ const merged = deepMerge(
80
+ defaults,
81
+ // vue.config.js → 标准字段映射
82
+ {
83
+ base: vueCli.base,
84
+ outputDir: vueCli.outputDir,
85
+ assetsDir: vueCli.assetsDir,
86
+ productionSourceMap: vueCli.productionSourceMap,
87
+ server: {
88
+ port: vueCli.server?.port,
89
+ proxy: vueCli.server?.proxy,
90
+ },
91
+ css: {
92
+ additionalData: vueCli.css?.additionalData,
93
+ },
94
+ resolve: {
95
+ alias: vueCli.resolve?.alias,
96
+ },
97
+ html: {
98
+ title: vueCli.html?.title,
99
+ },
100
+ mock: extraInfo.mockEntry ? {
101
+ enabled: true,
102
+ entry: extraInfo.mockEntry,
103
+ } : undefined,
104
+ },
105
+ // package.json inflyVite
106
+ pkgConfig,
107
+ // infly.vite.config.js
108
+ fileConfig || {},
109
+ // CLI 参数
110
+ {
111
+ context: { target: resolvedTarget },
112
+ server: {
113
+ port: cliOptions.port,
114
+ host: cliOptions.host,
115
+ open: cliOptions.open,
116
+ strictPort: cliOptions.strictPort,
117
+ },
118
+ }
119
+ );
120
+
121
+ // Mock 默认值:serve 且存在 mock 入口时启用
122
+ if (merged.mock.entry) {
123
+ const mockFullPath = path.resolve(projectRoot, merged.mock.entry);
124
+ if (fs.existsSync(mockFullPath)) {
125
+ merged.mock.enabled = merged.mock.enabled !== false && isServe;
126
+ } else if (merged.mock.enabled) {
127
+ // mock 明确启用但文件不存在 → 记录但由 runner 决定
128
+ }
129
+ }
130
+
131
+ // 严格兼容性验证
132
+ let validation = { valid: true, errors: [] };
133
+ let diagnoses = [];
134
+
135
+ if (merged.strictCompatibility) {
136
+ validation = validateStrictCompatibility(merged, {
137
+ hasChainWebpack: vueCli.hasChainWebpack,
138
+ hasFunctionConfigureWebpack: vueCli.hasFunctionConfigureWebpack,
139
+ projectRoot,
140
+ targets: Object.keys(fileConfig?.targets || {}),
141
+ });
142
+ } else {
143
+ diagnoses = diagnoseCompatIssues(merged, {
144
+ hasChainWebpack: vueCli.hasChainWebpack,
145
+ hasFunctionConfigureWebpack: vueCli.hasFunctionConfigureWebpack,
146
+ });
147
+ }
148
+
149
+ // 路径规范化
150
+ if (merged.outputDir && !path.isAbsolute(merged.outputDir)) {
151
+ merged.outputDir = path.resolve(projectRoot, merged.outputDir);
152
+ }
153
+
154
+ return {
155
+ config: merged,
156
+ env: { define, target: resolvedTarget, envVars: {} },
157
+ meta: {
158
+ vueCliWarnings,
159
+ fileErrors,
160
+ validation,
161
+ diagnoses,
162
+ resolvedTarget,
163
+ },
164
+ };
165
+ }
166
+
167
+ /**
168
+ * 从 package.json 读取 inflyVite 字段
169
+ */
170
+ function loadPackageJsonConfig(projectRoot) {
171
+ const pkgPath = path.join(projectRoot, 'package.json');
172
+ if (!fs.existsSync(pkgPath)) return {};
173
+
174
+ try {
175
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
176
+ return pkg.inflyVite || {};
177
+ } catch {
178
+ return {};
179
+ }
180
+ }
181
+
182
+ /**
183
+ * 加载 infly.vite.config.{mjs,js,cjs}
184
+ *
185
+ * @param {string} projectRoot
186
+ * @param {object} context - { command, mode, target, projectRoot, isBuild, isServe }
187
+ * @returns {Promise<{ config: object|null, errors: string[] }>}
188
+ */
189
+ async function loadInflyViteConfig(projectRoot, context) {
190
+ // 检测多文件冲突
191
+ const found = CONFIG_FILES.filter((name) =>
192
+ fs.existsSync(path.join(projectRoot, name))
193
+ );
194
+
195
+ if (found.length > 1) {
196
+ return {
197
+ config: null,
198
+ errors: [
199
+ `检测到多个 infly.vite.config 文件: ${found.join(', ')}。请只保留一个。`
200
+ ],
201
+ };
202
+ }
203
+
204
+ if (found.length === 0) {
205
+ return { config: null, errors: [] };
206
+ }
207
+
208
+ const configPath = path.join(projectRoot, found[0]);
209
+ const ext = path.extname(found[0]);
210
+
211
+ try {
212
+ let rawConfig;
213
+
214
+ if (ext === '.mjs') {
215
+ // ESM 动态导入
216
+ const imported = await import(`file://${configPath}`);
217
+ rawConfig = imported.default || imported;
218
+ } else if (ext === '.js' || ext === '.cjs') {
219
+ // CJS require
220
+ const projectRequire = createRequire(path.join(projectRoot, 'package.json'));
221
+ rawConfig = projectRequire(configPath);
222
+ } else {
223
+ return { config: null, errors: [`不支持的配置文件扩展名: ${ext}`] };
224
+ }
225
+
226
+ // 函数形式
227
+ if (typeof rawConfig === 'function') {
228
+ rawConfig = rawConfig(context);
229
+ }
230
+
231
+ if (!rawConfig || typeof rawConfig !== 'object') {
232
+ return { config: null, errors: [`${found[0]} 必须导出配置对象或函数`] };
233
+ }
234
+
235
+ return { config: rawConfig, errors: [] };
236
+ } catch (err) {
237
+ return {
238
+ config: null,
239
+ errors: [`无法加载 ${found[0]}: ${err.message}`],
240
+ };
241
+ }
242
+ }
243
+
244
+ /**
245
+ * 读取 package.json 信息(用于获取项目名称等元数据)
246
+ */
247
+ export function readProjectMeta(projectRoot) {
248
+ const pkgPath = path.join(projectRoot, 'package.json');
249
+ if (!fs.existsSync(pkgPath)) return { name: 'unknown', version: '0.0.0' };
250
+
251
+ try {
252
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
253
+ return {
254
+ name: pkg.name || path.basename(projectRoot),
255
+ version: pkg.version || '0.0.0',
256
+ description: pkg.description || '',
257
+ };
258
+ } catch {
259
+ return { name: path.basename(projectRoot), version: '0.0.0' };
260
+ }
261
+ }
@@ -32,6 +32,7 @@ import { createRequire } from 'node:module';
32
32
  * @returns {object} { vueConfig, warnings }
33
33
  */
34
34
  export function loadVueCliConfig(projectRoot, mode) {
35
+ void mode;
35
36
  const vueConfigPath = path.join(projectRoot, 'vue.config.js');
36
37
  const warnings = [];
37
38
 
@@ -71,7 +71,7 @@ function resolveDependencyForOptimize(requireFn, dependency, workspacePackagesDi
71
71
  return false;
72
72
  }
73
73
  return true;
74
- } catch (_) {
74
+ } catch {
75
75
  // Optional or currently inactive dependencies remain discoverable at runtime.
76
76
  return false;
77
77
  }
@@ -144,7 +144,7 @@ function resolveNestedDependencyAliases(projectRoot) {
144
144
  find: nestedDependency,
145
145
  replacement: path.dirname(packageJsonPath),
146
146
  });
147
- } catch (_) {
147
+ } catch {
148
148
  // The project does not use this optional compatibility dependency.
149
149
  }
150
150
  }
@@ -188,7 +188,7 @@ function resolvePnpmStorePaths(projectRoot) {
188
188
  const realPath = fs.realpathSync(pnpmStoreLink);
189
189
  paths.push(realPath);
190
190
  }
191
- } catch (_) {
191
+ } catch {
192
192
  // 忽略错误
193
193
  }
194
194
 
@@ -208,11 +208,11 @@ function resolvePnpmStorePaths(projectRoot) {
208
208
  const realEntryPath = fs.realpathSync(appRequire.resolve(dependency));
209
209
  const storeRoot = findPnpmStoreRoot(realEntryPath);
210
210
  if (storeRoot && !paths.includes(storeRoot)) paths.push(storeRoot);
211
- } catch (_) {
211
+ } catch {
212
212
  // 未安装或没有可解析入口的依赖不影响其他 store 路径发现。
213
213
  }
214
214
  }
215
- } catch (_) {
215
+ } catch {
216
216
  // 缺失或无效的 package.json 由后续配置流程报告。
217
217
  }
218
218
 
@@ -261,7 +261,6 @@ function prepareViteHtml(config, projectRoot) {
261
261
  const {
262
262
  htmlTemplate = 'public/index.html',
263
263
  mainEntry = 'src/main.js',
264
- mock = {},
265
264
  } = config;
266
265
 
267
266
  const htmlOptions = {
@@ -320,7 +319,7 @@ export function createViteConfig(config) {
320
319
  // 构建期在真实 workspace 解析,工厂只组装配置、不在组装期崩溃。
321
320
  try {
322
321
  return projectRequire.resolve('vue/dist/vue.esm.js');
323
- } catch (_) {
322
+ } catch {
324
323
  return 'vue/dist/vue.esm.js';
325
324
  }
326
325
  })();
@@ -338,7 +337,7 @@ export function createViteConfig(config) {
338
337
  try {
339
338
  const echartsDir = path.dirname(projectRequire.resolve('echarts'));
340
339
  aliases.push({ find: 'echarts', replacement: echartsDir });
341
- } catch (_) {
340
+ } catch {
342
341
  // 当前应用未使用 echarts
343
342
  }
344
343
 
@@ -13,6 +13,7 @@
13
13
  * @returns {Function}
14
14
  */
15
15
  export function buildManualChunks(projectRoot, overrides = {}) {
16
+ void overrides;
16
17
  return function manualChunks(id, { getModuleInfo }) {
17
18
  const mp = id.replace(/\\/g, '/');
18
19