-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathindex.ts
109 lines (98 loc) · 3.33 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import * as webpack from 'webpack';
import hash from 'hash-sum';
import * as path from 'path';
import * as loaderUtils from 'loader-utils';
import * as t from '@babel/types';
import { parse } from '@babel/parser';
import { isDefineComponentCall, parseComponentDecls } from './utils';
export default function loader(
this: webpack.loader.LoaderContext,
source: string,
) {
const loaderContext = this;
loaderContext.cacheable?.();
if (!(loaderContext.mode === 'development')) {
return source;
}
const webpackRemainingChain = loaderUtils.getRemainingRequest(loaderContext).split('!');
const fullPath = webpackRemainingChain[webpackRemainingChain.length - 1];
const filename = path.relative(process.cwd(), fullPath);
const file = parse(source, { sourceType: 'module', plugins: ['jsx', 'typescript', 'decorators-legacy'] });
if (!(filename.endsWith('.jsx') || filename.endsWith('.tsx'))) {
return source;
}
const declaredComponents: { name: string }[] = [];
const hotComponents: {
local: string;
id: string;
}[] = [];
let hasDefault = false;
for (const node of file.program.body) {
if (t.isVariableDeclaration(node)) {
declaredComponents.push(...parseComponentDecls(node));
} else if (t.isExportNamedDeclaration(node)) {
const { specifiers = [], declaration } = node;
if (t.isVariableDeclaration(declaration)) {
hotComponents.push(...parseComponentDecls(declaration).map(({ name }) => ({
local: name,
id: hash(`${filename}-${name}`),
})));
} else if (t.isClassDeclaration(declaration)) {
const name = declaration.id.name
hotComponents.push({
local: name,
id: hash(`${filename}-${name}`),
})
} else if (specifiers.length) {
for (const spec of specifiers) {
if (t.isExportSpecifier(spec) && t.isIdentifier(spec.exported)) {
if (declaredComponents.find(d => d.name === spec.local.name)) {
hotComponents.push({
local: spec.local.name,
id: hash(`${filename}-${spec.exported.name}`)
});
}
}
}
}
} else if (t.isExportDefaultDeclaration(node)) {
const { declaration } = node;
if (t.isIdentifier(declaration)) {
if (declaredComponents.find(d => d.name === declaration.name)) {
hotComponents.push({
local: declaration.name,
id: hash(`${filename}-default`)
})
}
} else if (isDefineComponentCall(declaration)) {
hotComponents.push({
local: '__default__',
id: hash(`${filename}-default`)
});
hasDefault = true
}
}
}
if (hotComponents.length) {
if (hasDefault) {
source = source.replace(
/export default defineComponent/g,
`const __default__ = defineComponent`
) + `\nexport default __default__`
}
let callbackCode = '';
for (const { local, id } of hotComponents) {
source +=
`\n${local}.__hmrId = '${id}'` +
`\n__VUE_HMR_RUNTIME__.createRecord('${id}', ${local})`
callbackCode += `\n__VUE_HMR_RUNTIME__.reload("${id}", ${local})`
}
source +=
`\n/* hot reload */` +
`\nif (module.hot) {` +
`\n module.hot.accept()` +
`\n ${callbackCode}` +
`\n}`
}
return source;
};