@infly/vue2-vite 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/LICENSE +15 -0
- package/README.md +307 -0
- package/bin/infly-vue2-vite.mjs +12 -0
- package/bin/vue-cli-service.mjs +135 -0
- package/package.json +71 -0
- package/src/cli/arguments.mjs +197 -0
- package/src/cli/node-version.mjs +46 -0
- package/src/cli/run.mjs +122 -0
- package/src/compat/assets.mjs +165 -0
- package/src/compat/commonjs.mjs +93 -0
- package/src/compat/empty-stub.mjs +58 -0
- package/src/compat/html.mjs +244 -0
- package/src/compat/import-interop.mjs +200 -0
- package/src/compat/jsx.mjs +142 -0
- package/src/compat/mock.mjs +125 -0
- package/src/compat/require-context.mjs +157 -0
- package/src/compat/router.mjs +62 -0
- package/src/compat/sass-export.mjs +112 -0
- package/src/compat/sass-importer.mjs +30 -0
- package/src/compat/svg-icons.mjs +35 -0
- package/src/config/discover.mjs +261 -0
- package/src/config/env.mjs +148 -0
- package/src/config/merge.mjs +65 -0
- package/src/config/project-config.mjs +87 -0
- package/src/config/registered.mjs +152 -0
- package/src/config/validation.mjs +122 -0
- package/src/config/vue-cli-reader.mjs +207 -0
- package/src/factory/build-policy.mjs +39 -0
- package/src/factory/create-vite-config.mjs +648 -0
- package/src/factory/manual-chunks.mjs +55 -0
- package/src/factory/output-names.mjs +62 -0
- package/src/index.mjs +55 -0
- package/src/runner/build.mjs +43 -0
- package/src/runner/serve.mjs +44 -0
- package/src/runner/signals.mjs +29 -0
- package/src/runner/test.mjs +190 -0
- package/src/runner/workspace.cjs +346 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 产物命名
|
|
3
|
+
*
|
|
4
|
+
* 定义 Vite build 输出文件命名规则:
|
|
5
|
+
* static/js/app-[hash:8].js
|
|
6
|
+
* static/js/chunk-[hash:8].js
|
|
7
|
+
* static/css/style-[hash:8].css
|
|
8
|
+
* static/images/asset-[hash:8].[ext]
|
|
9
|
+
* static/fonts/font-[hash:8].[ext]
|
|
10
|
+
* static/media/asset-[hash:8].[ext]
|
|
11
|
+
*
|
|
12
|
+
* 从 factory.js createBuildOutput 迁移。
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
|
|
17
|
+
const NAMED_VENDOR_CHUNKS = new Map([
|
|
18
|
+
['chunk-vue', 'vendor-vue'],
|
|
19
|
+
['chunk-element-ui', 'vendor-element-ui'],
|
|
20
|
+
['chunk-echarts', 'vendor-echarts'],
|
|
21
|
+
['chunk-utils', 'vendor-utils'],
|
|
22
|
+
['chunk-infly-ui', 'vendor-infly-ui'],
|
|
23
|
+
['chunk-infly-libs', 'vendor-infly-libs'],
|
|
24
|
+
['chunk-commons', 'vendor-commons'],
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 创建 Rollup output 配置
|
|
29
|
+
*
|
|
30
|
+
* @param {object} [overrides] - { namedVendorChunks? }
|
|
31
|
+
* @returns {object} Rollup output options
|
|
32
|
+
*/
|
|
33
|
+
export function createBuildOutput(overrides = {}) {
|
|
34
|
+
const vendorChunks = overrides.namedVendorChunks || NAMED_VENDOR_CHUNKS;
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
hashCharacters: 'hex',
|
|
38
|
+
entryFileNames() {
|
|
39
|
+
return 'static/js/app-[hash:8].js';
|
|
40
|
+
},
|
|
41
|
+
chunkFileNames(chunkInfo) {
|
|
42
|
+
const vendorName = vendorChunks.get(chunkInfo.name);
|
|
43
|
+
const prefix = vendorName || 'chunk';
|
|
44
|
+
return `static/js/${prefix}-[hash:8].js`;
|
|
45
|
+
},
|
|
46
|
+
assetFileNames(assetInfo) {
|
|
47
|
+
const originalName = assetInfo.names?.[0] || assetInfo.name || '';
|
|
48
|
+
const extension = path.extname(originalName).toLowerCase();
|
|
49
|
+
if (extension === '.css') return 'static/css/style-[hash:8][extname]';
|
|
50
|
+
if (/\.(png|jpe?g|gif|svg|webp|avif|ico)$/.test(extension)) {
|
|
51
|
+
return 'static/images/asset-[hash:8][extname]';
|
|
52
|
+
}
|
|
53
|
+
if (/\.(woff2?|eot|ttf|otf)$/.test(extension)) {
|
|
54
|
+
return 'static/fonts/font-[hash:8][extname]';
|
|
55
|
+
}
|
|
56
|
+
if (/\.(mp4|webm|ogg|mp3|wav|flac|aac)$/.test(extension)) {
|
|
57
|
+
return 'static/media/asset-[hash:8][extname]';
|
|
58
|
+
}
|
|
59
|
+
return 'static/assets/asset-[hash:8][extname]';
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
package/src/index.mjs
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @infly/vue2-vite 公开 Node API
|
|
3
|
+
*
|
|
4
|
+
* 提供编程式访问 Vite 兼容构建能力。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// CLI 信息
|
|
8
|
+
export { EXIT_CODES, run } from './cli/run.mjs';
|
|
9
|
+
|
|
10
|
+
// 配置
|
|
11
|
+
export { discoverConfig } from './config/discover.mjs';
|
|
12
|
+
export { buildDefine, parseEnvFile, loadEnvFiles, resolveTarget } from './config/env.mjs';
|
|
13
|
+
export { createDefaultConfig } from './config/project-config.mjs';
|
|
14
|
+
export {
|
|
15
|
+
extractAdditionalVueConfigInfo,
|
|
16
|
+
loadVueCliConfig,
|
|
17
|
+
} from './config/vue-cli-reader.mjs';
|
|
18
|
+
export {
|
|
19
|
+
createRegisteredConfig,
|
|
20
|
+
createRegisteredViteConfig,
|
|
21
|
+
} from './config/registered.mjs';
|
|
22
|
+
|
|
23
|
+
// 工厂
|
|
24
|
+
export { createViteConfig } from './factory/create-vite-config.mjs';
|
|
25
|
+
export { resolveBuildPolicy } from './factory/build-policy.mjs';
|
|
26
|
+
|
|
27
|
+
// Runner
|
|
28
|
+
export { serve } from './runner/serve.mjs';
|
|
29
|
+
export { build, dryRun } from './runner/build.mjs';
|
|
30
|
+
|
|
31
|
+
// 兼容插件(供高级用户扩展)
|
|
32
|
+
export {
|
|
33
|
+
generateGlobReplacement,
|
|
34
|
+
requireContextPlugin,
|
|
35
|
+
} from './compat/require-context.mjs';
|
|
36
|
+
export { assetRequirePlugin, transformAssetRequires } from './compat/assets.mjs';
|
|
37
|
+
export { commonJsPlugin, transformCommonJsModule } from './compat/commonjs.mjs';
|
|
38
|
+
export { transformJsx, jsxPrePlugin } from './compat/jsx.mjs';
|
|
39
|
+
export { createScssExportCompatPlugin, addAppRootSassLoadPath } from './compat/sass-export.mjs';
|
|
40
|
+
export { vueRouterPromisePlugin } from './compat/router.mjs';
|
|
41
|
+
export { createSvgIconPlugin } from './compat/svg-icons.mjs';
|
|
42
|
+
export {
|
|
43
|
+
mockPlugin,
|
|
44
|
+
createMockMiddleware,
|
|
45
|
+
hasMockServer,
|
|
46
|
+
} from './compat/mock.mjs';
|
|
47
|
+
export {
|
|
48
|
+
generateViteHtml,
|
|
49
|
+
replaceEjsTokens,
|
|
50
|
+
injectViteEntry,
|
|
51
|
+
validateEjsTemplate,
|
|
52
|
+
KNOWN_EJS_TOKENS,
|
|
53
|
+
} from './compat/html.mjs';
|
|
54
|
+
export { emptyStubPlugin } from './compat/empty-stub.mjs';
|
|
55
|
+
export { importInteropPlugin, transformImportInterop } from './compat/import-interop.mjs';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite build runner
|
|
3
|
+
*
|
|
4
|
+
* 使用 Vite Node API 执行生产构建。
|
|
5
|
+
* 替代原 vite-runner.js 的子进程方式。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { build as viteBuild } from 'vite';
|
|
9
|
+
|
|
10
|
+
const C_GREEN = '\x1b[32m';
|
|
11
|
+
const C_RED = '\x1b[31m';
|
|
12
|
+
const C_RESET = '\x1b[0m';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 执行 Vite build
|
|
16
|
+
*
|
|
17
|
+
* @param {import('vite').UserConfig} viteConfig - Vite 配置
|
|
18
|
+
* @returns {Promise<void>}
|
|
19
|
+
*/
|
|
20
|
+
export async function build(viteConfig) {
|
|
21
|
+
try {
|
|
22
|
+
await viteBuild(viteConfig);
|
|
23
|
+
console.log(`${C_GREEN}@infly/vue2-vite 构建完成${C_RESET}`);
|
|
24
|
+
} catch (err) {
|
|
25
|
+
console.error(`${C_RED}@infly/vue2-vite 构建失败:\n${err.stack || err.message}${C_RESET}`);
|
|
26
|
+
throw err;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Dry-run 模式:仅打印构建信息,不实际构建
|
|
32
|
+
*
|
|
33
|
+
* @param {object} config - 归一化配置
|
|
34
|
+
*/
|
|
35
|
+
export function dryRun(config) {
|
|
36
|
+
const { command, mode, target, projectRoot } = config.context || {};
|
|
37
|
+
console.log('@infly/vue2-vite dry-run:');
|
|
38
|
+
console.log(` 命令: ${command}`);
|
|
39
|
+
console.log(` mode: ${mode}`);
|
|
40
|
+
console.log(` target: ${target}`);
|
|
41
|
+
console.log(` 项目: ${projectRoot}`);
|
|
42
|
+
console.log(` 输出: ${config.outputDir}`);
|
|
43
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite dev server runner
|
|
3
|
+
*
|
|
4
|
+
* 使用 Vite Node API 启动 dev server。
|
|
5
|
+
* 替代原 vite-runner.js 的子进程方式。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createServer } from 'vite';
|
|
9
|
+
import { registerSignalHandlers } from './signals.mjs';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 启动 Vite dev server
|
|
13
|
+
*
|
|
14
|
+
* @param {import('vite').UserConfig} viteConfig - Vite 配置
|
|
15
|
+
* @returns {Promise<import('vite').ViteDevServer>}
|
|
16
|
+
*/
|
|
17
|
+
export async function serve(viteConfig) {
|
|
18
|
+
let server;
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
server = await createServer(viteConfig);
|
|
22
|
+
|
|
23
|
+
// 注册信号处理(Ctrl+C 优雅退出)
|
|
24
|
+
registerSignalHandlers(async () => {
|
|
25
|
+
if (server) {
|
|
26
|
+
await server.close();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
await server.listen();
|
|
31
|
+
|
|
32
|
+
server.printUrls();
|
|
33
|
+
server.bindCLIShortcuts({ print: true });
|
|
34
|
+
|
|
35
|
+
return server;
|
|
36
|
+
} catch (err) {
|
|
37
|
+
// 可能部分启动失败(如端口占用),但 mock/middleware 错误不阻止启动
|
|
38
|
+
console.error(`@infly/vue2-vite dev server 启动失败:\n${err.stack || err.message}`);
|
|
39
|
+
if (server) {
|
|
40
|
+
await server.close();
|
|
41
|
+
}
|
|
42
|
+
throw err;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 进程信号处理
|
|
3
|
+
*
|
|
4
|
+
* SIGINT/SIGTERM 转发,确保子进程正常退出。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 为异步操作注册信号处理
|
|
9
|
+
*
|
|
10
|
+
* @param {() => Promise<void>} cleanup - 清理回调
|
|
11
|
+
* @returns {() => void} 移除监听器的函数
|
|
12
|
+
*/
|
|
13
|
+
export function registerSignalHandlers(cleanup) {
|
|
14
|
+
const handler = (signal) => {
|
|
15
|
+
console.log(`\n@infly/vue2-vite 收到 ${signal},正在退出...`);
|
|
16
|
+
Promise.resolve()
|
|
17
|
+
.then(() => cleanup())
|
|
18
|
+
.then(() => process.exit(0))
|
|
19
|
+
.catch(() => process.exit(1));
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
process.on('SIGINT', handler);
|
|
23
|
+
process.on('SIGTERM', handler);
|
|
24
|
+
|
|
25
|
+
return () => {
|
|
26
|
+
process.off('SIGINT', handler);
|
|
27
|
+
process.off('SIGTERM', handler);
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vitest 测试 runner
|
|
3
|
+
*
|
|
4
|
+
* 从已生成的 Vite UserConfig 提取对测试有意义的子集(alias、define、css
|
|
5
|
+
* preprocessorOptions),配合 @vitejs/plugin-vue2 生成临时 vitest 配置并转交
|
|
6
|
+
* vitest CLI 运行。临时配置写入系统临时目录,不污染项目(维持"子仓零改动")。
|
|
7
|
+
*
|
|
8
|
+
* jest API 兼容:启用 globals(describe/it/expect/vi/mock 等全局可用),
|
|
9
|
+
* 使既有 jest 测试文件无需逐文件改写即可运行。
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import os from 'node:os';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import { spawn } from 'node:child_process';
|
|
16
|
+
import { createRequire } from 'node:module';
|
|
17
|
+
import { pathToFileURL } from 'node:url';
|
|
18
|
+
|
|
19
|
+
const require = createRequire(import.meta.url);
|
|
20
|
+
|
|
21
|
+
function cloneConfigValue(value) {
|
|
22
|
+
if (value instanceof RegExp) return value;
|
|
23
|
+
if (Array.isArray(value)) {
|
|
24
|
+
return value
|
|
25
|
+
.map((entry) => cloneConfigValue(entry))
|
|
26
|
+
.filter((entry) => entry !== undefined);
|
|
27
|
+
}
|
|
28
|
+
if (value && typeof value === 'object') {
|
|
29
|
+
return Object.fromEntries(
|
|
30
|
+
Object.entries(value)
|
|
31
|
+
.map(([key, entry]) => [key, cloneConfigValue(entry)])
|
|
32
|
+
.filter(([, entry]) => entry !== undefined),
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
if (typeof value === 'function' || value === undefined) return undefined;
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function serializeJavaScript(value) {
|
|
40
|
+
if (value instanceof RegExp) return value.toString();
|
|
41
|
+
if (Array.isArray(value)) return `[${value.map(serializeJavaScript).join(', ')}]`;
|
|
42
|
+
if (value && typeof value === 'object') {
|
|
43
|
+
return `{${Object.entries(value)
|
|
44
|
+
.map(([key, entry]) => `${JSON.stringify(key)}: ${serializeJavaScript(entry)}`)
|
|
45
|
+
.join(', ')}}`;
|
|
46
|
+
}
|
|
47
|
+
return JSON.stringify(value);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 解析 vitest CLI 入口(vitest 4 的 exports 不暴露 vitest.mjs,需读 bin 字段)
|
|
52
|
+
*/
|
|
53
|
+
function resolveVitestCli() {
|
|
54
|
+
try {
|
|
55
|
+
const packageJsonPath = require.resolve('vitest/package.json');
|
|
56
|
+
const binField = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')).bin;
|
|
57
|
+
const binPath = typeof binField === 'string' ? binField : binField?.vitest;
|
|
58
|
+
if (!binPath) return null;
|
|
59
|
+
return path.resolve(path.dirname(packageJsonPath), binPath);
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 生成 vitest 配置对象(可序列化的纯数据)
|
|
67
|
+
*
|
|
68
|
+
* @param {object} viteConfig - createViteConfig 的产物
|
|
69
|
+
* @param {object} config - 归一化项目配置
|
|
70
|
+
* @param {string} projectRoot
|
|
71
|
+
* @returns {object} 可 JSON 序列化的 vitest inline 配置数据
|
|
72
|
+
*/
|
|
73
|
+
export function createVitestConfigData(viteConfig, config, projectRoot) {
|
|
74
|
+
const include = [
|
|
75
|
+
'tests/**/*.{test,spec}.{js,mjs,ts}',
|
|
76
|
+
'tests/unit/**/*.{test,spec}.{js,mjs,ts}',
|
|
77
|
+
'src/**/*.{test,spec}.{js,mjs,ts}',
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
const css = cloneConfigValue(viteConfig?.css);
|
|
81
|
+
const sassOptions = css?.preprocessorOptions?.scss;
|
|
82
|
+
const hasSassImporter = Boolean(
|
|
83
|
+
viteConfig?.css?.preprocessorOptions?.scss?.importers?.length,
|
|
84
|
+
);
|
|
85
|
+
if (sassOptions) delete sassOptions.importers;
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
root: projectRoot,
|
|
89
|
+
resolve: {
|
|
90
|
+
// alias 数组(find/replacement,绝对路径)已在 Vite UserConfig 中解析好
|
|
91
|
+
...(viteConfig?.resolve?.alias ? { alias: viteConfig.resolve.alias } : {}),
|
|
92
|
+
},
|
|
93
|
+
...(viteConfig?.define ? { define: viteConfig.define } : {}),
|
|
94
|
+
...(css ? { css } : {}),
|
|
95
|
+
...(hasSassImporter ? { __inflySassTildeImporterRoot: projectRoot } : {}),
|
|
96
|
+
test: {
|
|
97
|
+
environment: 'jsdom',
|
|
98
|
+
globals: true,
|
|
99
|
+
include,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 把配置数据写成临时 vitest 配置文件,返回 { file, cleanup }
|
|
106
|
+
*
|
|
107
|
+
* 临时文件位于系统临时目录,vitest 与 vue2 插件均以绝对路径导入(vitest 4
|
|
108
|
+
* 移除了 'vitest/config' 子路径且临时目录不在包解析链上),配置完全自包含。
|
|
109
|
+
*/
|
|
110
|
+
export function writeTempVitestConfig(data, vue2PluginPath) {
|
|
111
|
+
const vitestPackageRoot = path.dirname(require.resolve('vitest/package.json'));
|
|
112
|
+
// vitest 4:defineConfig 在 dist/config.js(dist/index.js 不导出;无 'vitest/config' 子路径)
|
|
113
|
+
const vitestConfigImport = pathToFileURL(
|
|
114
|
+
path.join(vitestPackageRoot, 'dist', 'config.js'),
|
|
115
|
+
).href;
|
|
116
|
+
const pluginImport = pathToFileURL(vue2PluginPath).href;
|
|
117
|
+
const sassImporterImport = new URL('../compat/sass-importer.mjs', import.meta.url).href;
|
|
118
|
+
const source = [
|
|
119
|
+
`import { defineConfig } from ${JSON.stringify(vitestConfigImport)};`,
|
|
120
|
+
`import vue2 from ${JSON.stringify(pluginImport)};`,
|
|
121
|
+
`import { createSassTildeImporter } from ${JSON.stringify(sassImporterImport)};`,
|
|
122
|
+
`const config = ${serializeJavaScript(data)};`,
|
|
123
|
+
'config.plugins = [vue2()];',
|
|
124
|
+
'config.test.onConsoleLog = () => undefined;',
|
|
125
|
+
'if (config.__inflySassTildeImporterRoot) {',
|
|
126
|
+
' const importerRoot = config.__inflySassTildeImporterRoot;',
|
|
127
|
+
' delete config.__inflySassTildeImporterRoot;',
|
|
128
|
+
' config.css.preprocessorOptions.scss.importers = [createSassTildeImporter(importerRoot)];',
|
|
129
|
+
'}',
|
|
130
|
+
'export default defineConfig(config);',
|
|
131
|
+
'',
|
|
132
|
+
].join('\n');
|
|
133
|
+
|
|
134
|
+
const file = path.join(
|
|
135
|
+
os.tmpdir(),
|
|
136
|
+
`infly-vue2-vite-vitest-${process.pid}-${Date.now()}.mjs`,
|
|
137
|
+
);
|
|
138
|
+
fs.writeFileSync(file, source, 'utf8');
|
|
139
|
+
return {
|
|
140
|
+
file,
|
|
141
|
+
cleanup: () => fs.rmSync(file, { force: true }),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* 运行 vitest(一次性;--watch 时进入监听模式)
|
|
147
|
+
*
|
|
148
|
+
* @param {object} viteConfig - Vite UserConfig 产物
|
|
149
|
+
* @param {object} config - 归一化项目配置
|
|
150
|
+
* @param {object} options - { projectRoot, watch, passthrough }
|
|
151
|
+
* @returns {Promise<number>} vitest 退出码
|
|
152
|
+
*/
|
|
153
|
+
export async function runTest(viteConfig, config, options = {}) {
|
|
154
|
+
const projectRoot = options.projectRoot || process.cwd();
|
|
155
|
+
const vitestCli = resolveVitestCli();
|
|
156
|
+
if (!vitestCli) {
|
|
157
|
+
throw new Error('找不到 vitest CLI。请确认 @infly/vue2-vite 安装了 vitest 依赖。');
|
|
158
|
+
}
|
|
159
|
+
const vue2PluginPath = require.resolve('@vitejs/plugin-vue2');
|
|
160
|
+
|
|
161
|
+
const data = createVitestConfigData(viteConfig, config, projectRoot);
|
|
162
|
+
const { file, cleanup } = writeTempVitestConfig(data, vue2PluginPath);
|
|
163
|
+
|
|
164
|
+
const finalArgs = options.watch
|
|
165
|
+
? ['--config', file, ...(options.passthrough || [])]
|
|
166
|
+
: ['run', '--config', file, ...(options.passthrough || [])];
|
|
167
|
+
|
|
168
|
+
return await new Promise((resolve) => {
|
|
169
|
+
const child = spawn(process.execPath, [vitestCli, ...finalArgs], {
|
|
170
|
+
cwd: projectRoot,
|
|
171
|
+
env: process.env,
|
|
172
|
+
stdio: 'inherit',
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
['SIGINT', 'SIGTERM'].forEach((sig) => {
|
|
176
|
+
process.once(sig, () => child.kill(sig));
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
child.once('error', (err) => {
|
|
180
|
+
cleanup();
|
|
181
|
+
console.error(`@infly/vue2-vite vitest 启动失败: ${err.message}`);
|
|
182
|
+
resolve(1);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
child.once('exit', (code) => {
|
|
186
|
+
cleanup();
|
|
187
|
+
resolve(typeof code === 'number' ? code : 1);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
}
|