@webstir-io/webstir-frontend 0.1.40 → 0.1.41
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/README.md +124 -60
- package/dist/assets/imageOptimizer.js +10 -15
- package/dist/assets/precompression.js +1 -1
- package/dist/builders/contentBuilder.js +102 -90
- package/dist/builders/cssBuilder.js +25 -19
- package/dist/builders/htmlBuilder.js +57 -42
- package/dist/builders/index.js +1 -1
- package/dist/builders/jsBuilder.js +219 -76
- package/dist/builders/staticAssetsBuilder.js +27 -9
- package/dist/builders/types.d.ts +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +6 -30
- package/dist/config/manifest.js +7 -6
- package/dist/config/paths.js +2 -2
- package/dist/config/schema.d.ts +8 -0
- package/dist/config/schema.js +7 -6
- package/dist/config/setup.js +1 -1
- package/dist/config/workspace.js +11 -9
- package/dist/core/constants.d.ts +1 -1
- package/dist/core/constants.js +5 -5
- package/dist/core/diagnostics.js +1 -1
- package/dist/core/pages.js +4 -4
- package/dist/hooks.js +3 -3
- package/dist/html/criticalCss.js +6 -3
- package/dist/html/htmlSecurity.d.ts +6 -1
- package/dist/html/htmlSecurity.js +28 -14
- package/dist/html/lazyLoad.js +1 -1
- package/dist/html/pageScaffold.js +1 -1
- package/dist/html/resourceHints.js +5 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/inspect.d.ts +2 -0
- package/dist/inspect.js +110 -0
- package/dist/modes/ssg/metadata.js +4 -4
- package/dist/modes/ssg/routing.js +2 -5
- package/dist/modes/ssg/seo.js +5 -5
- package/dist/modes/ssg/views.js +17 -11
- package/dist/operations.js +18 -10
- package/dist/pipeline.d.ts +1 -0
- package/dist/pipeline.js +6 -1
- package/dist/provider.js +28 -24
- package/dist/runtime/boundary.d.ts +28 -0
- package/dist/runtime/boundary.js +247 -0
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.js +1 -0
- package/dist/types.d.ts +52 -0
- package/dist/utils/fs.d.ts +11 -10
- package/dist/utils/fs.js +48 -20
- package/dist/utils/glob.d.ts +8 -0
- package/dist/utils/glob.js +21 -0
- package/dist/utils/hash.js +1 -2
- package/dist/utils/pagePaths.js +2 -2
- package/package.json +19 -14
- package/scripts/publish.sh +2 -94
- package/scripts/update-contract.sh +12 -10
- package/src/assets/assetManifest.ts +39 -29
- package/src/assets/imageOptimizer.ts +91 -82
- package/src/assets/precompression.ts +22 -16
- package/src/builders/contentBuilder.ts +1224 -1149
- package/src/builders/cssBuilder.ts +466 -417
- package/src/builders/htmlBuilder.ts +511 -448
- package/src/builders/index.ts +7 -7
- package/src/builders/jsBuilder.ts +538 -280
- package/src/builders/staticAssetsBuilder.ts +166 -135
- package/src/builders/types.ts +7 -6
- package/src/cli.ts +66 -90
- package/src/config/manifest.ts +16 -14
- package/src/config/paths.ts +5 -5
- package/src/config/schema.ts +38 -37
- package/src/config/setup.ts +7 -7
- package/src/config/workspace.ts +118 -116
- package/src/config/workspaceManifest.ts +14 -14
- package/src/core/constants.ts +62 -62
- package/src/core/diagnostics.ts +26 -26
- package/src/core/pages.ts +19 -19
- package/src/hooks.ts +128 -118
- package/src/html/criticalCss.ts +84 -77
- package/src/html/htmlSecurity.ts +107 -66
- package/src/html/lazyLoad.ts +22 -19
- package/src/html/pageScaffold.ts +37 -28
- package/src/html/resourceHints.ts +83 -74
- package/src/index.ts +2 -0
- package/src/inspect.ts +158 -0
- package/src/modes/ssg/metadata.ts +53 -51
- package/src/modes/ssg/routing.ts +177 -177
- package/src/modes/ssg/seo.ts +208 -200
- package/src/modes/ssg/validation.ts +31 -25
- package/src/modes/ssg/views.ts +257 -238
- package/src/operations.ts +105 -95
- package/src/pipeline.ts +81 -69
- package/src/provider.ts +184 -176
- package/src/runtime/boundary.ts +325 -0
- package/src/runtime/index.ts +1 -0
- package/src/types.ts +107 -48
- package/src/utils/changedFile.ts +22 -22
- package/src/utils/fs.ts +73 -26
- package/src/utils/glob.ts +38 -0
- package/src/utils/hash.ts +2 -4
- package/src/utils/pagePaths.ts +35 -23
- package/src/utils/pathMatch.ts +26 -23
- package/tests/add-page-defaults.test.js +44 -39
- package/tests/bundlerParity.test.js +252 -0
- package/tests/cli.contract.test.js +13 -0
- package/tests/content-pages.test.js +108 -13
- package/tests/css-app-imports.test.js +22 -11
- package/tests/css-page-imports.test.js +26 -13
- package/tests/diagnostics.test.js +39 -36
- package/tests/features.test.js +48 -43
- package/tests/hooks.test.js +58 -42
- package/tests/htmlSecurity.test.js +66 -0
- package/tests/inspect.test.js +148 -0
- package/tests/provider.integration.test.js +71 -20
- package/tests/runtime.test.js +493 -0
- package/tests/ssg-defaults.test.js +284 -177
- package/tests/ssg-guardrails.test.js +51 -51
- package/tsconfig.json +3 -10
- package/dist/watch/frontendFiles.d.ts +0 -3
- package/dist/watch/frontendFiles.js +0 -25
- package/dist/watch/hotUpdateTracker.d.ts +0 -51
- package/dist/watch/hotUpdateTracker.js +0 -205
- package/dist/watch/pipelineHelpers.d.ts +0 -26
- package/dist/watch/pipelineHelpers.js +0 -177
- package/dist/watch/types.d.ts +0 -27
- package/dist/watch/types.js +0 -1
- package/dist/watch/watchCoordinator.d.ts +0 -36
- package/dist/watch/watchCoordinator.js +0 -551
- package/dist/watch/watchDaemon.d.ts +0 -17
- package/dist/watch/watchDaemon.js +0 -127
- package/dist/watch/watchReporter.d.ts +0 -21
- package/dist/watch/watchReporter.js +0 -64
- package/scripts/smoke.mjs +0 -35
- package/src/watch/frontendFiles.ts +0 -32
- package/src/watch/hotUpdateTracker.ts +0 -285
- package/src/watch/pipelineHelpers.ts +0 -242
- package/src/watch/types.ts +0 -23
- package/src/watch/watchCoordinator.ts +0 -666
- package/src/watch/watchDaemon.ts +0 -144
- package/src/watch/watchReporter.ts +0 -98
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { load } from 'cheerio';
|
|
4
|
+
|
|
5
|
+
import { addSubresourceIntegrity } from '../dist/html/htmlSecurity.js';
|
|
6
|
+
|
|
7
|
+
test('addSubresourceIntegrity skips external fetches by default', async () => {
|
|
8
|
+
const document = load(`
|
|
9
|
+
<html>
|
|
10
|
+
<head>
|
|
11
|
+
<script src="https://cdn.example.com/app.js"></script>
|
|
12
|
+
<link rel="stylesheet" href="https://cdn.example.com/app.css" />
|
|
13
|
+
</head>
|
|
14
|
+
</html>
|
|
15
|
+
`);
|
|
16
|
+
|
|
17
|
+
let calls = 0;
|
|
18
|
+
const result = await addSubresourceIntegrity(document, {
|
|
19
|
+
fetcher: async () => {
|
|
20
|
+
calls += 1;
|
|
21
|
+
throw new Error('fetch should not be called when external fetch is disabled');
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
assert.equal(calls, 0);
|
|
26
|
+
assert.deepEqual(result.failures, []);
|
|
27
|
+
assert.deepEqual(result.skippedExternalResources, [
|
|
28
|
+
'https://cdn.example.com/app.js',
|
|
29
|
+
'https://cdn.example.com/app.css',
|
|
30
|
+
]);
|
|
31
|
+
assert.equal(document('script').attr('integrity'), undefined);
|
|
32
|
+
assert.equal(document('link').attr('integrity'), undefined);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('addSubresourceIntegrity can opt in to fetching external resources', async () => {
|
|
36
|
+
const document = load(`
|
|
37
|
+
<html>
|
|
38
|
+
<head>
|
|
39
|
+
<script src="https://cdn.example.com/app.js"></script>
|
|
40
|
+
<link rel="stylesheet" href="https://cdn.example.com/app.css" />
|
|
41
|
+
</head>
|
|
42
|
+
</html>
|
|
43
|
+
`);
|
|
44
|
+
|
|
45
|
+
let calls = 0;
|
|
46
|
+
const result = await addSubresourceIntegrity(document, {
|
|
47
|
+
allowExternalFetch: true,
|
|
48
|
+
fetcher: async () => {
|
|
49
|
+
calls += 1;
|
|
50
|
+
return {
|
|
51
|
+
ok: true,
|
|
52
|
+
async arrayBuffer() {
|
|
53
|
+
return Buffer.from('console.log("webstir");');
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
assert.equal(calls, 2);
|
|
60
|
+
assert.deepEqual(result.failures, []);
|
|
61
|
+
assert.deepEqual(result.skippedExternalResources, []);
|
|
62
|
+
assert.match(String(document('script').attr('integrity')), /^sha384-/);
|
|
63
|
+
assert.match(String(document('link').attr('integrity')), /^sha384-/);
|
|
64
|
+
assert.equal(document('script').attr('crossorigin'), 'anonymous');
|
|
65
|
+
assert.equal(document('link').attr('crossorigin'), 'anonymous');
|
|
66
|
+
});
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import fssync from 'node:fs';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
|
|
8
|
+
import { inspectFrontendWorkspace } from '../dist/index.js';
|
|
9
|
+
|
|
10
|
+
async function createWorkspace({ frontendConfig, pkg, withFrontend = true } = {}) {
|
|
11
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'webstir-frontend-inspect-'));
|
|
12
|
+
const frontendRoot = path.join(root, 'src', 'frontend');
|
|
13
|
+
|
|
14
|
+
if (withFrontend) {
|
|
15
|
+
await fs.mkdir(frontendRoot, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
await fs.writeFile(
|
|
19
|
+
path.join(root, 'package.json'),
|
|
20
|
+
JSON.stringify(
|
|
21
|
+
pkg ?? {
|
|
22
|
+
name: 'inspect-workspace',
|
|
23
|
+
version: '1.0.0',
|
|
24
|
+
},
|
|
25
|
+
null,
|
|
26
|
+
2,
|
|
27
|
+
),
|
|
28
|
+
'utf8',
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
if (frontendConfig !== undefined) {
|
|
32
|
+
await fs.writeFile(
|
|
33
|
+
path.join(frontendRoot, 'frontend.config.json'),
|
|
34
|
+
JSON.stringify(frontendConfig, null, 2),
|
|
35
|
+
'utf8',
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
root,
|
|
41
|
+
cleanup: () => fs.rm(root, { recursive: true, force: true }),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
test('inspectFrontendWorkspace resolves shallow workspace facts without building', async (t) => {
|
|
46
|
+
const workspace = await createWorkspace({
|
|
47
|
+
pkg: {
|
|
48
|
+
name: 'inspect-workspace',
|
|
49
|
+
version: '1.0.0',
|
|
50
|
+
webstir: {
|
|
51
|
+
enable: {
|
|
52
|
+
clientNav: true,
|
|
53
|
+
contentNav: true,
|
|
54
|
+
unknownFlag: true,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
frontendConfig: {
|
|
59
|
+
paths: {
|
|
60
|
+
contentRoot: 'docs/content',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
t.after(workspace.cleanup);
|
|
66
|
+
|
|
67
|
+
const appRoot = path.join(workspace.root, 'src', 'frontend', 'app');
|
|
68
|
+
const pageRoot = path.join(workspace.root, 'src', 'frontend', 'pages', 'home');
|
|
69
|
+
const contentRoot = path.join(workspace.root, 'docs', 'content');
|
|
70
|
+
|
|
71
|
+
await fs.mkdir(appRoot, { recursive: true });
|
|
72
|
+
await fs.mkdir(pageRoot, { recursive: true });
|
|
73
|
+
await fs.mkdir(contentRoot, { recursive: true });
|
|
74
|
+
|
|
75
|
+
await fs.writeFile(path.join(appRoot, 'app.html'), '<!doctype html><html></html>', 'utf8');
|
|
76
|
+
await fs.writeFile(path.join(appRoot, 'app.css'), 'body{}', 'utf8');
|
|
77
|
+
await fs.writeFile(path.join(appRoot, 'app.ts'), 'export {};\n', 'utf8');
|
|
78
|
+
await fs.writeFile(path.join(pageRoot, 'index.html'), '<head></head><main></main>', 'utf8');
|
|
79
|
+
await fs.writeFile(path.join(pageRoot, 'index.css'), 'main{}', 'utf8');
|
|
80
|
+
await fs.writeFile(path.join(pageRoot, 'index.ts'), 'export {};\n', 'utf8');
|
|
81
|
+
await fs.writeFile(path.join(contentRoot, '_sidebar.json'), '{}', 'utf8');
|
|
82
|
+
|
|
83
|
+
const result = await inspectFrontendWorkspace(workspace.root);
|
|
84
|
+
|
|
85
|
+
assert.equal(result.config.paths.src.content, contentRoot);
|
|
86
|
+
assert.equal(result.packageJson.exists, true);
|
|
87
|
+
assert.deepEqual(result.packageJson.enable.raw, {
|
|
88
|
+
clientNav: true,
|
|
89
|
+
contentNav: true,
|
|
90
|
+
unknownFlag: true,
|
|
91
|
+
});
|
|
92
|
+
assert.deepEqual(result.packageJson.enable.known, {
|
|
93
|
+
spa: false,
|
|
94
|
+
clientNav: true,
|
|
95
|
+
backend: false,
|
|
96
|
+
search: false,
|
|
97
|
+
contentNav: true,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
assert.equal(result.appShell.exists, true);
|
|
101
|
+
assert.equal(result.appShell.templateExists, true);
|
|
102
|
+
assert.equal(result.appShell.stylesheetExists, true);
|
|
103
|
+
assert.equal(result.appShell.scriptExists, true);
|
|
104
|
+
|
|
105
|
+
assert.deepEqual(
|
|
106
|
+
result.pages.map((page) => ({
|
|
107
|
+
name: page.name,
|
|
108
|
+
htmlExists: page.htmlExists,
|
|
109
|
+
stylesheetExists: page.stylesheetExists,
|
|
110
|
+
scriptExists: page.scriptExists,
|
|
111
|
+
})),
|
|
112
|
+
[
|
|
113
|
+
{
|
|
114
|
+
name: 'home',
|
|
115
|
+
htmlExists: true,
|
|
116
|
+
stylesheetExists: true,
|
|
117
|
+
scriptExists: true,
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
assert.equal(result.content.exists, true);
|
|
123
|
+
assert.equal(result.content.sidebarOverrideExists, true);
|
|
124
|
+
|
|
125
|
+
assert.equal(fssync.existsSync(path.join(workspace.root, 'build')), false);
|
|
126
|
+
assert.equal(fssync.existsSync(path.join(workspace.root, '.webstir')), false);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('inspectFrontendWorkspace reports absent frontend facts cleanly', async (t) => {
|
|
130
|
+
const workspace = await createWorkspace();
|
|
131
|
+
t.after(workspace.cleanup);
|
|
132
|
+
|
|
133
|
+
const result = await inspectFrontendWorkspace(workspace.root);
|
|
134
|
+
|
|
135
|
+
assert.equal(result.packageJson.exists, true);
|
|
136
|
+
assert.equal(result.packageJson.enable.raw, undefined);
|
|
137
|
+
assert.deepEqual(result.packageJson.enable.known, {
|
|
138
|
+
spa: false,
|
|
139
|
+
clientNav: false,
|
|
140
|
+
backend: false,
|
|
141
|
+
search: false,
|
|
142
|
+
contentNav: false,
|
|
143
|
+
});
|
|
144
|
+
assert.equal(result.appShell.exists, false);
|
|
145
|
+
assert.equal(result.pages.length, 0);
|
|
146
|
+
assert.equal(result.content.exists, false);
|
|
147
|
+
assert.equal(result.content.sidebarOverrideExists, false);
|
|
148
|
+
});
|
|
@@ -11,7 +11,10 @@ async function loadProviderOrSkip(t) {
|
|
|
11
11
|
return mod.frontendProvider;
|
|
12
12
|
} catch (err) {
|
|
13
13
|
// Likely due to optional native deps like sharp; skip gracefully.
|
|
14
|
-
console.warn(
|
|
14
|
+
console.warn(
|
|
15
|
+
'[frontend-tests] Skipping provider integration: optional dependency unavailable:',
|
|
16
|
+
err?.message ?? err,
|
|
17
|
+
);
|
|
15
18
|
t?.diagnostic?.('skip: missing optional dependency');
|
|
16
19
|
return null;
|
|
17
20
|
}
|
|
@@ -25,8 +28,16 @@ async function createWorkspace() {
|
|
|
25
28
|
await fs.mkdir(pageDir, { recursive: true });
|
|
26
29
|
|
|
27
30
|
// Minimal app template and page fragment
|
|
28
|
-
await fs.writeFile(
|
|
29
|
-
|
|
31
|
+
await fs.writeFile(
|
|
32
|
+
path.join(appDir, 'app.html'),
|
|
33
|
+
'<!DOCTYPE html><html><head><title>App</title></head><body><main></main></body></html>',
|
|
34
|
+
'utf8',
|
|
35
|
+
);
|
|
36
|
+
await fs.writeFile(
|
|
37
|
+
path.join(pageDir, 'index.html'),
|
|
38
|
+
'<head></head><main><section>Home</section></main>',
|
|
39
|
+
'utf8',
|
|
40
|
+
);
|
|
30
41
|
await fs.writeFile(path.join(pageDir, 'index.ts'), 'console.log("home");', 'utf8');
|
|
31
42
|
|
|
32
43
|
return root;
|
|
@@ -47,16 +58,28 @@ async function createWorkspaceWithClientNav() {
|
|
|
47
58
|
webstir: {
|
|
48
59
|
mode: 'ssg',
|
|
49
60
|
enable: {
|
|
50
|
-
clientNav: true
|
|
51
|
-
}
|
|
52
|
-
}
|
|
61
|
+
clientNav: true,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
53
64
|
};
|
|
54
65
|
await fs.writeFile(path.join(root, 'package.json'), JSON.stringify(pkg, null, 2), 'utf8');
|
|
55
66
|
|
|
56
|
-
await fs.writeFile(
|
|
57
|
-
|
|
67
|
+
await fs.writeFile(
|
|
68
|
+
path.join(appDir, 'app.html'),
|
|
69
|
+
'<!DOCTYPE html><html><head><title>App</title></head><body><main></main></body></html>',
|
|
70
|
+
'utf8',
|
|
71
|
+
);
|
|
72
|
+
await fs.writeFile(
|
|
73
|
+
path.join(appDir, 'app.ts'),
|
|
74
|
+
'import "./scripts/features/client-nav.js";',
|
|
75
|
+
'utf8',
|
|
76
|
+
);
|
|
58
77
|
await fs.writeFile(path.join(featureDir, 'client-nav.ts'), 'export {};', 'utf8');
|
|
59
|
-
await fs.writeFile(
|
|
78
|
+
await fs.writeFile(
|
|
79
|
+
path.join(pageDir, 'index.html'),
|
|
80
|
+
'<head></head><main><section>Home</section></main>',
|
|
81
|
+
'utf8',
|
|
82
|
+
);
|
|
60
83
|
|
|
61
84
|
return root;
|
|
62
85
|
}
|
|
@@ -85,8 +108,16 @@ test('frontend provider publish produces dist assets and preserves entry in mani
|
|
|
85
108
|
const workspace = await createWorkspace();
|
|
86
109
|
|
|
87
110
|
// Run build first so manifest has entries from build/frontend
|
|
88
|
-
await frontendProvider.build({
|
|
89
|
-
|
|
111
|
+
await frontendProvider.build({
|
|
112
|
+
workspaceRoot: workspace,
|
|
113
|
+
env: { WEBSTIR_MODULE_MODE: 'build' },
|
|
114
|
+
incremental: false,
|
|
115
|
+
});
|
|
116
|
+
const publishResult = await frontendProvider.build({
|
|
117
|
+
workspaceRoot: workspace,
|
|
118
|
+
env: { WEBSTIR_MODULE_MODE: 'publish' },
|
|
119
|
+
incremental: false,
|
|
120
|
+
});
|
|
90
121
|
|
|
91
122
|
// Dist should contain a hashed JS file
|
|
92
123
|
const distPageDir = path.join(workspace, 'dist', 'frontend', 'pages', 'home');
|
|
@@ -102,13 +133,28 @@ test('enable.clientNav uses feature module (no legacy helper injection)', async
|
|
|
102
133
|
if (!frontendProvider) return; // skip
|
|
103
134
|
const workspace = await createWorkspaceWithClientNav();
|
|
104
135
|
|
|
105
|
-
await frontendProvider.build({
|
|
106
|
-
|
|
136
|
+
await frontendProvider.build({
|
|
137
|
+
workspaceRoot: workspace,
|
|
138
|
+
env: { WEBSTIR_MODULE_MODE: 'build' },
|
|
139
|
+
incremental: false,
|
|
140
|
+
});
|
|
141
|
+
await frontendProvider.build({
|
|
142
|
+
workspaceRoot: workspace,
|
|
143
|
+
env: { WEBSTIR_MODULE_MODE: 'publish' },
|
|
144
|
+
incremental: false,
|
|
145
|
+
});
|
|
107
146
|
|
|
108
147
|
const distClientNav = path.join(workspace, 'dist', 'frontend', 'clientNav.js');
|
|
109
|
-
assert.equal(
|
|
148
|
+
assert.equal(
|
|
149
|
+
fssync.existsSync(distClientNav),
|
|
150
|
+
false,
|
|
151
|
+
'did not expect dist/frontend/clientNav.js',
|
|
152
|
+
);
|
|
110
153
|
|
|
111
|
-
const distHtml = await fs.readFile(
|
|
154
|
+
const distHtml = await fs.readFile(
|
|
155
|
+
path.join(workspace, 'dist', 'frontend', 'index.html'),
|
|
156
|
+
'utf8',
|
|
157
|
+
);
|
|
112
158
|
assert.ok(!distHtml.includes('clientNav.js'), 'did not expect client-nav script injected');
|
|
113
159
|
assert.ok(!distHtml.includes('index.js'), 'should not inject page index.js when none exists');
|
|
114
160
|
});
|
|
@@ -124,14 +170,19 @@ test('enable.clientNav without feature module fails fast', async (t) => {
|
|
|
124
170
|
webstir: {
|
|
125
171
|
mode: 'ssg',
|
|
126
172
|
enable: {
|
|
127
|
-
clientNav: true
|
|
128
|
-
}
|
|
129
|
-
}
|
|
173
|
+
clientNav: true,
|
|
174
|
+
},
|
|
175
|
+
},
|
|
130
176
|
};
|
|
131
177
|
await fs.writeFile(path.join(workspace, 'package.json'), JSON.stringify(pkg, null, 2), 'utf8');
|
|
132
178
|
|
|
133
179
|
await assert.rejects(
|
|
134
|
-
() =>
|
|
135
|
-
|
|
180
|
+
() =>
|
|
181
|
+
frontendProvider.build({
|
|
182
|
+
workspaceRoot: workspace,
|
|
183
|
+
env: { WEBSTIR_MODULE_MODE: 'build' },
|
|
184
|
+
incremental: false,
|
|
185
|
+
}),
|
|
186
|
+
/Enabled feature module\(s\) missing: client-nav/,
|
|
136
187
|
);
|
|
137
188
|
});
|