lcd-router-webpack-plugin 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/.lecprc.ts +5 -0
- package/LICENSE +674 -0
- package/lib/Generator.d.ts +16 -0
- package/lib/Generator.d.ts.map +1 -0
- package/lib/Generator.js +35 -0
- package/lib/Generator.js.map +1 -0
- package/lib/ReducersGenerator.d.ts +15 -0
- package/lib/ReducersGenerator.d.ts.map +1 -0
- package/lib/ReducersGenerator.js +62 -0
- package/lib/ReducersGenerator.js.map +1 -0
- package/lib/RoutersGenerator.d.ts +24 -0
- package/lib/RoutersGenerator.d.ts.map +1 -0
- package/lib/RoutersGenerator.js +115 -0
- package/lib/RoutersGenerator.js.map +1 -0
- package/lib/SagasGenerator.d.ts +16 -0
- package/lib/SagasGenerator.d.ts.map +1 -0
- package/lib/SagasGenerator.js +56 -0
- package/lib/SagasGenerator.js.map +1 -0
- package/lib/index.d.ts +9 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +181 -0
- package/lib/index.js.map +1 -0
- package/lib/utils/files.d.ts +23 -0
- package/lib/utils/files.d.ts.map +1 -0
- package/lib/utils/files.js +65 -0
- package/lib/utils/files.js.map +1 -0
- package/lib/utils/index.d.ts +5 -0
- package/lib/utils/index.d.ts.map +1 -0
- package/lib/utils/index.js +50 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/paths.d.ts +38 -0
- package/lib/utils/paths.d.ts.map +1 -0
- package/lib/utils/paths.js +81 -0
- package/lib/utils/paths.js.map +1 -0
- package/lib/utils/resolver.d.ts +25 -0
- package/lib/utils/resolver.d.ts.map +1 -0
- package/lib/utils/resolver.js +41 -0
- package/lib/utils/resolver.js.map +1 -0
- package/lib/utils/types.d.ts +75 -0
- package/lib/utils/types.d.ts.map +1 -0
- package/lib/utils/types.js +6 -0
- package/lib/utils/types.js.map +1 -0
- package/package.json +29 -0
- package/src/Generator.ts +46 -0
- package/src/ReducersGenerator.ts +90 -0
- package/src/RoutersGenerator.ts +295 -0
- package/src/SagasGenerator.ts +101 -0
- package/src/index.ts +204 -0
- package/src/utils/files.ts +54 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/paths.ts +77 -0
- package/src/utils/resolver.ts +37 -0
- package/src/utils/types.ts +76 -0
- package/tsconfig.json +14 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import fse from 'fs-extra';
|
|
2
|
+
import { PathService } from './paths';
|
|
3
|
+
import fetchSync from 'sync-fetch';
|
|
4
|
+
|
|
5
|
+
export class FileService {
|
|
6
|
+
pathService: PathService;
|
|
7
|
+
|
|
8
|
+
constructor(pathService) {
|
|
9
|
+
this.pathService = pathService;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
writeFileSync = (path: string, content: string) => {
|
|
13
|
+
fse.outputFileSync(path, content, { encoding: 'utf8' });
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 创建 meJSON.js 文件, 包含部分内容
|
|
18
|
+
*/
|
|
19
|
+
writeMeJSONFile = (filepath: string, chunkCode: string[]) => {
|
|
20
|
+
const code = chunkCode.join('\n');
|
|
21
|
+
this.writeFileSync(filepath, code);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 书写主题文件
|
|
26
|
+
*/
|
|
27
|
+
writeThemeFile = (hash: string, funcName: string) => {
|
|
28
|
+
const code = this.fetchThemeFileContent(hash);
|
|
29
|
+
const target = this.pathService.getThemeJSCacheFileAbs(hash);
|
|
30
|
+
if (!fse.pathExistsSync(target)) {
|
|
31
|
+
fse.outputFileSync(target, ` export function ${funcName}(){ ${code} }`, { encoding: 'utf8' });
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 获取 主题 文件内容
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
fetchThemeFileContent = (hash: string) => {
|
|
40
|
+
// TODO: 需要加错误处理, 以及重试机制
|
|
41
|
+
const code = fetchSync(`https://assets.dotfashion.cn/unpkg/@shein-components/shineout-theme@0.0.0-${hash}/index.js`).text();
|
|
42
|
+
if (!code.includes('(function(){')) {
|
|
43
|
+
throw new Error(`获取主题文件失败,hash:${hash}`);
|
|
44
|
+
}
|
|
45
|
+
return code;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 读 json 文件
|
|
50
|
+
*/
|
|
51
|
+
readJSONSync = (path: string) => {
|
|
52
|
+
return fse.readJSONSync(path, { encoding: 'utf8' });
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import type { Options } from '../utils';
|
|
3
|
+
|
|
4
|
+
export const dir = 'lessCoding';
|
|
5
|
+
|
|
6
|
+
export const themes = 'themes';
|
|
7
|
+
|
|
8
|
+
export const LcdTempDir = '.lego';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 路径处理服务
|
|
12
|
+
*/
|
|
13
|
+
export class PathService {
|
|
14
|
+
options: Options;
|
|
15
|
+
|
|
16
|
+
legoAbs: string;
|
|
17
|
+
|
|
18
|
+
constructor(options) {
|
|
19
|
+
this.options = options;
|
|
20
|
+
this.legoAbs = path.join(this.options.context!, 'src', LcdTempDir);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 页面根目录绝对路径
|
|
25
|
+
* 通常都是
|
|
26
|
+
* - src
|
|
27
|
+
* - components
|
|
28
|
+
* */
|
|
29
|
+
getPageRootAbs() {
|
|
30
|
+
return path.join(this.options.context!, 'src', this.options.pageDir);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getSrcRootAbs() {
|
|
34
|
+
return path.join(this.options.context!, 'src');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 当前文件的绝对路径
|
|
39
|
+
* */
|
|
40
|
+
getCurrentFileAbs(relativeFilePath: string) {
|
|
41
|
+
return path.join(this.getPageRootAbs(), relativeFilePath);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** 当前文件的绝对目录路径 */
|
|
45
|
+
getCurrentDirAbs(relativeFilePath: string) {
|
|
46
|
+
return path.join(this.getPageRootAbs(), path.dirname(relativeFilePath));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** 生成的 reducers 文件路径 */
|
|
50
|
+
getReducersCacheFileAbs() {
|
|
51
|
+
return path.join(this.legoAbs, dir, 'reducers.js');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** 生成的 sagas 文件路径 */
|
|
55
|
+
getSagasCacheFileAbs() {
|
|
56
|
+
return path.join(this.legoAbs, dir, 'sagas.js');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** 生成的 routers 文件路径 */
|
|
60
|
+
getRoutersCacheFileAbs() {
|
|
61
|
+
return path.join(this.legoAbs, dir, 'routers.js');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** 主题文件cache 的路径 */
|
|
65
|
+
getThemeJSCacheFileAbs(hash: string) {
|
|
66
|
+
return path.join(this.legoAbs, dir, themes, `${hash}.js`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** 获取 mejson 编译后的文件路径 */
|
|
70
|
+
getMeJSONCacheFileAbs(relativeFilePath: string) {
|
|
71
|
+
return path.join(this.legoAbs, dir, 'me-json', this.getMeJsonCacheFileName(relativeFilePath));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getMeJsonCacheFileName(relativeFilePath: string) {
|
|
75
|
+
return relativeFilePath.replace(/(.*)\/me\.json$/, '$1.js').replace(/\//g, '-_-');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { create } from 'enhanced-resolve';
|
|
2
|
+
import type { Compiler } from 'webpack';
|
|
3
|
+
import type { Options } from './types';
|
|
4
|
+
|
|
5
|
+
export class Resolver {
|
|
6
|
+
resolver: any;
|
|
7
|
+
options: Options;
|
|
8
|
+
constructor(compiler: Compiler, options: Options) {
|
|
9
|
+
this.options = options;
|
|
10
|
+
this.resolver = create.sync({
|
|
11
|
+
extensions: compiler.options.resolve.extensions,
|
|
12
|
+
alias: compiler.options.resolve.alias,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 获取 当前目录下 reducer文件的路径
|
|
18
|
+
*/
|
|
19
|
+
getReducerFile = (dirname) => this.resolver(dirname, `./${this.options.reducerName}`);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 获取 当前目录下 view文件的路径
|
|
23
|
+
*/
|
|
24
|
+
getViewFile = (dirname) => this.resolver(dirname, `./view`);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 获取 当前目录下 saga 文件的路径
|
|
28
|
+
* @param isMobx 如果是 mobx 则返回 reducers 的地址
|
|
29
|
+
*/
|
|
30
|
+
getSagaFile = (dirname, isMobx?: boolean) =>
|
|
31
|
+
isMobx ? this.getReducerFile(dirname) : this.resolver(dirname, `./saga`);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 获取 me.json 配置的 errorComponent 地址
|
|
35
|
+
*/
|
|
36
|
+
getErrorComFile = (dirname, errorComponent) => this.resolver(dirname, errorComponent);
|
|
37
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export interface Options {
|
|
2
|
+
/**
|
|
3
|
+
* 组件上下文, 默认取 compiler.context
|
|
4
|
+
* @default compiler.context
|
|
5
|
+
*/
|
|
6
|
+
context?: string;
|
|
7
|
+
/**
|
|
8
|
+
* 是否禁用内置路由
|
|
9
|
+
* 默认会将 react-router-dom 转换到 rrc-loader-helper/router
|
|
10
|
+
* 如果你是新项目,建议将该配置配置为true,因为内置路由针对react-router做了大量的改动,可能会引起一些无法预测的故障
|
|
11
|
+
* @default false
|
|
12
|
+
*/
|
|
13
|
+
disableBuiltInRoute?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* 是否开启 webpack prefetch预加载
|
|
16
|
+
* @default false
|
|
17
|
+
*/
|
|
18
|
+
enablePreFetch?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* 指定页面路径 不进行注册路由
|
|
21
|
+
* @default []
|
|
22
|
+
*/
|
|
23
|
+
externals?: string[];
|
|
24
|
+
/**
|
|
25
|
+
* 页面目录
|
|
26
|
+
* @default component
|
|
27
|
+
*/
|
|
28
|
+
pageDir: string;
|
|
29
|
+
/**
|
|
30
|
+
* shineout 主题
|
|
31
|
+
*/
|
|
32
|
+
theme?: {
|
|
33
|
+
hash: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* reducer 文件名称
|
|
37
|
+
* @default reducers
|
|
38
|
+
*/
|
|
39
|
+
reducerName: string;
|
|
40
|
+
/**
|
|
41
|
+
* loading 组件路径
|
|
42
|
+
*/
|
|
43
|
+
loading?: string;
|
|
44
|
+
/**
|
|
45
|
+
* 一个神奇的属性,用于处理 /xxx/order/list 这种路由过长的问题
|
|
46
|
+
* 也可以用来作为父路由的默认路由目录
|
|
47
|
+
* 会生成一个新路由 /xxx/order,实际目录指向为 /xxx/order/list
|
|
48
|
+
* @default list
|
|
49
|
+
*/
|
|
50
|
+
index?: string;
|
|
51
|
+
/**
|
|
52
|
+
* 渲染出错时的组件地址
|
|
53
|
+
*/
|
|
54
|
+
errorComponent?: string;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 是否允许页面内生成自定义路由
|
|
58
|
+
* 例如在 component/order/detail/me.json 中 配置 route: '/:id',此时会生成动态路由 /order/detail/:id
|
|
59
|
+
* 非常不推荐使用的一个属性,因为此功能受 me.json 中 exact 属性影响, 仅当 exact: true 时候,才不会拼接路由
|
|
60
|
+
* 当开启 dangerousRoute 后, 不再受 exact 影响, 都会生成 拼接路由 /order/detail/:id
|
|
61
|
+
* @default false
|
|
62
|
+
*/
|
|
63
|
+
dangerousRoute?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface MeJSON {
|
|
67
|
+
theme?: string;
|
|
68
|
+
sync?: boolean;
|
|
69
|
+
mobx?: boolean;
|
|
70
|
+
keepAlive?: boolean;
|
|
71
|
+
retain?: boolean;
|
|
72
|
+
title?: string;
|
|
73
|
+
linkExtendable?: boolean;
|
|
74
|
+
injectStore?: boolean | string;
|
|
75
|
+
route?: string;
|
|
76
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"moduleResolution": "Node",
|
|
4
|
+
"target": "ES5",
|
|
5
|
+
"esModuleInterop": true,
|
|
6
|
+
"jsx": "react",
|
|
7
|
+
"lib": ["ESNext"],
|
|
8
|
+
"sourceMap": true,
|
|
9
|
+
"noEmitOnError": true,
|
|
10
|
+
"allowSyntheticDefaultImports": true,
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"declarationDir": "lib"
|
|
13
|
+
}
|
|
14
|
+
}
|