mm_statics 1.6.6 → 1.6.9
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/index.js +28 -132
- package/package.json +7 -6
- package/vue_compiler.js +276 -0
package/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
let send = require('koa-send');
|
|
2
2
|
const { EsToAmdConvert } = require('mm_es6_to_amd');
|
|
3
|
-
const
|
|
4
|
-
const { compile } = require('@vue/compiler-dom');
|
|
3
|
+
const VueSFCCompiler = require('./vue_compiler.js');
|
|
5
4
|
const prettier = require('prettier');
|
|
6
5
|
const { marked } = require('marked');
|
|
7
6
|
|
|
7
|
+
var vueCompiler = new VueSFCCompiler();
|
|
8
|
+
|
|
8
9
|
/**
|
|
9
10
|
* 静态文件处理类
|
|
10
11
|
*/
|
|
@@ -45,11 +46,11 @@ class Static {
|
|
|
45
46
|
// 需要转换的静态文件扩展名
|
|
46
47
|
files: ['.js', '.vue', '.html'],
|
|
47
48
|
// 是否转换ES6模块为AMD模块
|
|
48
|
-
convert_amd:
|
|
49
|
+
convert_amd: false, // 修改为 false,避免 Vue 文件被错误转换为 AMD 格式
|
|
49
50
|
// 是否开启文件监听
|
|
50
51
|
watch: false,
|
|
51
52
|
// 监听的文件扩展名
|
|
52
|
-
watch_files: ['.js', '.css', '.html', '.vue', '.json', '.md'
|
|
53
|
+
watch_files: ['.js', '.css', '.html', '.vue', '.json', '.md']
|
|
53
54
|
};
|
|
54
55
|
|
|
55
56
|
/**
|
|
@@ -256,135 +257,26 @@ Static.prototype._toAmd = async function (file_type, text) {
|
|
|
256
257
|
return result;
|
|
257
258
|
};
|
|
258
259
|
|
|
259
|
-
/**
|
|
260
|
-
* 处理Vue模板部分
|
|
261
|
-
* @param {object} desc Vue组件描述符
|
|
262
|
-
* @returns {string} 编译后的render函数
|
|
263
|
-
*/
|
|
264
|
-
Static.prototype._processTemplate = function (desc) {
|
|
265
|
-
if (!desc.template) return '';
|
|
266
|
-
|
|
267
|
-
const template_result = compile(desc.template.content, {
|
|
268
|
-
mode: 'module'
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
// 提取render函数代码,去除import语句和export语句
|
|
272
|
-
let render_function = template_result.code
|
|
273
|
-
.replace(/^import[^;]+;\s*/gm, '')
|
|
274
|
-
.replace(/^export[^;]+;\s*/gm, '')
|
|
275
|
-
.trim();
|
|
276
260
|
|
|
277
|
-
// 如果render函数包含函数定义,提取函数体
|
|
278
|
-
let render_match = render_function.match(/function\s+render\s*\([^)]*\)\s*{([\s\S]*?)}\s*$/);
|
|
279
|
-
if (render_match) {
|
|
280
|
-
render_function = `function render(_ctx, _cache) {${render_match[1]}}`;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
return render_function;
|
|
284
|
-
};
|
|
285
261
|
|
|
286
262
|
/**
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
Static.prototype.
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
let script_content = desc.script.content;
|
|
298
|
-
|
|
299
|
-
// 提取import语句
|
|
300
|
-
let imports = '';
|
|
301
|
-
let import_match = script_content.match(/import[^;]+;/g);
|
|
302
|
-
if (import_match) {
|
|
303
|
-
imports = import_match.join('\n') + '\n';
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// 提取export default部分,保留完整的组件定义
|
|
307
|
-
let export_match = script_content.match(/export\s+default\s*({[\s\S]*?})\s*$/s);
|
|
308
|
-
if (export_match) {
|
|
309
|
-
return this._buildCompWithExport(export_match[1], imports, render_function);
|
|
310
|
-
} else {
|
|
311
|
-
return this._buildDefaultComp(imports, render_function);
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* 创建默认组件结构
|
|
317
|
-
* @param {string} render_function render函数
|
|
318
|
-
* @returns {string} 默认组件代码
|
|
319
|
-
*/
|
|
320
|
-
Static.prototype._createDefaultComp = function (render_function) {
|
|
321
|
-
return `
|
|
322
|
-
export default {
|
|
323
|
-
name: 'VueComponent',
|
|
324
|
-
data() {
|
|
325
|
-
return {}
|
|
326
|
-
}${render_function ? `,\n render: ${render_function}` : ''}\n};
|
|
327
|
-
`;
|
|
328
|
-
};
|
|
263
|
+
* 编译Vue组件
|
|
264
|
+
* @param {string} code Vue组件代码
|
|
265
|
+
* @param {string} filePath 文件路径
|
|
266
|
+
* @returns {Promise<string>} 可直接调用的JavaScript组件代码
|
|
267
|
+
*/
|
|
268
|
+
Static.prototype._compileVue = async function (code, filePath = '') {
|
|
269
|
+
try {
|
|
270
|
+
// 使用修复后的 Vue 编译器
|
|
271
|
+
const { code: compiledCode } = await vueCompiler.toJS(code, filePath);
|
|
329
272
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
*/
|
|
337
|
-
Static.prototype._buildCompWithExport = function (code_lib, imports, render_function) {
|
|
338
|
-
let proc_code = code_lib;
|
|
339
|
-
|
|
340
|
-
// 确保组件字符串是完整的对象结构
|
|
341
|
-
if (!proc_code.trim().endsWith('}')) {
|
|
342
|
-
proc_code = proc_code + '\n}';
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// 如果render函数存在,将其添加到组件选项中
|
|
346
|
-
if (render_function) {
|
|
347
|
-
// 在最后一个属性之前插入render函数
|
|
348
|
-
if (proc_code.trim().endsWith('}')) {
|
|
349
|
-
proc_code = proc_code.replace(/}\s*$/, '');
|
|
350
|
-
// 确保最后一个属性后有逗号
|
|
351
|
-
if (!proc_code.trim().endsWith(',')) {
|
|
352
|
-
proc_code += ',';
|
|
353
|
-
}
|
|
354
|
-
proc_code += `\n render: ${render_function}\n}`;
|
|
355
|
-
}
|
|
273
|
+
// Vue 编译后的代码是 JavaScript,应该使用 babel 解析器格式化
|
|
274
|
+
const result = await this._formatCode(compiledCode, 'babel');
|
|
275
|
+
return result;
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.error('Vue编译失败:', error);
|
|
278
|
+
return `console.error('Vue编译失败: ${error.message}');\nexport default { name: 'ErrorComponent' };`;
|
|
356
279
|
}
|
|
357
|
-
|
|
358
|
-
return `${imports}
|
|
359
|
-
export default ${proc_code};
|
|
360
|
-
`;
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* 构建默认组件
|
|
365
|
-
* @param {string} imports import语句
|
|
366
|
-
* @param {string} render_function render函数
|
|
367
|
-
* @returns {string} 默认组件代码
|
|
368
|
-
*/
|
|
369
|
-
Static.prototype._buildDefaultComp = function (imports, render_function) {
|
|
370
|
-
return `${imports}
|
|
371
|
-
export default {
|
|
372
|
-
name: 'VueComponent',
|
|
373
|
-
data() {
|
|
374
|
-
return {}
|
|
375
|
-
}${render_function ? `,\n render: ${render_function}` : ''}\n};
|
|
376
|
-
`;
|
|
377
|
-
};
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
* 编译Vue组件
|
|
381
|
-
* @param {string} code Vue组件代码
|
|
382
|
-
* @returns {Promise<string>} 可直接调用的JavaScript组件代码
|
|
383
|
-
*/
|
|
384
|
-
Static.prototype._compileVue = async function (code) {
|
|
385
|
-
let desc = parse(code).descriptor;
|
|
386
|
-
let render_function = this._processTemplate(desc);
|
|
387
|
-
return await this._processScript(desc, render_function);
|
|
388
280
|
};
|
|
389
281
|
|
|
390
282
|
/**
|
|
@@ -433,7 +325,7 @@ Static.prototype._runVue = async function (path) {
|
|
|
433
325
|
let file = `.${path}`.fullname(this.config.root);
|
|
434
326
|
let text = file.loadText();
|
|
435
327
|
if (text) {
|
|
436
|
-
code = await this._compileVue(text);
|
|
328
|
+
code = await this._compileVue(text, file);
|
|
437
329
|
}
|
|
438
330
|
return code;
|
|
439
331
|
};
|
|
@@ -451,11 +343,11 @@ Static.prototype._extractMarkdownTitle = function (text) {
|
|
|
451
343
|
// 匹配一级标题格式:# 标题
|
|
452
344
|
var title_regex = /^#\s+(.+)$/m;
|
|
453
345
|
var match = text.match(title_regex);
|
|
454
|
-
|
|
346
|
+
|
|
455
347
|
if (match && match[1]) {
|
|
456
348
|
return match[1].trim();
|
|
457
349
|
}
|
|
458
|
-
|
|
350
|
+
|
|
459
351
|
return null;
|
|
460
352
|
};
|
|
461
353
|
|
|
@@ -473,7 +365,7 @@ Static.prototype._runMarkdown = async function (path) {
|
|
|
473
365
|
try {
|
|
474
366
|
// 使用marked将markdown转换为HTML
|
|
475
367
|
let markdown_html = marked.parse(text);
|
|
476
|
-
|
|
368
|
+
|
|
477
369
|
// 优先从Markdown内容中提取一级标题,后备使用文件名
|
|
478
370
|
var title_from_content = this._extractMarkdownTitle(text);
|
|
479
371
|
var title_from_file = path.split('/').pop().replace('.md', '');
|
|
@@ -621,6 +513,10 @@ Static.prototype._getHeaders = function (file_type) {
|
|
|
621
513
|
else if (this.config.compile_vue) {
|
|
622
514
|
headers['content-type'] = 'application/javascript; charset=utf-8';
|
|
623
515
|
}
|
|
516
|
+
else {
|
|
517
|
+
// 当不编译 Vue 文件时,设置为 JavaScript MIME 类型
|
|
518
|
+
headers['content-type'] = 'application/javascript; charset=utf-8';
|
|
519
|
+
}
|
|
624
520
|
break;
|
|
625
521
|
case 'html':
|
|
626
522
|
headers['content-type'] = 'text/html; charset=utf-8';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mm_statics",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.9",
|
|
4
4
|
"description": "这是超级美眉statics函数模块,用于web服务端statics缓存",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -32,11 +32,12 @@
|
|
|
32
32
|
"homepage": "https://gitee.com/qiuwenwu91/mm_statics#readme",
|
|
33
33
|
"files": [
|
|
34
34
|
"index.js",
|
|
35
|
+
"vue_compiler.js",
|
|
35
36
|
"eslint.config.js",
|
|
36
37
|
"static/"
|
|
37
38
|
],
|
|
38
39
|
"dependencies": {
|
|
39
|
-
"@vue/compiler-sfc": "^3.5.
|
|
40
|
+
"@vue/compiler-sfc": "^3.5.27",
|
|
40
41
|
"abstract-syntax-tree": "^2.22.0",
|
|
41
42
|
"chokidar": "^5.0.0",
|
|
42
43
|
"koa": "^3.1.1",
|
|
@@ -44,13 +45,13 @@
|
|
|
44
45
|
"marked": "^17.0.1",
|
|
45
46
|
"mm_cache": "^1.4.8",
|
|
46
47
|
"mm_es6_to_amd": "^1.4.7",
|
|
47
|
-
"prettier": "^3.
|
|
48
|
+
"prettier": "^3.8.1"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"eslint": "^9.39.2",
|
|
51
|
-
"eslint-plugin-jsdoc": "^
|
|
52
|
-
"mm_eslint": "^1.
|
|
52
|
+
"eslint-plugin-jsdoc": "^62.4.1",
|
|
53
|
+
"mm_eslint": "^1.5.7",
|
|
53
54
|
"mocha": "^11.7.5",
|
|
54
|
-
"supertest": "^7.
|
|
55
|
+
"supertest": "^7.2.2"
|
|
55
56
|
}
|
|
56
57
|
}
|
package/vue_compiler.js
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
// vue-sfc-compiler.js - 修复版
|
|
2
|
+
const { parse, compileScript, compileTemplate, compileStyleAsync } = require('@vue/compiler-sfc');
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
const prettier = require('prettier');
|
|
5
|
+
|
|
6
|
+
class VueSFCCompiler {
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
this.options = {
|
|
9
|
+
isProduction: process.env.NODE_ENV === 'production',
|
|
10
|
+
sourceMap: true,
|
|
11
|
+
...options
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 编译 .vue 文件为 JS 模块
|
|
17
|
+
* @param {string} source - .vue 文件内容
|
|
18
|
+
* @param {string} filename - 文件名(用于错误提示)
|
|
19
|
+
* @returns {Promise<{code: string, map?: any}>}
|
|
20
|
+
*/
|
|
21
|
+
async toJS(source, filename) {
|
|
22
|
+
// 1. 解析 SFC
|
|
23
|
+
const { descriptor, errors } = parse(source, {
|
|
24
|
+
filename,
|
|
25
|
+
sourceMap: this.options.sourceMap
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (errors.length) {
|
|
29
|
+
throw new Error(`Vue SFC parse error: ${errors[0].message}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 2. 生成组件 ID
|
|
33
|
+
descriptor.id = this.generateComponentId(filename, source);
|
|
34
|
+
|
|
35
|
+
// 3. 编译脚本部分
|
|
36
|
+
const scriptCode = await this.compileScript(descriptor);
|
|
37
|
+
|
|
38
|
+
// 4. 编译模板部分
|
|
39
|
+
const templateCode = await this.compileTemplate(descriptor, filename);
|
|
40
|
+
|
|
41
|
+
// 5. 编译样式部分
|
|
42
|
+
const styleCode = await this.compileStyles(descriptor, filename);
|
|
43
|
+
|
|
44
|
+
// 6. 组合成最终模块
|
|
45
|
+
const code = await this.assembleModule(descriptor, scriptCode, templateCode, styleCode);
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
code,
|
|
49
|
+
errors: []
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 生成组件 ID(基于文件内容哈希)
|
|
55
|
+
*/
|
|
56
|
+
generateComponentId(filename, source) {
|
|
57
|
+
const hash = crypto.createHash('sha256');
|
|
58
|
+
hash.update(filename + source);
|
|
59
|
+
return hash.digest('hex').substring(0, 8);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 编译脚本部分
|
|
64
|
+
*/
|
|
65
|
+
async compileScript(descriptor) {
|
|
66
|
+
if (!descriptor.script && !descriptor.scriptSetup) {
|
|
67
|
+
return 'const __script = {};';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const result = compileScript(descriptor, {
|
|
71
|
+
id: descriptor.id,
|
|
72
|
+
isProd: this.options.isProduction,
|
|
73
|
+
sourceMap: this.options.sourceMap,
|
|
74
|
+
inlineTemplate: false
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// 检查是否已经使用了 defineComponent
|
|
78
|
+
const hasDefineComponent = result.content.includes('defineComponent');
|
|
79
|
+
|
|
80
|
+
// 检查是否已经导入了 defineComponent
|
|
81
|
+
const hasDefineComponentImport = result.content.includes('import { defineComponent }') ||
|
|
82
|
+
result.content.includes('import defineComponent');
|
|
83
|
+
|
|
84
|
+
// 移除 export default,改为赋值给 __script 变量
|
|
85
|
+
let scriptContent = result.content || '';
|
|
86
|
+
if (scriptContent.includes('export default')) {
|
|
87
|
+
if (hasDefineComponent && scriptContent.includes('export default defineComponent')) {
|
|
88
|
+
// 如果已经是 export default defineComponent(...),说明组件已经正确包装
|
|
89
|
+
// 直接替换为 const __script = defineComponent(...)
|
|
90
|
+
scriptContent = scriptContent.replace('export default defineComponent', 'const __script = defineComponent');
|
|
91
|
+
} else {
|
|
92
|
+
scriptContent = scriptContent.replace('export default', 'const __script =');
|
|
93
|
+
}
|
|
94
|
+
} else if (scriptContent.includes('export')) {
|
|
95
|
+
// 处理命名导出
|
|
96
|
+
scriptContent = `const __script = {\n${scriptContent}\n};`;
|
|
97
|
+
} else {
|
|
98
|
+
scriptContent = `const __script = {};\n${scriptContent}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return scriptContent;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 编译模板部分
|
|
106
|
+
*/
|
|
107
|
+
async compileTemplate(descriptor, filename) {
|
|
108
|
+
const templateBlock = descriptor.template;
|
|
109
|
+
if (!templateBlock) {
|
|
110
|
+
return '';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const result = compileTemplate({
|
|
114
|
+
source: templateBlock.content,
|
|
115
|
+
filename,
|
|
116
|
+
id: descriptor.id,
|
|
117
|
+
scoped: descriptor.styles.some(s => s.scoped),
|
|
118
|
+
slotted: descriptor.slotted,
|
|
119
|
+
isProd: this.options.isProduction,
|
|
120
|
+
compilerOptions: {
|
|
121
|
+
sourceMap: this.options.sourceMap,
|
|
122
|
+
mode: 'module'
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
if (result.errors.length) {
|
|
127
|
+
throw new Error(`Template compile error: ${result.errors[0]}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return result.code;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 编译样式部分
|
|
135
|
+
*/
|
|
136
|
+
async compileStyles(descriptor, filename) {
|
|
137
|
+
if (!descriptor.styles.length) {
|
|
138
|
+
return '';
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let styleCode = '';
|
|
142
|
+
for (let i = 0; i < descriptor.styles.length; i++) {
|
|
143
|
+
const style = descriptor.styles[i];
|
|
144
|
+
const result = await compileStyleAsync({
|
|
145
|
+
source: style.content,
|
|
146
|
+
filename,
|
|
147
|
+
id: style.scoped ? `data-v-${descriptor.id}` : undefined,
|
|
148
|
+
scoped: style.scoped,
|
|
149
|
+
isProd: this.options.isProduction
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
if (result.errors.length) {
|
|
153
|
+
console.warn(`Style compile warning: ${result.errors[0]}`);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// 对于 scoped 样式,添加 scopeId 到组件
|
|
158
|
+
if (style.scoped) {
|
|
159
|
+
styleCode += `
|
|
160
|
+
// Scoped styles for ${descriptor.id}
|
|
161
|
+
const __style_${i} = \`${result.code.replace(/`/g, '\\`')}\`;
|
|
162
|
+
`;
|
|
163
|
+
} else {
|
|
164
|
+
styleCode += `
|
|
165
|
+
// Global styles
|
|
166
|
+
const __style_${i} = \`${result.code.replace(/`/g, '\\`')}\`;
|
|
167
|
+
`;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return styleCode;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* 组装成最终模块
|
|
176
|
+
*/
|
|
177
|
+
async assembleModule(descriptor, scriptCode, templateCode, styleCode) {
|
|
178
|
+
const hasScopedStyle = descriptor.styles.some(s => s.scoped);
|
|
179
|
+
const scopeId = hasScopedStyle ? `data-v-${descriptor.id}` : null;
|
|
180
|
+
|
|
181
|
+
// 检查脚本部分是否已经导入了 defineComponent
|
|
182
|
+
const hasDefineComponentImport = scriptCode.includes('import { defineComponent }') ||
|
|
183
|
+
scriptCode.includes('import defineComponent');
|
|
184
|
+
|
|
185
|
+
// 检查脚本部分是否已经使用了 defineComponent 函数
|
|
186
|
+
const hasDefineComponentFunction = scriptCode.includes('defineComponent(');
|
|
187
|
+
|
|
188
|
+
// 组装最终代码
|
|
189
|
+
let assembledCode = '';
|
|
190
|
+
|
|
191
|
+
// 添加脚本部分
|
|
192
|
+
if (scriptCode) {
|
|
193
|
+
assembledCode += scriptCode;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// 添加模板部分
|
|
197
|
+
if (templateCode) {
|
|
198
|
+
assembledCode += '\n' + templateCode;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// 添加样式部分
|
|
202
|
+
if (styleCode) {
|
|
203
|
+
assembledCode += '\n' + styleCode;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// 添加组件组装逻辑 - 将 render 函数合并到组件对象中
|
|
207
|
+
assembledCode += `
|
|
208
|
+
// 组装组件
|
|
209
|
+
${scopeId ? `__script.__scopeId = "${scopeId}";` : ''}
|
|
210
|
+
|
|
211
|
+
// 文件信息(开发环境)
|
|
212
|
+
${!this.options.isProduction ? `__script.__file = ${JSON.stringify(descriptor.filename)};` : ''}
|
|
213
|
+
|
|
214
|
+
// 样式注入函数
|
|
215
|
+
function injectStyles() {
|
|
216
|
+
if (typeof document === 'undefined') return;
|
|
217
|
+
|
|
218
|
+
const styleId = 'vue-component-style-' + ${JSON.stringify(descriptor.id)};
|
|
219
|
+
|
|
220
|
+
// 检查样式是否已经注入
|
|
221
|
+
if (document.getElementById(styleId)) return;
|
|
222
|
+
|
|
223
|
+
// 创建 style 元素
|
|
224
|
+
const styleEl = document.createElement('style');
|
|
225
|
+
styleEl.id = styleId;
|
|
226
|
+
styleEl.textContent = __style_0;
|
|
227
|
+
|
|
228
|
+
// 插入到 head
|
|
229
|
+
document.head.appendChild(styleEl);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// 注入样式
|
|
233
|
+
injectStyles();
|
|
234
|
+
|
|
235
|
+
// 将 render 函数合并到组件对象中
|
|
236
|
+
__script.render = render;
|
|
237
|
+
|
|
238
|
+
// 导出组件
|
|
239
|
+
${!hasDefineComponentImport && !hasDefineComponentFunction ? 'import { defineComponent } from \'vue\';\nexport default defineComponent(__script);' : 'export default __script;'}
|
|
240
|
+
`;
|
|
241
|
+
|
|
242
|
+
// 对最终组合代码进行整体格式化
|
|
243
|
+
return await this._formatCode(assembledCode, 'babel');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* 格式化代码
|
|
248
|
+
*/
|
|
249
|
+
async _formatCode(code, parser) {
|
|
250
|
+
if (!code || code.trim() === '') {
|
|
251
|
+
return code;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
try {
|
|
255
|
+
const formattedCode = await prettier.format(code, {
|
|
256
|
+
parser: parser,
|
|
257
|
+
semi: true,
|
|
258
|
+
singleQuote: true,
|
|
259
|
+
trailingComma: 'es5',
|
|
260
|
+
printWidth: 100,
|
|
261
|
+
tabWidth: 2,
|
|
262
|
+
useTabs: false,
|
|
263
|
+
bracketSpacing: true,
|
|
264
|
+
arrowParens: 'avoid'
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
return formattedCode;
|
|
268
|
+
} catch (error) {
|
|
269
|
+
// 格式化失败时返回原代码
|
|
270
|
+
console.warn(`格式化代码失败: ${error.message}`);
|
|
271
|
+
return code;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
module.exports = VueSFCCompiler;
|