@modern-js/plugin-ssg 1.0.1 → 1.1.2
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/CHANGELOG.md +38 -6
- package/dist/js/modern/index.js +96 -58
- package/dist/js/modern/libs/make.js +37 -0
- package/dist/js/modern/libs/replace.js +5 -4
- package/dist/js/modern/libs/util.js +38 -22
- package/dist/js/modern/server/index.js +2 -2
- package/dist/js/modern/server/prerender.js +2 -2
- package/dist/js/modern/server/process.js +1 -1
- package/dist/js/modern/types.js +0 -1
- package/dist/js/node/index.js +92 -55
- package/dist/js/node/libs/make.js +50 -0
- package/dist/js/node/libs/replace.js +5 -4
- package/dist/js/node/libs/util.js +38 -29
- package/dist/js/node/server/index.js +2 -2
- package/dist/js/node/server/prerender.js +2 -2
- package/dist/js/node/server/process.js +2 -2
- package/dist/types/libs/make.d.ts +5 -0
- package/dist/types/libs/replace.d.ts +1 -1
- package/dist/types/libs/util.d.ts +4 -8
- package/dist/types/types.d.ts +13 -17
- package/package.json +10 -11
- package/src/index.ts +84 -83
- package/src/libs/make.ts +45 -0
- package/src/libs/output.ts +1 -1
- package/src/libs/replace.ts +7 -4
- package/src/libs/util.ts +39 -27
- package/src/server/index.ts +1 -1
- package/src/server/process.ts +3 -2
- package/src/types.ts +26 -20
- package/tests/lib.test.ts +48 -169
- package/tests/util.test.ts +71 -32
- package/dist/js/modern/libs/createPage.js +0 -46
- package/dist/js/modern/libs/invoker.js +0 -56
- package/dist/js/modern/libs/render.js +0 -15
- package/dist/js/modern/loader/index.js +0 -105
- package/dist/js/modern/manifest-op.js +0 -101
- package/dist/js/node/libs/createPage.js +0 -57
- package/dist/js/node/libs/invoker.js +0 -67
- package/dist/js/node/libs/render.js +0 -22
- package/dist/js/node/loader/index.js +0 -115
- package/dist/js/node/manifest-op.js +0 -124
- package/dist/types/libs/createPage.d.ts +0 -2
- package/dist/types/libs/invoker.d.ts +0 -5
- package/dist/types/libs/render.d.ts +0 -3
- package/dist/types/loader/index.d.ts +0 -4
- package/dist/types/manifest-op.d.ts +0 -18
- package/src/libs/createPage.ts +0 -42
- package/src/libs/invoker.ts +0 -56
- package/src/libs/render.ts +0 -16
- package/src/loader/index.ts +0 -99
- package/src/manifest-op.ts +0 -111
- package/tests/operate.test.ts +0 -39
package/src/libs/replace.ts
CHANGED
|
@@ -2,7 +2,7 @@ import normalize from 'normalize-path';
|
|
|
2
2
|
import { ModernRoute } from '@modern-js/server';
|
|
3
3
|
import { SsgRoute } from '../types';
|
|
4
4
|
|
|
5
|
-
export function exist(route:
|
|
5
|
+
export function exist(route: ModernRoute, pageRoutes: ModernRoute[]): number {
|
|
6
6
|
return pageRoutes.slice().findIndex(pageRoute => {
|
|
7
7
|
const urlEqual = normalize(pageRoute.urlPath) === normalize(route.urlPath);
|
|
8
8
|
const entryEqual = pageRoute.entryName === route.entryName;
|
|
@@ -16,12 +16,15 @@ export function exist(route: SsgRoute, pageRoutes: ModernRoute[]): number {
|
|
|
16
16
|
export function replaceRoute(ssgRoutes: SsgRoute[], pageRoutes: ModernRoute[]) {
|
|
17
17
|
// remove redundant fields and replace rendered entryPath
|
|
18
18
|
const cleanSsgRoutes = ssgRoutes.map(ssgRoute => {
|
|
19
|
-
const { output, ...cleanSsgRoute } = ssgRoute;
|
|
20
|
-
return Object.assign(
|
|
19
|
+
const { output, headers, ...cleanSsgRoute } = ssgRoute;
|
|
20
|
+
return Object.assign(
|
|
21
|
+
cleanSsgRoute,
|
|
22
|
+
output ? { entryPath: output } : {},
|
|
23
|
+
) as ModernRoute;
|
|
21
24
|
});
|
|
22
25
|
|
|
23
26
|
// all routes that need to be added and replaced
|
|
24
|
-
const freshRoutes:
|
|
27
|
+
const freshRoutes: ModernRoute[] = [];
|
|
25
28
|
cleanSsgRoutes.forEach(ssgRoute => {
|
|
26
29
|
const index = exist(ssgRoute, pageRoutes);
|
|
27
30
|
|
package/src/libs/util.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
-
import { ROUTE_SPEC_FILE, fs } from '@modern-js/utils';
|
|
2
|
+
import { ROUTE_SPEC_FILE, fs, isSingleEntry } from '@modern-js/utils';
|
|
3
3
|
import { ModernRoute } from '@modern-js/server';
|
|
4
|
-
import {
|
|
5
|
-
import { MODE } from '@/manifest-op';
|
|
4
|
+
import { EntryPoint, MultiEntryOptions, SSG, SsgRoute } from '../types';
|
|
6
5
|
|
|
7
|
-
export function formatOutput(
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
export function formatOutput(filename: string) {
|
|
7
|
+
const outputPath = path.extname(filename)
|
|
8
|
+
? filename
|
|
9
|
+
: `${filename}/index.html`;
|
|
10
|
+
return outputPath;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export function formatPath(str: string) {
|
|
@@ -89,27 +89,39 @@ export const writeJSONSpec = (dir: string, routes: ModernRoute[]) => {
|
|
|
89
89
|
fs.writeJSONSync(routeJSONPath, { routes }, { spaces: 2 });
|
|
90
90
|
};
|
|
91
91
|
|
|
92
|
-
export const getSSGRenderLevel = (key: boolean | string) => {
|
|
93
|
-
const level = typeof key === 'boolean' ? MODE.LOOSE : MODE[key.toUpperCase()];
|
|
94
|
-
// currently only MODE.STRICT and MODE.LOOSE are supported
|
|
95
|
-
if (!level || level > 2 || level < 1) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
`[SSG Render Fail] SSG 不支持当前 Mode,useSSG: ${key.toString()}, Level: ${level}`,
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return level;
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
export const parsedSSGConfig = (ssg: SSGConfig) => {
|
|
105
|
-
const useSSG = Boolean(ssg);
|
|
106
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
107
|
-
const userHook = typeof ssg === 'function' ? ssg : () => {};
|
|
108
|
-
return { useSSG, userHook };
|
|
109
|
-
};
|
|
110
|
-
|
|
111
92
|
export const replaceWithAlias = (
|
|
112
93
|
base: string,
|
|
113
94
|
filePath: string,
|
|
114
95
|
alias: string,
|
|
115
|
-
) => path.join(alias, path.relative(base, filePath));
|
|
96
|
+
) => path.posix.join(alias, path.posix.relative(base, filePath));
|
|
97
|
+
|
|
98
|
+
export const standardOptions = (ssgOptions: SSG, entrypoints: EntryPoint[]) => {
|
|
99
|
+
if (ssgOptions === false) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (ssgOptions === true) {
|
|
104
|
+
return entrypoints.reduce((opt, entry) => {
|
|
105
|
+
opt[entry.entryName] = ssgOptions;
|
|
106
|
+
return opt;
|
|
107
|
+
}, {} as MultiEntryOptions);
|
|
108
|
+
} else if (typeof ssgOptions === 'object') {
|
|
109
|
+
const isSingle = isSingleEntry(entrypoints);
|
|
110
|
+
|
|
111
|
+
if (isSingle && typeof (ssgOptions as any).main === 'undefined') {
|
|
112
|
+
return { main: ssgOptions } as MultiEntryOptions;
|
|
113
|
+
} else {
|
|
114
|
+
return ssgOptions as MultiEntryOptions;
|
|
115
|
+
}
|
|
116
|
+
} else if (typeof ssgOptions === 'function') {
|
|
117
|
+
const intermediateOptions: MultiEntryOptions = {};
|
|
118
|
+
for (const entrypoint of entrypoints) {
|
|
119
|
+
const { entryName } = entrypoint;
|
|
120
|
+
// Todo may be async function
|
|
121
|
+
intermediateOptions[entryName] = ssgOptions(entryName);
|
|
122
|
+
}
|
|
123
|
+
return intermediateOptions;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return false;
|
|
127
|
+
};
|
package/src/server/index.ts
CHANGED
|
@@ -15,7 +15,7 @@ export const createServer = (
|
|
|
15
15
|
new Promise((resolve, reject) => {
|
|
16
16
|
// this side of the shallow copy of a route for subsequent render processing, to prevent the modification of the current field
|
|
17
17
|
// manually enable the server-side rendering configuration for all routes that require SSG
|
|
18
|
-
const backup = ssgRoutes.map(ssgRoute => ({
|
|
18
|
+
const backup: ModernRoute[] = ssgRoutes.map(ssgRoute => ({
|
|
19
19
|
...ssgRoute,
|
|
20
20
|
isSSR: true,
|
|
21
21
|
bundle: `${SERVER_BUNDLE_DIRECTORY}/${ssgRoute.entryName}.js`,
|
package/src/server/process.ts
CHANGED
|
@@ -2,9 +2,10 @@ import Server, { ModernRoute } from '@modern-js/server';
|
|
|
2
2
|
import portfinder from 'portfinder';
|
|
3
3
|
import { NormalizedConfig } from '@modern-js/core';
|
|
4
4
|
import { compatRequire } from '@modern-js/utils';
|
|
5
|
-
import { makeRender } from '../libs/
|
|
5
|
+
import { makeRender } from '../libs/make';
|
|
6
6
|
import { compile as createRender } from './prerender';
|
|
7
7
|
import { CLOSE_SIGN } from './consts';
|
|
8
|
+
import { SsgRoute } from '@/types';
|
|
8
9
|
|
|
9
10
|
type Then<T> = T extends PromiseLike<infer U> ? U : T;
|
|
10
11
|
|
|
@@ -67,7 +68,7 @@ process.on('message', async (chunk: string) => {
|
|
|
67
68
|
// get server handler, render to ssr
|
|
68
69
|
const render = createRender(modernServer!.getRequestHandler());
|
|
69
70
|
const renderPromiseAry = makeRender(
|
|
70
|
-
routes.filter(route => !route.isApi),
|
|
71
|
+
routes.filter(route => !route.isApi) as SsgRoute[],
|
|
71
72
|
render,
|
|
72
73
|
port,
|
|
73
74
|
);
|
package/src/types.ts
CHANGED
|
@@ -16,30 +16,36 @@ export type AgreedRouteMap = {
|
|
|
16
16
|
[propNames: string]: AgreedRoute[];
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
export type
|
|
20
|
-
|
|
21
|
-
output?: string;
|
|
22
|
-
params?: Record<string, string | number>;
|
|
19
|
+
export type SsgRoute = ModernRoute & {
|
|
20
|
+
output: string;
|
|
23
21
|
headers?: Record<string, string>;
|
|
24
22
|
};
|
|
25
|
-
export type UserInterfaceRoute = ModernRoute & {
|
|
26
|
-
path: string;
|
|
27
|
-
agreed?: boolean;
|
|
28
|
-
};
|
|
29
23
|
|
|
30
|
-
export type
|
|
31
|
-
|
|
24
|
+
export type RouteOptions =
|
|
25
|
+
| string
|
|
26
|
+
| {
|
|
27
|
+
url: string;
|
|
28
|
+
output?: string;
|
|
29
|
+
params?: Record<string, any>[];
|
|
30
|
+
headers?: Record<string, any>;
|
|
31
|
+
};
|
|
32
32
|
|
|
33
|
-
export type
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
export type SingleEntryOptions =
|
|
34
|
+
| boolean
|
|
35
|
+
| {
|
|
36
|
+
preventDefault?: string[];
|
|
37
|
+
headers?: Record<string, any>;
|
|
38
|
+
routes: RouteOptions[];
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type MultiEntryOptions = Record<string, SingleEntryOptions>;
|
|
42
|
+
|
|
43
|
+
export type SSG =
|
|
44
|
+
| boolean
|
|
45
|
+
| SingleEntryOptions
|
|
46
|
+
| MultiEntryOptions
|
|
47
|
+
| ((entryName: string) => SingleEntryOptions);
|
|
41
48
|
|
|
42
|
-
export type SSGConfig = boolean | ((context: any) => void);
|
|
43
49
|
export type ExtendOutputConfig = {
|
|
44
|
-
ssg:
|
|
50
|
+
ssg: SSG;
|
|
45
51
|
};
|
package/tests/lib.test.ts
CHANGED
|
@@ -1,178 +1,10 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
// import { createInvoker } from '../libs/invoker';
|
|
4
3
|
import { ModernRoute } from '@modern-js/server';
|
|
5
4
|
import { exist, replaceRoute } from '@/libs/replace';
|
|
6
|
-
import {
|
|
7
|
-
AgreedRoute,
|
|
8
|
-
CreatePageListener,
|
|
9
|
-
HookContext,
|
|
10
|
-
SsgRoute,
|
|
11
|
-
} from '@/types';
|
|
12
|
-
import { createPageFactory } from '@/libs/createPage';
|
|
13
|
-
import { invoker } from '@/libs/invoker';
|
|
14
|
-
|
|
15
|
-
const noop = () => {
|
|
16
|
-
//
|
|
17
|
-
};
|
|
5
|
+
import { makeRoute } from '@/libs/make';
|
|
18
6
|
|
|
19
7
|
describe('test functional function', () => {
|
|
20
|
-
it('should listener get arguments correctly', () => {
|
|
21
|
-
const route = { path: '/foo', agreed: false };
|
|
22
|
-
const listener: CreatePageListener = (r: SsgRoute, agreed?: boolean) => {
|
|
23
|
-
expect(r.urlPath).toBe('/foo');
|
|
24
|
-
expect(agreed).toBeFalsy();
|
|
25
|
-
};
|
|
26
|
-
const createPage = createPageFactory(route as any, listener);
|
|
27
|
-
createPage();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should listener get url correctly', () => {
|
|
31
|
-
const route = { path: '/foo', agreed: false };
|
|
32
|
-
const listener: CreatePageListener = (r: SsgRoute, agreed?: boolean) => {
|
|
33
|
-
expect(r.urlPath).toBe('/bar');
|
|
34
|
-
expect(agreed).toBeFalsy();
|
|
35
|
-
};
|
|
36
|
-
const createPage = createPageFactory(route as any, listener);
|
|
37
|
-
createPage({ url: '/bar' });
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('should listener get output correctly', () => {
|
|
41
|
-
const route = { path: '/foo', agreed: false };
|
|
42
|
-
const listener: CreatePageListener = (r: SsgRoute, agreed?: boolean) => {
|
|
43
|
-
expect(r.output).toBe('./bar');
|
|
44
|
-
expect(agreed).toBeFalsy();
|
|
45
|
-
};
|
|
46
|
-
const createPage = createPageFactory(route as any, listener);
|
|
47
|
-
createPage({ output: './bar' });
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('should listener get dynamic route correctly', () => {
|
|
51
|
-
const route = { path: '/:foo', agreed: true };
|
|
52
|
-
const listener: CreatePageListener = (r: SsgRoute, agreed?: boolean) => {
|
|
53
|
-
expect(r.urlPath).toBe('/bar');
|
|
54
|
-
expect(agreed).toBeTruthy();
|
|
55
|
-
};
|
|
56
|
-
const createPage = createPageFactory(route as any, listener);
|
|
57
|
-
createPage({ params: { foo: 'bar' } });
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should listener get multi route correctly', () => {
|
|
61
|
-
const route = { path: '/foo', agreed: false };
|
|
62
|
-
const urls = ['/a', '/b', '/c'];
|
|
63
|
-
const listener: CreatePageListener = (r: SsgRoute) => {
|
|
64
|
-
expect(urls.includes(r.urlPath)).toBe(true);
|
|
65
|
-
};
|
|
66
|
-
const createPage = createPageFactory(route as any, listener);
|
|
67
|
-
createPage(urls.map(url => ({ url })));
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('should hook get context correctly', () => {
|
|
71
|
-
const pageRoutes = [
|
|
72
|
-
{
|
|
73
|
-
urlPath: '/foo',
|
|
74
|
-
entryName: 'foo',
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
urlPath: '/bar',
|
|
78
|
-
entryName: 'bar',
|
|
79
|
-
},
|
|
80
|
-
];
|
|
81
|
-
let i = 0;
|
|
82
|
-
const hook = (context: HookContext) => {
|
|
83
|
-
expect(typeof context.createPage).toBe('function');
|
|
84
|
-
expect(context.route.path).toEqual(pageRoutes[i].urlPath);
|
|
85
|
-
i++;
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
invoker(pageRoutes as any, {}, hook, () => false, noop);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('should hook get context correctly while use appoint', () => {
|
|
92
|
-
const pageRoutes = [
|
|
93
|
-
{
|
|
94
|
-
urlPath: '/foo',
|
|
95
|
-
entryName: 'foo',
|
|
96
|
-
},
|
|
97
|
-
];
|
|
98
|
-
const appointRouteMap: Record<string, AgreedRoute[]> = {
|
|
99
|
-
foo: [
|
|
100
|
-
{
|
|
101
|
-
path: '/a',
|
|
102
|
-
component: 'a',
|
|
103
|
-
_component: 'a',
|
|
104
|
-
exact: true,
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
path: '/b',
|
|
108
|
-
component: 'b',
|
|
109
|
-
_component: 'b',
|
|
110
|
-
exact: true,
|
|
111
|
-
},
|
|
112
|
-
],
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
let i = 0;
|
|
116
|
-
const hook = (context: HookContext) => {
|
|
117
|
-
expect(typeof context.createPage).toBe('function');
|
|
118
|
-
expect(context.route.path).toEqual(`/foo${appointRouteMap.foo[i].path}`);
|
|
119
|
-
i++;
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
invoker(
|
|
123
|
-
pageRoutes as any,
|
|
124
|
-
appointRouteMap,
|
|
125
|
-
hook,
|
|
126
|
-
context => {
|
|
127
|
-
expect(['a', 'b'].includes(context.component)).toBeTruthy();
|
|
128
|
-
return true;
|
|
129
|
-
},
|
|
130
|
-
noop,
|
|
131
|
-
);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('only static route invoke checker', () => {
|
|
135
|
-
const pageRoutes = [
|
|
136
|
-
{
|
|
137
|
-
urlPath: '/foo',
|
|
138
|
-
entryName: 'foo',
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
urlPath: '/:bar',
|
|
142
|
-
entryName: 'bar',
|
|
143
|
-
},
|
|
144
|
-
];
|
|
145
|
-
const appointRouteMap: Record<string, AgreedRoute[]> = {
|
|
146
|
-
foo: [
|
|
147
|
-
{
|
|
148
|
-
path: '/a',
|
|
149
|
-
component: 'a',
|
|
150
|
-
_component: 'a',
|
|
151
|
-
exact: true,
|
|
152
|
-
},
|
|
153
|
-
],
|
|
154
|
-
bar: [
|
|
155
|
-
{
|
|
156
|
-
path: '/b',
|
|
157
|
-
component: 'b',
|
|
158
|
-
_component: 'b',
|
|
159
|
-
exact: true,
|
|
160
|
-
},
|
|
161
|
-
],
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
invoker(
|
|
165
|
-
pageRoutes as any,
|
|
166
|
-
appointRouteMap,
|
|
167
|
-
noop,
|
|
168
|
-
context => {
|
|
169
|
-
expect(context.component).toBe('a');
|
|
170
|
-
return true;
|
|
171
|
-
},
|
|
172
|
-
noop,
|
|
173
|
-
);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
8
|
it('should check route exist correctly', () => {
|
|
177
9
|
const pageRoutes: ModernRoute[] = JSON.parse(
|
|
178
10
|
fs.readFileSync(path.join(__dirname, 'material/lib.route.json'), 'utf-8'),
|
|
@@ -222,4 +54,51 @@ describe('test functional function', () => {
|
|
|
222
54
|
|
|
223
55
|
expect(result).toEqual(final);
|
|
224
56
|
});
|
|
57
|
+
|
|
58
|
+
it('shoule generate route correctly', () => {
|
|
59
|
+
const baseRoute: ModernRoute = {
|
|
60
|
+
urlPath: '/foo',
|
|
61
|
+
isSPA: true,
|
|
62
|
+
isSSR: false,
|
|
63
|
+
entryName: 'foo',
|
|
64
|
+
isApi: false,
|
|
65
|
+
bundle: '',
|
|
66
|
+
entryPath: 'html/foo/index.html',
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const route1 = makeRoute(baseRoute, '/baz');
|
|
70
|
+
expect(route1.urlPath).toBe('/foo/baz');
|
|
71
|
+
expect(route1.urlPath).toBe('/foo/baz');
|
|
72
|
+
|
|
73
|
+
const route2 = makeRoute(baseRoute, { url: '/baz' });
|
|
74
|
+
expect(route2.urlPath).toBe('/foo/baz');
|
|
75
|
+
expect(route2.output).toBe(path.normalize('html/foo/baz'));
|
|
76
|
+
|
|
77
|
+
const route3 = makeRoute(baseRoute, {
|
|
78
|
+
url: '/baz',
|
|
79
|
+
output: 'html/baz.html',
|
|
80
|
+
});
|
|
81
|
+
expect(route3.output).toBe(path.normalize('html/baz.html'));
|
|
82
|
+
|
|
83
|
+
const route4 = makeRoute(
|
|
84
|
+
baseRoute,
|
|
85
|
+
{
|
|
86
|
+
url: '/baz',
|
|
87
|
+
},
|
|
88
|
+
{ ua: 'mobile' },
|
|
89
|
+
);
|
|
90
|
+
expect(route4.headers).toEqual({ ua: 'mobile' });
|
|
91
|
+
|
|
92
|
+
const route5 = makeRoute(
|
|
93
|
+
baseRoute,
|
|
94
|
+
{
|
|
95
|
+
url: '/baz',
|
|
96
|
+
headers: {
|
|
97
|
+
ua: 'pc',
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
{ ua: 'mobile' },
|
|
101
|
+
);
|
|
102
|
+
expect(route5.headers).toEqual({ ua: 'pc' });
|
|
103
|
+
});
|
|
225
104
|
});
|
package/tests/util.test.ts
CHANGED
|
@@ -4,11 +4,9 @@ import {
|
|
|
4
4
|
isDynamicUrl,
|
|
5
5
|
getUrlPrefix,
|
|
6
6
|
getOutput,
|
|
7
|
-
getSSGRenderLevel,
|
|
8
|
-
parsedSSGConfig,
|
|
9
7
|
replaceWithAlias,
|
|
8
|
+
standardOptions,
|
|
10
9
|
} from '@/libs/util';
|
|
11
|
-
import { MODE } from '@/manifest-op';
|
|
12
10
|
|
|
13
11
|
describe('test ssg util function', () => {
|
|
14
12
|
it('should return format path correctly', () => {
|
|
@@ -64,42 +62,83 @@ describe('test ssg util function', () => {
|
|
|
64
62
|
});
|
|
65
63
|
|
|
66
64
|
it('should return format output correctly', () => {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
expect(onlyBase).toBe(entryPath);
|
|
65
|
+
const entryPath1 = '/base/home/index.html';
|
|
66
|
+
expect(formatOutput(entryPath1)).toBe(entryPath1);
|
|
70
67
|
|
|
71
|
-
const
|
|
72
|
-
expect(
|
|
68
|
+
const entryPath2 = '/base/home';
|
|
69
|
+
expect(formatOutput(entryPath2)).toBe(entryPath1);
|
|
70
|
+
});
|
|
73
71
|
|
|
74
|
-
|
|
75
|
-
expect(
|
|
72
|
+
it('should replace alias correctly', () => {
|
|
73
|
+
expect(replaceWithAlias('/src', '/src/app.js', '@src')).toBe('@src/app.js');
|
|
74
|
+
});
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
it('should starndar user config correctly', () => {
|
|
77
|
+
const opt0 = standardOptions(false, []);
|
|
78
|
+
expect(opt0).toBeFalsy();
|
|
79
79
|
|
|
80
|
-
const
|
|
81
|
-
expect(
|
|
82
|
-
});
|
|
80
|
+
const opt1 = standardOptions(true, [{ entryName: 'main', entry: '' }]);
|
|
81
|
+
expect(opt1).toEqual({ main: true });
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
const opt2 = standardOptions(true, [
|
|
84
|
+
{ entryName: 'main', entry: '' },
|
|
85
|
+
{ entryName: 'home', entry: '' },
|
|
86
|
+
]);
|
|
87
|
+
expect(opt2).toEqual({ main: true, home: true });
|
|
88
|
+
|
|
89
|
+
const opt3 = standardOptions(true, [
|
|
90
|
+
{ entryName: 'main', entry: '' },
|
|
91
|
+
{ entryName: 'home', entry: '' },
|
|
92
|
+
]);
|
|
93
|
+
expect(opt3).toEqual({ main: true, home: true });
|
|
89
94
|
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
95
|
+
// single entry, object config
|
|
96
|
+
const ssg1 = {
|
|
97
|
+
routes: ['/foo', { url: '/baz' }],
|
|
93
98
|
};
|
|
94
|
-
|
|
95
|
-
expect(
|
|
96
|
-
expect(parsedSSGConfig(true as any).useSSG).toBe(true);
|
|
97
|
-
expect(parsedSSGConfig(true as any).userHook).toBeInstanceOf(Function);
|
|
98
|
-
expect(parsedSSGConfig(empty).useSSG).toBe(true);
|
|
99
|
-
expect(parsedSSGConfig(empty).userHook).toBe(empty);
|
|
99
|
+
const opt4 = standardOptions(ssg1, [{ entryName: 'main', entry: '' }]);
|
|
100
|
+
expect(opt4).toEqual({ main: ssg1 });
|
|
100
101
|
});
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
// error usage, just test
|
|
104
|
+
const ssg2 = {
|
|
105
|
+
routes: ['/foo', { url: '/baz' }],
|
|
106
|
+
};
|
|
107
|
+
const opt5 = standardOptions(ssg2, [
|
|
108
|
+
{ entryName: 'main', entry: '' },
|
|
109
|
+
{ entryName: 'home', entry: '' },
|
|
110
|
+
]);
|
|
111
|
+
expect(opt5).toEqual(ssg2);
|
|
112
|
+
|
|
113
|
+
const ssg3 = {
|
|
114
|
+
main: { routes: ['/foo', { url: '/baz' }] },
|
|
115
|
+
home: false,
|
|
116
|
+
};
|
|
117
|
+
const opt6 = standardOptions(ssg3, [
|
|
118
|
+
{ entryName: 'main', entry: '' },
|
|
119
|
+
{ entryName: 'home', entry: '' },
|
|
120
|
+
]);
|
|
121
|
+
expect(opt6).toEqual(ssg3);
|
|
122
|
+
|
|
123
|
+
const ssg4 = () => true;
|
|
124
|
+
const opt7 = standardOptions(ssg4, [
|
|
125
|
+
{ entryName: 'main', entry: '' },
|
|
126
|
+
{ entryName: 'home', entry: '' },
|
|
127
|
+
]);
|
|
128
|
+
expect(opt7).toEqual({ main: true, home: true });
|
|
129
|
+
|
|
130
|
+
const ssg5 = (entryName: string) => {
|
|
131
|
+
if (entryName === 'main') {
|
|
132
|
+
return true;
|
|
133
|
+
} else {
|
|
134
|
+
return {
|
|
135
|
+
routes: ['/foo'],
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
const opt8 = standardOptions(ssg5, [
|
|
140
|
+
{ entryName: 'main', entry: '' },
|
|
141
|
+
{ entryName: 'home', entry: '' },
|
|
142
|
+
]);
|
|
143
|
+
expect(opt8).toEqual({ main: true, home: { routes: ['/foo'] } });
|
|
105
144
|
});
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
const _excluded = ["path", "agreed"];
|
|
2
|
-
|
|
3
|
-
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
|
|
4
|
-
|
|
5
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
6
|
-
|
|
7
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
8
|
-
|
|
9
|
-
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
10
|
-
|
|
11
|
-
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
12
|
-
|
|
13
|
-
import { generatePath } from 'react-router-dom';
|
|
14
|
-
import { formatPath, isDynamicUrl } from "./util";
|
|
15
|
-
export const createPageFactory = (route, listener) => config => {
|
|
16
|
-
if (Array.isArray(config)) {
|
|
17
|
-
config.forEach(cfg => {
|
|
18
|
-
listener(createPage(route, cfg), route.agreed);
|
|
19
|
-
});
|
|
20
|
-
} else {
|
|
21
|
-
listener(createPage(route, config), route.agreed);
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
function createPage(route, config = {}) {
|
|
26
|
-
const {
|
|
27
|
-
path,
|
|
28
|
-
agreed
|
|
29
|
-
} = route,
|
|
30
|
-
filterRoute = _objectWithoutProperties(route, _excluded);
|
|
31
|
-
|
|
32
|
-
const urlPath = formatPath(config.url || path);
|
|
33
|
-
|
|
34
|
-
const ssgRoute = _objectSpread(_objectSpread({}, filterRoute), {}, {
|
|
35
|
-
urlPath
|
|
36
|
-
}); // using params completion dynamic routing
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (agreed && isDynamicUrl(urlPath) && config.params) {
|
|
40
|
-
ssgRoute.urlPath = generatePath(urlPath, config.params);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
ssgRoute.output = config.output;
|
|
44
|
-
ssgRoute.headers = config.headers;
|
|
45
|
-
return ssgRoute;
|
|
46
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
|
|
2
|
-
|
|
3
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
4
|
-
|
|
5
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
6
|
-
|
|
7
|
-
import normalize from 'normalize-path';
|
|
8
|
-
import { isDynamicUrl } from "./util";
|
|
9
|
-
import { createPageFactory } from "./createPage";
|
|
10
|
-
|
|
11
|
-
function createContext(route, listener) {
|
|
12
|
-
return {
|
|
13
|
-
createPage: createPageFactory(route, listener),
|
|
14
|
-
route
|
|
15
|
-
};
|
|
16
|
-
} // eslint-disable-next-line max-params
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export async function invoker(pageRoutes, agreedRouteMap, hook, autoAddAgreed, listener) {
|
|
20
|
-
for (const pageRoute of pageRoutes) {
|
|
21
|
-
const {
|
|
22
|
-
urlPath,
|
|
23
|
-
entryName
|
|
24
|
-
} = pageRoute;
|
|
25
|
-
const agreedRoutes = agreedRouteMap[entryName];
|
|
26
|
-
|
|
27
|
-
if (agreedRoutes) {
|
|
28
|
-
for (const agreedRoute of agreedRoutes) {
|
|
29
|
-
const fullpath = normalize(`${urlPath}${agreedRoute.path}`) || '/';
|
|
30
|
-
|
|
31
|
-
const route = _objectSpread(_objectSpread({}, pageRoute), {}, {
|
|
32
|
-
path: fullpath,
|
|
33
|
-
agreed: true
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const context = createContext(route, listener); // The hook function can return false to prevent the automatic addition of agreed routes
|
|
37
|
-
|
|
38
|
-
const isStaticPage = await hook(context);
|
|
39
|
-
|
|
40
|
-
if (!isDynamicUrl(fullpath) && isStaticPage !== false) {
|
|
41
|
-
const autoAdd = autoAddAgreed(_objectSpread(_objectSpread({}, context), {}, {
|
|
42
|
-
component: agreedRoute._component
|
|
43
|
-
}));
|
|
44
|
-
autoAdd && context.createPage();
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
} else {
|
|
48
|
-
const route = _objectSpread(_objectSpread({}, pageRoute), {}, {
|
|
49
|
-
path: urlPath
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const context = createContext(route, listener);
|
|
53
|
-
await hook(context);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
|
|
2
|
-
|
|
3
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
4
|
-
|
|
5
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
6
|
-
|
|
7
|
-
export function makeRender(ssgRoutes, render, port) {
|
|
8
|
-
return ssgRoutes.map(ssgRoute => render({
|
|
9
|
-
url: ssgRoute.urlPath,
|
|
10
|
-
headers: _objectSpread({
|
|
11
|
-
host: `localhost:${port}`
|
|
12
|
-
}, ssgRoute.headers),
|
|
13
|
-
connection: {}
|
|
14
|
-
}));
|
|
15
|
-
}
|