lcd-router-webpack-plugin 1.0.0 → 9.0.0-alpha.10
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/lib/babel/index.d.ts +3 -0
- package/lib/babel/index.d.ts.map +1 -0
- package/lib/babel/index.js +26 -0
- package/lib/babel/index.js.map +1 -0
- package/lib/babel/plugins/enhance-reducer.d.ts +3 -0
- package/lib/babel/plugins/enhance-reducer.d.ts.map +1 -0
- package/lib/babel/plugins/enhance-reducer.js +63 -0
- package/lib/babel/plugins/enhance-reducer.js.map +1 -0
- package/lib/babel/plugins/external-wrap.d.ts +3 -0
- package/lib/babel/plugins/external-wrap.d.ts.map +1 -0
- package/lib/babel/plugins/external-wrap.js +43 -0
- package/lib/babel/plugins/external-wrap.js.map +1 -0
- package/lib/babel/plugins/replace-source.d.ts +3 -0
- package/lib/babel/plugins/replace-source.d.ts.map +1 -0
- package/lib/babel/plugins/replace-source.js +54 -0
- package/lib/babel/plugins/replace-source.js.map +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +44 -3
- package/lib/index.js.map +1 -1
- package/lib/utils/paths.d.ts +1 -1
- package/lib/utils/paths.d.ts.map +1 -1
- package/lib/utils/paths.js.map +1 -1
- package/package.json +6 -3
- package/.lecprc.ts +0 -5
- package/src/Generator.ts +0 -46
- package/src/ReducersGenerator.ts +0 -90
- package/src/RoutersGenerator.ts +0 -295
- package/src/SagasGenerator.ts +0 -101
- package/src/index.ts +0 -204
- package/src/utils/files.ts +0 -54
- package/src/utils/index.ts +0 -4
- package/src/utils/paths.ts +0 -77
- package/src/utils/resolver.ts +0 -37
- package/src/utils/types.ts +0 -76
- package/tsconfig.json +0 -14
package/src/ReducersGenerator.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import babelCore, { transformSync, types } from '@babel/core';
|
|
3
|
-
import type { MeJSON } from './utils';
|
|
4
|
-
import { Generator } from './Generator';
|
|
5
|
-
|
|
6
|
-
interface GetReducersBabelPluginItem {
|
|
7
|
-
meJSON: MeJSON;
|
|
8
|
-
namespace: string;
|
|
9
|
-
isExternal: boolean;
|
|
10
|
-
meJSONPath: string;
|
|
11
|
-
}
|
|
12
|
-
export class ReducersGenerator extends Generator<GetReducersBabelPluginItem> {
|
|
13
|
-
constructor() {
|
|
14
|
-
super();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// TODO: 这里类型 加了个 any, 不太希望写else, 所以导致的问题,ts类型推导似乎不合理
|
|
18
|
-
objectPropertyValue(type: 'call' | 'string' | 'identifier', value: string): any {
|
|
19
|
-
if (type === 'call') {
|
|
20
|
-
return types.callExpression(types.identifier('decorate'), [
|
|
21
|
-
types.identifier(this.identifierString(value)),
|
|
22
|
-
types.stringLiteral(value),
|
|
23
|
-
]);
|
|
24
|
-
}
|
|
25
|
-
if (type === 'string') {
|
|
26
|
-
return types.stringLiteral('');
|
|
27
|
-
}
|
|
28
|
-
if (type === 'identifier') {
|
|
29
|
-
return types.identifier(this.identifierString(value));
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
writeCodeToFile(absPath: string) {
|
|
34
|
-
const items = Array.from(this.cache.values());
|
|
35
|
-
const code = transformSync('', {
|
|
36
|
-
plugins: [
|
|
37
|
-
() => {
|
|
38
|
-
return {
|
|
39
|
-
name: 'babel-plugin-replace-react-redux',
|
|
40
|
-
visitor: {
|
|
41
|
-
Program: {
|
|
42
|
-
enter: (path) => {
|
|
43
|
-
const codes: (
|
|
44
|
-
| babelCore.types.ImportDeclaration
|
|
45
|
-
| babelCore.types.ExportDefaultDeclaration
|
|
46
|
-
)[] = [
|
|
47
|
-
this.importDefaultDeclaration(
|
|
48
|
-
'decorate',
|
|
49
|
-
'rrc-loader-helper/lib/reducer-decorate',
|
|
50
|
-
),
|
|
51
|
-
];
|
|
52
|
-
items
|
|
53
|
-
.filter((x) => x.meJSON.sync || x.isExternal)
|
|
54
|
-
.map((x) =>
|
|
55
|
-
this.importNamedDeclaration([['reducer', x.namespace]], x.meJSONPath),
|
|
56
|
-
)
|
|
57
|
-
.forEach((x) => codes.push(x));
|
|
58
|
-
|
|
59
|
-
const properties = items.map((x) => {
|
|
60
|
-
if (x.isExternal || x.meJSON.sync) {
|
|
61
|
-
if (x.meJSON.mobx) {
|
|
62
|
-
return types.objectProperty(
|
|
63
|
-
types.stringLiteral(x.namespace),
|
|
64
|
-
this.objectPropertyValue('call', x.namespace),
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
return types.objectProperty(
|
|
68
|
-
types.stringLiteral(x.namespace),
|
|
69
|
-
this.objectPropertyValue('identifier', x.namespace),
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
return types.objectProperty(
|
|
73
|
-
types.stringLiteral(x.namespace),
|
|
74
|
-
this.objectPropertyValue('string', x.namespace),
|
|
75
|
-
);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
codes.push(types.exportDefaultDeclaration(types.objectExpression(properties)));
|
|
79
|
-
|
|
80
|
-
path.pushContainer('body', codes);
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
},
|
|
86
|
-
],
|
|
87
|
-
});
|
|
88
|
-
fs.writeFileSync(absPath, code?.code!, { encoding: 'utf8' });
|
|
89
|
-
}
|
|
90
|
-
}
|
package/src/RoutersGenerator.ts
DELETED
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import { transformSync, types } from '@babel/core';
|
|
3
|
-
import type { Options, MeJSON, PathService } from './utils';
|
|
4
|
-
import { Generator } from './Generator';
|
|
5
|
-
|
|
6
|
-
interface Item {
|
|
7
|
-
meJSONPath: string;
|
|
8
|
-
meJSON: MeJSON;
|
|
9
|
-
isExternal: boolean;
|
|
10
|
-
path: string;
|
|
11
|
-
page: string;
|
|
12
|
-
exact: boolean;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface TransformItem extends Item, MeJSON {}
|
|
16
|
-
|
|
17
|
-
export class RoutersGenerator extends Generator<Item> {
|
|
18
|
-
config: Options;
|
|
19
|
-
pathService: PathService;
|
|
20
|
-
|
|
21
|
-
constructor(config: Options, pathService: PathService) {
|
|
22
|
-
super();
|
|
23
|
-
this.config = config;
|
|
24
|
-
this.pathService = pathService;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
private errorComponentVariableDeclaration() {
|
|
28
|
-
return types.variableDeclaration('const', [
|
|
29
|
-
types.variableDeclarator(
|
|
30
|
-
types.identifier('ErrorComponent'),
|
|
31
|
-
types.arrowFunctionExpression(
|
|
32
|
-
[types.identifier('props')],
|
|
33
|
-
types.blockStatement([
|
|
34
|
-
types.returnStatement(
|
|
35
|
-
types.jsxElement(
|
|
36
|
-
types.jsxOpeningElement(types.jsxIdentifier('div'), [], false),
|
|
37
|
-
types.jsxClosingElement(types.jsxIdentifier('div')),
|
|
38
|
-
[
|
|
39
|
-
types.jsxElement(
|
|
40
|
-
types.jsxOpeningElement(types.jsxIdentifier('h1'), [], false),
|
|
41
|
-
types.jsxClosingElement(types.jsxIdentifier('h1')),
|
|
42
|
-
[types.jsxText('页面渲染发生异常')],
|
|
43
|
-
),
|
|
44
|
-
types.jsxElement(
|
|
45
|
-
types.jsxOpeningElement(types.jsxIdentifier('span'), [], false),
|
|
46
|
-
types.jsxClosingElement(types.jsxIdentifier('span')),
|
|
47
|
-
[
|
|
48
|
-
types.jsxExpressionContainer(
|
|
49
|
-
types.optionalMemberExpression(
|
|
50
|
-
types.memberExpression(
|
|
51
|
-
types.identifier('props'),
|
|
52
|
-
types.identifier('errorStack'),
|
|
53
|
-
),
|
|
54
|
-
types.identifier('message'),
|
|
55
|
-
false,
|
|
56
|
-
true,
|
|
57
|
-
),
|
|
58
|
-
),
|
|
59
|
-
],
|
|
60
|
-
),
|
|
61
|
-
],
|
|
62
|
-
false,
|
|
63
|
-
),
|
|
64
|
-
),
|
|
65
|
-
]),
|
|
66
|
-
),
|
|
67
|
-
),
|
|
68
|
-
]);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
private loadingVariableDeclaration() {
|
|
72
|
-
return types.variableDeclaration('const', [
|
|
73
|
-
types.variableDeclarator(
|
|
74
|
-
types.identifier('Loading'),
|
|
75
|
-
types.arrowFunctionExpression(
|
|
76
|
-
[],
|
|
77
|
-
types.blockStatement([
|
|
78
|
-
types.returnStatement(
|
|
79
|
-
types.jsxFragment(types.jsxOpeningFragment(), types.jsxClosingFragment(), []),
|
|
80
|
-
),
|
|
81
|
-
]),
|
|
82
|
-
),
|
|
83
|
-
),
|
|
84
|
-
]);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
private createDowngradeValue(meJSON: MeJSON) {
|
|
88
|
-
return <T extends keyof MeJSON>(name: T, defaultValue: MeJSON[T]) => {
|
|
89
|
-
/** @ts-ignore */
|
|
90
|
-
return meJSON[name] ?? this.config[name] ?? defaultValue;
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
private transform(item: Item): TransformItem {
|
|
95
|
-
const downgradeValue = this.createDowngradeValue(item.meJSON);
|
|
96
|
-
// 路由参数
|
|
97
|
-
let route = item.meJSON.route ?? '';
|
|
98
|
-
const keepAlive = downgradeValue('keepAlive', false);
|
|
99
|
-
const retain = downgradeValue('retain', false);
|
|
100
|
-
const title = downgradeValue('title', undefined);
|
|
101
|
-
// FUCK keep-alive 特性的坑, 为了兼容同一个页面多次打开 动态拓展 redux 的reducer 节点
|
|
102
|
-
const linkExtendable = downgradeValue('linkExtendable', false);
|
|
103
|
-
route = linkExtendable ? `${route}/:id?` : route;
|
|
104
|
-
let injectStore = downgradeValue('injectStore', false);
|
|
105
|
-
if (injectStore === true) injectStore = 'store';
|
|
106
|
-
return {
|
|
107
|
-
...item,
|
|
108
|
-
route,
|
|
109
|
-
keepAlive,
|
|
110
|
-
retain,
|
|
111
|
-
title,
|
|
112
|
-
linkExtendable,
|
|
113
|
-
injectStore,
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
private pageImportExpression(item: TransformItem) {
|
|
118
|
-
const returnObjectProperties = [
|
|
119
|
-
types.objectProperty(types.identifier('module'), types.identifier('module')),
|
|
120
|
-
];
|
|
121
|
-
if (item.meJSON.sync) {
|
|
122
|
-
returnObjectProperties.push(
|
|
123
|
-
types.objectProperty(types.identifier('sync'), types.booleanLiteral(true)),
|
|
124
|
-
);
|
|
125
|
-
} else {
|
|
126
|
-
returnObjectProperties.push(
|
|
127
|
-
types.objectProperty(types.identifier('sync'), types.booleanLiteral(false)),
|
|
128
|
-
types.objectProperty(types.identifier('reducers'), types.identifier('reducers')),
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
const sourceAst = types.stringLiteral(item.meJSONPath);
|
|
132
|
-
|
|
133
|
-
if (this.config.enablePreFetch) {
|
|
134
|
-
types.addComment(sourceAst, 'leading', 'webpackPrefetch: true');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return types.callExpression(
|
|
138
|
-
types.memberExpression(
|
|
139
|
-
types.callExpression(types.import(), [sourceAst]),
|
|
140
|
-
types.identifier('then'),
|
|
141
|
-
),
|
|
142
|
-
[
|
|
143
|
-
types.arrowFunctionExpression(
|
|
144
|
-
[types.identifier('module')],
|
|
145
|
-
types.blockStatement([
|
|
146
|
-
// TODO
|
|
147
|
-
types.returnStatement(types.objectExpression(returnObjectProperties)),
|
|
148
|
-
]),
|
|
149
|
-
),
|
|
150
|
-
],
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
private loadableCallExpression(item: TransformItem) {
|
|
155
|
-
return types.callExpression(types.identifier('Loadable'), [
|
|
156
|
-
types.objectExpression([
|
|
157
|
-
types.objectProperty(
|
|
158
|
-
types.identifier('title'),
|
|
159
|
-
item.title ? types.stringLiteral(item.title) : types.nullLiteral(),
|
|
160
|
-
),
|
|
161
|
-
types.objectProperty(types.identifier('keepAlive'), types.booleanLiteral(item.keepAlive!)),
|
|
162
|
-
types.objectProperty(types.identifier('route'), types.stringLiteral(item.route!)),
|
|
163
|
-
types.objectProperty(types.identifier('retain'), types.booleanLiteral(item.retain!)),
|
|
164
|
-
types.objectProperty(
|
|
165
|
-
types.identifier('injectStore'),
|
|
166
|
-
typeof item.injectStore === 'boolean'
|
|
167
|
-
? types.booleanLiteral(item.injectStore)
|
|
168
|
-
: types.stringLiteral(item.injectStore!),
|
|
169
|
-
),
|
|
170
|
-
types.objectProperty(types.identifier('page'), types.stringLiteral(item.page)),
|
|
171
|
-
types.objectProperty(types.identifier('loading'), types.identifier('Loading')),
|
|
172
|
-
types.objectProperty(
|
|
173
|
-
types.identifier('errorComponent'),
|
|
174
|
-
types.identifier('ErrorComponent'),
|
|
175
|
-
),
|
|
176
|
-
types.objectProperty(
|
|
177
|
-
types.identifier('metaInfo'),
|
|
178
|
-
types.callExpression(
|
|
179
|
-
types.memberExpression(types.identifier('JSON'), types.identifier('parse')),
|
|
180
|
-
[types.stringLiteral(JSON.stringify(item.meJSON))],
|
|
181
|
-
),
|
|
182
|
-
),
|
|
183
|
-
types.objectProperty(
|
|
184
|
-
types.identifier('loader'),
|
|
185
|
-
types.arrowFunctionExpression([], this.pageImportExpression(item)),
|
|
186
|
-
),
|
|
187
|
-
]),
|
|
188
|
-
]);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
writeCodeToFile(absPath: string) {
|
|
192
|
-
const items = Array.from(this.cache.values());
|
|
193
|
-
const code = transformSync('', {
|
|
194
|
-
plugins: [
|
|
195
|
-
() => {
|
|
196
|
-
return {
|
|
197
|
-
name: 'babel-plugin-replace-react-redux',
|
|
198
|
-
visitor: {
|
|
199
|
-
Program: {
|
|
200
|
-
enter: (path) => {
|
|
201
|
-
const ast: (
|
|
202
|
-
| types.ImportDeclaration
|
|
203
|
-
| types.VariableDeclaration
|
|
204
|
-
| types.ExportDefaultDeclaration
|
|
205
|
-
| types.ExpressionStatement
|
|
206
|
-
)[] = [
|
|
207
|
-
this.importNamedDeclaration([], 'rrc-loader-helper/lib/fake-react'),
|
|
208
|
-
this.importDefaultDeclaration('Loadable', 'rrc-loader-helper/lib/loadable'),
|
|
209
|
-
this.importDefaultDeclaration('React', 'react'),
|
|
210
|
-
];
|
|
211
|
-
|
|
212
|
-
/** 如果用户没有指定loading组件,那么自动生成一个空 loading */
|
|
213
|
-
if (this.config.loading) {
|
|
214
|
-
ast.push(this.importDefaultDeclaration('Loading', this.config.loading));
|
|
215
|
-
} else {
|
|
216
|
-
ast.push(this.loadingVariableDeclaration());
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (this.config.errorComponent) {
|
|
220
|
-
ast.push(
|
|
221
|
-
this.importDefaultDeclaration('ErrorComponent', this.config.errorComponent),
|
|
222
|
-
);
|
|
223
|
-
} else {
|
|
224
|
-
ast.push(this.errorComponentVariableDeclaration());
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
if (this.config.theme?.hash) {
|
|
228
|
-
ast.push(
|
|
229
|
-
this.importNamedDeclaration(
|
|
230
|
-
['toGlobalTheme'],
|
|
231
|
-
this.pathService.getThemeJSCacheFileAbs(this.config.theme?.hash),
|
|
232
|
-
),
|
|
233
|
-
);
|
|
234
|
-
ast.push(
|
|
235
|
-
types.expressionStatement(
|
|
236
|
-
types.optionalCallExpression(types.identifier('toGlobalTheme'), [], true),
|
|
237
|
-
),
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
const _ = items
|
|
242
|
-
.filter((x) => !x.isExternal)
|
|
243
|
-
.map((x) => this.transform(x))
|
|
244
|
-
.map((x) => {
|
|
245
|
-
const path =
|
|
246
|
-
this.config.dangerousRoute || !x.exact
|
|
247
|
-
? `/${x.path}${x.route}`
|
|
248
|
-
: `/${x.path}`;
|
|
249
|
-
return types.objectExpression([
|
|
250
|
-
types.objectProperty(
|
|
251
|
-
types.identifier('exact'),
|
|
252
|
-
types.booleanLiteral(x.exact),
|
|
253
|
-
),
|
|
254
|
-
types.objectProperty(
|
|
255
|
-
types.identifier('keepAlive'),
|
|
256
|
-
types.booleanLiteral(x.keepAlive!),
|
|
257
|
-
),
|
|
258
|
-
types.objectProperty(types.identifier('key'), types.stringLiteral(path)),
|
|
259
|
-
types.objectProperty(types.identifier('path'), types.stringLiteral(path)),
|
|
260
|
-
types.objectProperty(
|
|
261
|
-
types.identifier('component'),
|
|
262
|
-
this.loadableCallExpression(x),
|
|
263
|
-
),
|
|
264
|
-
]);
|
|
265
|
-
});
|
|
266
|
-
ast.push(
|
|
267
|
-
types.exportDefaultDeclaration(
|
|
268
|
-
types.arrowFunctionExpression(
|
|
269
|
-
[types.identifier('reducers')],
|
|
270
|
-
types.blockStatement([types.returnStatement(types.arrayExpression(_))]),
|
|
271
|
-
),
|
|
272
|
-
),
|
|
273
|
-
);
|
|
274
|
-
|
|
275
|
-
path.pushContainer('body', ast);
|
|
276
|
-
},
|
|
277
|
-
},
|
|
278
|
-
},
|
|
279
|
-
};
|
|
280
|
-
},
|
|
281
|
-
],
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
fs.writeFileSync(
|
|
285
|
-
absPath,
|
|
286
|
-
[
|
|
287
|
-
JSON.stringify(`👹 pages total count is ${Array.from(this.cache.keys()).length}`),
|
|
288
|
-
code?.code!,
|
|
289
|
-
].join(';\r\n'),
|
|
290
|
-
{
|
|
291
|
-
encoding: 'utf8',
|
|
292
|
-
},
|
|
293
|
-
);
|
|
294
|
-
}
|
|
295
|
-
}
|
package/src/SagasGenerator.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { Generator } from './Generator';
|
|
2
|
-
import type { MeJSON } from './utils';
|
|
3
|
-
import { transformSync, types } from '@babel/core';
|
|
4
|
-
import fs from 'fs';
|
|
5
|
-
interface Item {
|
|
6
|
-
namespace: string;
|
|
7
|
-
meJSONPath: string;
|
|
8
|
-
isExternal: boolean;
|
|
9
|
-
meJSON: MeJSON;
|
|
10
|
-
}
|
|
11
|
-
export class SagasGenerator extends Generator<Item> {
|
|
12
|
-
constructor() {
|
|
13
|
-
super();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
private setCtxExpressionStatement(namespace: string) {
|
|
17
|
-
return types.expressionStatement(
|
|
18
|
-
types.yieldExpression(
|
|
19
|
-
types.callExpression(types.identifier('setCtx'), [
|
|
20
|
-
types.objectExpression([
|
|
21
|
-
types.objectProperty(types.identifier('mobxStyle'), types.booleanLiteral(true)),
|
|
22
|
-
types.objectProperty(types.identifier('page'), types.stringLiteral(namespace)),
|
|
23
|
-
types.objectProperty(types.identifier('url'), types.stringLiteral('')),
|
|
24
|
-
]),
|
|
25
|
-
]),
|
|
26
|
-
),
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
private callExpressionStatement(namespace: string) {
|
|
31
|
-
return types.expressionStatement(
|
|
32
|
-
types.yieldExpression(
|
|
33
|
-
types.callExpression(types.identifier('call'), [
|
|
34
|
-
types.memberExpression(
|
|
35
|
-
types.identifier(this.identifierString(namespace)),
|
|
36
|
-
types.identifier('saga'),
|
|
37
|
-
),
|
|
38
|
-
]),
|
|
39
|
-
),
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
writeCodeToFile(absPath: string) {
|
|
44
|
-
const items = Array.from(this.cache.values());
|
|
45
|
-
const code = transformSync('', {
|
|
46
|
-
plugins: [
|
|
47
|
-
() => {
|
|
48
|
-
return {
|
|
49
|
-
visitor: {
|
|
50
|
-
Program: {
|
|
51
|
-
enter: (path) => {
|
|
52
|
-
const ast: (types.ImportDeclaration | types.ExportDefaultDeclaration)[] = [
|
|
53
|
-
this.importNamedDeclaration(['setCtx'], 'rrc-loader-helper/lib/retain'),
|
|
54
|
-
this.importNamedDeclaration(
|
|
55
|
-
['call'],
|
|
56
|
-
'rrc-loader-helper/lib/sagas/redux-saga/effects',
|
|
57
|
-
),
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
items
|
|
61
|
-
.filter((x) => x.meJSON.sync || x.isExternal)
|
|
62
|
-
.forEach((x) =>
|
|
63
|
-
// 如果是mobx, 取 reducer, 否则取 saga
|
|
64
|
-
ast.push(
|
|
65
|
-
this.importNamedDeclaration(
|
|
66
|
-
[[x.meJSON.mobx ? 'reducer' : 'saga', x.namespace]],
|
|
67
|
-
x.meJSONPath,
|
|
68
|
-
),
|
|
69
|
-
),
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
const arrayItem = items.map((x) => {
|
|
73
|
-
if (!x.isExternal && !x.meJSON.sync) {
|
|
74
|
-
return types.stringLiteral('');
|
|
75
|
-
}
|
|
76
|
-
if (x.meJSON.mobx) {
|
|
77
|
-
return types.functionExpression(
|
|
78
|
-
null,
|
|
79
|
-
[],
|
|
80
|
-
types.blockStatement([
|
|
81
|
-
this.setCtxExpressionStatement(x.namespace),
|
|
82
|
-
this.callExpressionStatement(x.namespace),
|
|
83
|
-
]),
|
|
84
|
-
true,
|
|
85
|
-
false,
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
return types.identifier(this.identifierString(x.namespace));
|
|
89
|
-
});
|
|
90
|
-
ast.push(types.exportDefaultDeclaration(types.arrayExpression(arrayItem)));
|
|
91
|
-
path.pushContainer('body', ast);
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
},
|
|
97
|
-
],
|
|
98
|
-
});
|
|
99
|
-
fs.writeFileSync(absPath, code?.code!, { encoding: 'utf8' });
|
|
100
|
-
}
|
|
101
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import type { Compiler, WebpackPluginInstance } from 'webpack';
|
|
2
|
-
import globby from 'globby';
|
|
3
|
-
import chokidar from 'chokidar';
|
|
4
|
-
import deepmerge from 'deepmerge';
|
|
5
|
-
import { PathService, Resolver, Options, FileService } from './utils';
|
|
6
|
-
import { ReducersGenerator } from './ReducersGenerator';
|
|
7
|
-
import { SagasGenerator } from './SagasGenerator';
|
|
8
|
-
import { RoutersGenerator } from './RoutersGenerator';
|
|
9
|
-
|
|
10
|
-
import path from 'node:path';
|
|
11
|
-
|
|
12
|
-
export default class LcdRouterWebpackPlugin implements WebpackPluginInstance {
|
|
13
|
-
options: Options;
|
|
14
|
-
constructor(options: Options) {
|
|
15
|
-
this.options = options;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
apply(compiler: Compiler) {
|
|
19
|
-
this.mergeOptions(compiler);
|
|
20
|
-
|
|
21
|
-
compiler.hooks.afterPlugins.tap('LcdRouterWebpackPlugin', (compiler) => {
|
|
22
|
-
const options = this.options;
|
|
23
|
-
|
|
24
|
-
const pathService = new PathService(options);
|
|
25
|
-
const resolver = new Resolver(compiler, options);
|
|
26
|
-
const fileService = new FileService(pathService);
|
|
27
|
-
|
|
28
|
-
const reducersGenerator = new ReducersGenerator();
|
|
29
|
-
const sagasGenerator = new SagasGenerator();
|
|
30
|
-
const routersGenerator = new RoutersGenerator(options, pathService);
|
|
31
|
-
|
|
32
|
-
function isDev(compiler) {
|
|
33
|
-
if (compiler.options.mode === 'production' || process.env.NODE_ENV === 'production')
|
|
34
|
-
return false;
|
|
35
|
-
return true;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function writeCode() {
|
|
39
|
-
reducersGenerator.writeCodeToFile(pathService.getReducersCacheFileAbs());
|
|
40
|
-
sagasGenerator.writeCodeToFile(pathService.getSagasCacheFileAbs());
|
|
41
|
-
routersGenerator.writeCodeToFile(pathService.getRoutersCacheFileAbs());
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function resolveFile(filepath: string) {
|
|
45
|
-
const absFilePath = pathService.getCurrentFileAbs(filepath);
|
|
46
|
-
const currentDir = path.dirname(filepath);
|
|
47
|
-
const absCurrentDir = path.dirname(absFilePath);
|
|
48
|
-
|
|
49
|
-
const chunkCode = [] as string[];
|
|
50
|
-
try {
|
|
51
|
-
const reducerPath = resolver.getReducerFile(absCurrentDir);
|
|
52
|
-
chunkCode.push(`export { default as reducer } from '${reducerPath}';`);
|
|
53
|
-
} catch (e) {
|
|
54
|
-
// feat: reducers 可以不存在, 方便结合reactive 和 ak,默认创建一个reducers
|
|
55
|
-
chunkCode.push(`export function reducer(){ return {} }`);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const viewPath = resolver.getViewFile(absCurrentDir);
|
|
59
|
-
chunkCode.push(`export { default as view } from '${viewPath}';`);
|
|
60
|
-
|
|
61
|
-
const meJSON = fileService.readJSONSync(absFilePath);
|
|
62
|
-
if (meJSON.theme && !options.theme?.hash) {
|
|
63
|
-
throw Error(`开启页面级主题之前,请优先开启全局主题 ${absFilePath}`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (!meJSON.mobx) {
|
|
67
|
-
const sagaPath = resolver.getSagaFile(absCurrentDir);
|
|
68
|
-
chunkCode.push(`export { default as saga } from '${sagaPath}';`);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (meJSON.errorComponent) {
|
|
72
|
-
const errorCompPath = resolver.getErrorComFile(absCurrentDir, meJSON.errorComponent);
|
|
73
|
-
chunkCode.push(`export { default as ErrorComponent } from '${errorCompPath}';`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (options.theme?.hash) {
|
|
77
|
-
const themePath = pathService.getThemeJSCacheFileAbs(options.theme?.hash);
|
|
78
|
-
chunkCode.push(`export * from '${themePath}';`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (meJSON.theme) {
|
|
82
|
-
fileService.writeThemeFile(meJSON.theme, 'toGlobalTheme');
|
|
83
|
-
const themePath = pathService.getThemeJSCacheFileAbs(meJSON.theme);
|
|
84
|
-
chunkCode.push(`export * from '${themePath}';`);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const meJSONPath = pathService.getMeJSONCacheFileAbs(filepath);
|
|
88
|
-
|
|
89
|
-
fileService.writeMeJSONFile(meJSONPath, chunkCode);
|
|
90
|
-
|
|
91
|
-
const isExternal = options.externals?.some?.((x) => x === path.dirname(filepath)) ?? false;
|
|
92
|
-
|
|
93
|
-
// 处理是否存在多store的场景
|
|
94
|
-
const hasChildStore =
|
|
95
|
-
globby.sync(`**/*.${options.reducerName}.{t,j}s`, { cwd: absCurrentDir }).length > 0;
|
|
96
|
-
if (hasChildStore && (meJSON.sync || isExternal)) {
|
|
97
|
-
throw Error(
|
|
98
|
-
`如果开启了Sync模式或当前页面存在于LCD的external中,那么则不支持多Store功能,${absCurrentDir}`,
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/** reducers.js */
|
|
103
|
-
reducersGenerator.set(filepath, {
|
|
104
|
-
meJSON,
|
|
105
|
-
isExternal,
|
|
106
|
-
namespace: currentDir,
|
|
107
|
-
meJSONPath: meJSONPath,
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
/** saga.js */
|
|
111
|
-
sagasGenerator.set(currentDir, {
|
|
112
|
-
meJSON,
|
|
113
|
-
isExternal,
|
|
114
|
-
namespace: currentDir,
|
|
115
|
-
meJSONPath: meJSONPath,
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
/** router */
|
|
119
|
-
routersGenerator.set(currentDir, {
|
|
120
|
-
meJSON,
|
|
121
|
-
isExternal,
|
|
122
|
-
page: currentDir,
|
|
123
|
-
path: currentDir,
|
|
124
|
-
exact: false,
|
|
125
|
-
meJSONPath: meJSONPath,
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
/** 处理 /list 的路由 */
|
|
129
|
-
if (new RegExp(`\/${options.index}$`).test(absCurrentDir)) {
|
|
130
|
-
const _key = absCurrentDir.replace(new RegExp(`\/${options.index}$`), '');
|
|
131
|
-
routersGenerator.set(_key, {
|
|
132
|
-
meJSON,
|
|
133
|
-
isExternal,
|
|
134
|
-
page: absCurrentDir,
|
|
135
|
-
path: _key,
|
|
136
|
-
exact: true,
|
|
137
|
-
meJSONPath: meJSONPath,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (options.theme?.hash) {
|
|
143
|
-
fileService.writeThemeFile(options.theme.hash, 'toGlobalTheme');
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const list = globby.sync('**/me.json', {
|
|
147
|
-
cwd: pathService.getPageRootAbs(),
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
if (list.length === 0) {
|
|
151
|
-
console.warn('没有找到me.json文件');
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* glob 的排序 是包含文件名 me.json 的完整路径,存在问题
|
|
156
|
-
* 比如 会将 /xx/ss/me.json 排到 /xx/ss/zz/me.json 前面
|
|
157
|
-
* glob 的 noSort option 会将 文件夹排到前面, 因此需要手动排序, 并且统一成 globby, 速度更快
|
|
158
|
-
*/
|
|
159
|
-
const sortedList = list
|
|
160
|
-
.map((filepath) => filepath?.replace(/me.json$/, ''))
|
|
161
|
-
.sort((a, b) => {
|
|
162
|
-
if (a?.startsWith(b)) return -1;
|
|
163
|
-
return a.localeCompare(b, 'en');
|
|
164
|
-
})
|
|
165
|
-
.map((dir) => `${dir}me.json`);
|
|
166
|
-
|
|
167
|
-
sortedList.forEach((filepath) => {
|
|
168
|
-
resolveFile(filepath);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
writeCode();
|
|
172
|
-
|
|
173
|
-
if (isDev(compiler)) {
|
|
174
|
-
const watcher = chokidar.watch('**/me.json', {
|
|
175
|
-
cwd: pathService.getPageRootAbs(),
|
|
176
|
-
ignoreInitial: true,
|
|
177
|
-
});
|
|
178
|
-
const fn = async (filepath) => {
|
|
179
|
-
await resolveFile(filepath);
|
|
180
|
-
writeCode();
|
|
181
|
-
};
|
|
182
|
-
watcher.on('add', fn);
|
|
183
|
-
watcher.on('addDir', fn);
|
|
184
|
-
watcher.on('change', fn);
|
|
185
|
-
watcher.on('unlink', fn);
|
|
186
|
-
watcher.on('unlinkDir', fn);
|
|
187
|
-
watcher.on('error', fn);
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
mergeOptions(compiler: Compiler) {
|
|
193
|
-
const defaultOptions = {
|
|
194
|
-
context: compiler.context,
|
|
195
|
-
enablePreFetch: false,
|
|
196
|
-
index: 'list',
|
|
197
|
-
externals: [],
|
|
198
|
-
pageDir: 'component',
|
|
199
|
-
reducerName: 'reducers',
|
|
200
|
-
disableBuiltInRoute: false,
|
|
201
|
-
};
|
|
202
|
-
this.options = deepmerge(defaultOptions, this.options);
|
|
203
|
-
}
|
|
204
|
-
}
|