slicejs-cli 3.4.0 → 3.4.1
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/AGENTS.md +247 -0
- package/client.js +63 -64
- package/commands/Print.js +11 -15
- package/commands/Validations.js +12 -23
- package/commands/buildProduction/buildProduction.js +23 -26
- package/commands/bundle/bundle.js +10 -11
- package/commands/createComponent/createComponent.js +14 -16
- package/commands/deleteComponent/deleteComponent.js +6 -6
- package/commands/doctor/doctor.js +11 -14
- package/commands/getComponent/getComponent.js +99 -162
- package/commands/init/init.js +25 -21
- package/commands/listComponents/listComponents.js +18 -21
- package/commands/startServer/startServer.js +21 -24
- package/commands/startServer/watchServer.js +7 -7
- package/commands/types/types.js +53 -18
- package/commands/utils/PathHelper.js +9 -2
- package/commands/utils/VersionChecker.js +3 -3
- package/commands/utils/bundling/DependencyAnalyzer.js +8 -16
- package/commands/utils/loadConfig.js +31 -0
- package/commands/utils/updateManager.js +3 -4
- package/docs/superpowers/specs/2026-05-10-pwa-generate-design.md +105 -105
- package/package.json +15 -3
- package/post.js +2 -2
- package/tests/bundle-generator.test.js +3 -20
- package/tests/component-registry-parse.test.js +34 -0
- package/tests/fixtures/components.js +8 -0
- package/tests/fixtures/sliceConfig.json +74 -0
- package/tests/getcomponent.test.js +407 -0
- package/tests/helpers/setup.js +97 -0
- package/tests/init-command-contract.test.js +46 -0
- package/tests/local-cli-delegation.test.js +7 -5
- package/tests/path-helper.test.js +206 -0
- package/tests/types-breakage.test.js +491 -0
- package/tests/types-generator-errors.test.js +361 -0
- package/tests/types-generator.test.js +172 -184
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Design of `slice generate-pwa` (V1)
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Objective
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Add a dedicated CLI command, `slice generate-pwa`, that converts a Slice build into an offline-capable PWA, with configurable cache strategy and explicit backend domain exclusion to prevent accidental REST API caching.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The command must be post-bundle, operate on `dist/`, and maintain a simple V1 experience.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## V1 Scope
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
11
|
+
- New `slice generate-pwa` command.
|
|
12
|
+
- Automatically run `build` before the PWA process.
|
|
13
|
+
- Generate `manifest.json` in `dist/`.
|
|
14
|
+
- Generate `sw.js` in `dist/`.
|
|
15
|
+
- Register Service Worker in the entry HTML of `dist`.
|
|
16
|
+
- Support strategies: `hybrid` (default), `offline-first`, `network-first`.
|
|
17
|
+
- Persist and read configuration from `src/sliceConfig.json` in:
|
|
18
18
|
- `pwa.cache.excludeDomains`.
|
|
19
|
-
-
|
|
19
|
+
- Apply effective exclusion of `localhost` and `127.0.0.1` in development.
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## Out of V1 Scope
|
|
22
22
|
|
|
23
|
-
- Exclusion
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
23
|
+
- Exclusion by paths or headers (`excludePaths`, `excludeHeaders`).
|
|
24
|
+
- Advanced interactive UI for creating PWA icons.
|
|
25
|
+
- Support for push notifications, background sync, or advanced runtime caching by API type.
|
|
26
|
+
- Formal plugin system; left prepared for future evolution.
|
|
27
27
|
|
|
28
|
-
## UX
|
|
28
|
+
## Command UX
|
|
29
29
|
|
|
30
|
-
###
|
|
30
|
+
### Syntax
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
33
|
slice generate-pwa
|
|
34
34
|
slice generate-pwa --strategy hybrid
|
|
35
35
|
slice generate-pwa --strategy offline-first
|
|
36
36
|
slice generate-pwa --strategy network-first
|
|
37
|
-
slice generate-pwa --name "
|
|
37
|
+
slice generate-pwa --name "My App" --short-name "MyApp"
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
### Flags
|
|
40
|
+
### V1 Flags
|
|
41
41
|
|
|
42
42
|
- `--strategy <hybrid|offline-first|network-first>` (default: `hybrid`)
|
|
43
43
|
- `--name <string>`
|
|
44
44
|
- `--short-name <string>`
|
|
45
45
|
|
|
46
|
-
###
|
|
46
|
+
### Execution flow
|
|
47
47
|
|
|
48
|
-
1.
|
|
49
|
-
2.
|
|
50
|
-
3.
|
|
51
|
-
4.
|
|
52
|
-
5.
|
|
53
|
-
6.
|
|
54
|
-
7.
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
48
|
+
1. Run production build.
|
|
49
|
+
2. Read and normalize PWA configuration from `src/sliceConfig.json`.
|
|
50
|
+
3. Generate asset manifest for precache from `dist/`.
|
|
51
|
+
4. Generate `dist/manifest.json`.
|
|
52
|
+
5. Generate `dist/sw.js` with the selected strategy.
|
|
53
|
+
6. Inject (or ensure) SW registration in entry HTML of `dist`.
|
|
54
|
+
7. Print final summary:
|
|
55
|
+
- strategy used,
|
|
56
|
+
- number of precached assets,
|
|
57
|
+
- effective excluded domains.
|
|
58
58
|
|
|
59
|
-
##
|
|
59
|
+
## Configuration in `sliceConfig.json`
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
V1 minimal section:
|
|
62
62
|
|
|
63
63
|
```json
|
|
64
64
|
{
|
|
@@ -70,113 +70,113 @@ Seccion minima V1:
|
|
|
70
70
|
}
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
Rules:
|
|
74
74
|
|
|
75
|
-
-
|
|
76
|
-
- `excludeDomains`
|
|
77
|
-
-
|
|
75
|
+
- If `pwa` does not exist, the command creates the section without breaking existing configuration.
|
|
76
|
+
- `excludeDomains` accepts exact hosts (e.g., `api.mydomain.com`).
|
|
77
|
+
- In development execution, `localhost` and `127.0.0.1` are effectively added (not necessarily persisted).
|
|
78
78
|
|
|
79
|
-
##
|
|
79
|
+
## Proposed Architecture
|
|
80
80
|
|
|
81
|
-
###
|
|
81
|
+
### CLI Integration
|
|
82
82
|
|
|
83
|
-
-
|
|
83
|
+
- Add command in `client.js`:
|
|
84
84
|
- `generate-pwa`
|
|
85
|
-
-
|
|
86
|
-
-
|
|
85
|
+
- `--strategy` option
|
|
86
|
+
- name options for manifest
|
|
87
87
|
|
|
88
|
-
###
|
|
88
|
+
### New Modules
|
|
89
89
|
|
|
90
90
|
- `commands/pwa/generatePwa.js`
|
|
91
|
-
-
|
|
91
|
+
- Orchestrator of the complete flow.
|
|
92
92
|
- `commands/pwa/ConfigResolver.js`
|
|
93
|
-
-
|
|
93
|
+
- Reads/creates/normalizes `pwa.cache.excludeDomains`.
|
|
94
94
|
- `commands/pwa/AssetManifestBuilder.js`
|
|
95
|
-
-
|
|
95
|
+
- Iterates `dist/` and builds precache list.
|
|
96
96
|
- `commands/pwa/ManifestGenerator.js`
|
|
97
|
-
-
|
|
97
|
+
- Generates `manifest.json` with defaults and flag overrides.
|
|
98
98
|
- `commands/pwa/ServiceWorkerGenerator.js`
|
|
99
|
-
-
|
|
99
|
+
- Generates `sw.js` with selected strategy and exclusions.
|
|
100
100
|
|
|
101
|
-
##
|
|
101
|
+
## Cache Design
|
|
102
102
|
|
|
103
|
-
###
|
|
103
|
+
### Global Rules
|
|
104
104
|
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
-
|
|
108
|
-
-
|
|
105
|
+
- Intercept only `GET` requests.
|
|
106
|
+
- If the host is in `excludeDomains`, do a direct `fetch` (no cache).
|
|
107
|
+
- Cache versioning by build id (timestamp or build hash).
|
|
108
|
+
- On new SW activation, automatically clean old caches.
|
|
109
109
|
|
|
110
|
-
###
|
|
110
|
+
### Strategies
|
|
111
111
|
|
|
112
112
|
- `hybrid` (default):
|
|
113
|
-
- assets
|
|
114
|
-
-
|
|
113
|
+
- static assets -> `cache-first`.
|
|
114
|
+
- HTML navigation -> `network-first` with offline fallback.
|
|
115
115
|
- `offline-first`:
|
|
116
|
-
-
|
|
117
|
-
-
|
|
116
|
+
- navigation + static -> `cache-first`.
|
|
117
|
+
- background update when online.
|
|
118
118
|
- `network-first`:
|
|
119
|
-
-
|
|
120
|
-
-
|
|
119
|
+
- navigation -> `network-first`.
|
|
120
|
+
- precached static assets as fallback.
|
|
121
121
|
|
|
122
|
-
##
|
|
122
|
+
## REST API and Security Handling
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
To prevent unwanted backend caching:
|
|
125
125
|
|
|
126
|
-
-
|
|
127
|
-
-
|
|
128
|
-
-
|
|
126
|
+
- Domain exclusion via `excludeDomains` (main V1 rule).
|
|
127
|
+
- Limit runtime cache to frontend assets and navigation per strategy.
|
|
128
|
+
- Do not cache methods other than `GET`.
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
Result: client assets are accelerated offline, but the backend stays out of the cache via explicit configuration.
|
|
131
131
|
|
|
132
132
|
## Error handling
|
|
133
133
|
|
|
134
|
-
-
|
|
135
|
-
-
|
|
136
|
-
-
|
|
137
|
-
-
|
|
134
|
+
- If build fails, abort `generate-pwa` with a clear message.
|
|
135
|
+
- If `dist/` does not exist after build, abort with diagnostics.
|
|
136
|
+
- If `sliceConfig.json` is invalid, show error with repair suggestion.
|
|
137
|
+
- If SW registration cannot be injected into HTML, report warning and target path.
|
|
138
138
|
|
|
139
139
|
## Testing
|
|
140
140
|
|
|
141
141
|
### Unit tests
|
|
142
142
|
|
|
143
143
|
- `ConfigResolver`:
|
|
144
|
-
-
|
|
145
|
-
-
|
|
144
|
+
- creates `pwa.cache.excludeDomains` section when it does not exist,
|
|
145
|
+
- respects existing config.
|
|
146
146
|
- `AssetManifestBuilder`:
|
|
147
|
-
-
|
|
148
|
-
-
|
|
147
|
+
- includes expected assets,
|
|
148
|
+
- excludes unsuitable files.
|
|
149
149
|
- `ServiceWorkerGenerator`:
|
|
150
|
-
-
|
|
151
|
-
-
|
|
150
|
+
- generates correct logic per strategy,
|
|
151
|
+
- respects `excludeDomains`.
|
|
152
152
|
|
|
153
|
-
###
|
|
153
|
+
### Integration
|
|
154
154
|
|
|
155
|
-
- `slice generate-pwa`
|
|
156
|
-
-
|
|
157
|
-
-
|
|
155
|
+
- `slice generate-pwa` runs build and creates `dist/manifest.json` + `dist/sw.js`.
|
|
156
|
+
- SW registration present in output HTML.
|
|
157
|
+
- domain exclusions applied in generated code.
|
|
158
158
|
|
|
159
|
-
### E2E manual
|
|
159
|
+
### Minimal E2E manual
|
|
160
160
|
|
|
161
161
|
- Build + generate-pwa.
|
|
162
|
-
-
|
|
163
|
-
-
|
|
164
|
-
-
|
|
165
|
-
|
|
166
|
-
## Plan
|
|
167
|
-
|
|
168
|
-
- `excludePaths`
|
|
169
|
-
-
|
|
170
|
-
-
|
|
171
|
-
-
|
|
172
|
-
|
|
173
|
-
##
|
|
174
|
-
|
|
175
|
-
-
|
|
176
|
-
-
|
|
177
|
-
-
|
|
178
|
-
-
|
|
179
|
-
- `hybrid`
|
|
180
|
-
-
|
|
181
|
-
-
|
|
182
|
-
-
|
|
162
|
+
- Open app, validate installability (manifest).
|
|
163
|
+
- Turn off network, validate offline navigation in `hybrid`.
|
|
164
|
+
- Verify that requests to excluded domain are not served from SW cache.
|
|
165
|
+
|
|
166
|
+
## Evolution Plan (post V1)
|
|
167
|
+
|
|
168
|
+
- `excludePaths` and `excludeHeaders`.
|
|
169
|
+
- Assisted PWA icon and shortcut support.
|
|
170
|
+
- Per-route strategy (e.g., `/api/*` network-only).
|
|
171
|
+
- Extract reusable postbundle pipeline for other features.
|
|
172
|
+
|
|
173
|
+
## Acceptance Criteria
|
|
174
|
+
|
|
175
|
+
- Functional `slice generate-pwa` command exists.
|
|
176
|
+
- Runs build before generating PWA artifacts.
|
|
177
|
+
- Generates `manifest.json` and `sw.js` in `dist/`.
|
|
178
|
+
- Registers SW in main output HTML.
|
|
179
|
+
- `hybrid` is default with HTML `network-first` and offline fallback.
|
|
180
|
+
- Reads/writes `pwa.cache.excludeDomains` in `src/sliceConfig.json`.
|
|
181
|
+
- Excludes configured domains from runtime cache.
|
|
182
|
+
- Shows a readable final summary to the user.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slicejs-cli",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.1",
|
|
4
4
|
"description": "Command client for developing web applications with Slice.js framework",
|
|
5
5
|
"main": "client.js",
|
|
6
6
|
"bin": {
|
|
@@ -12,7 +12,19 @@
|
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
14
|
"test": "node --test",
|
|
15
|
-
"postinstall": "node post.js"
|
|
15
|
+
"postinstall": "node post.js",
|
|
16
|
+
"slice:dev": "slice dev",
|
|
17
|
+
"slice:start": "slice start",
|
|
18
|
+
"slice:create": "slice component create",
|
|
19
|
+
"slice:list": "slice component list",
|
|
20
|
+
"slice:delete": "slice component delete",
|
|
21
|
+
"slice:init": "slice init",
|
|
22
|
+
"slice:get": "slice get",
|
|
23
|
+
"slice:browse": "slice browse",
|
|
24
|
+
"slice:sync": "slice sync",
|
|
25
|
+
"slice:version": "slice version",
|
|
26
|
+
"slice:update": "slice update",
|
|
27
|
+
"slice:types": "slice types generate"
|
|
16
28
|
},
|
|
17
29
|
"keywords": [
|
|
18
30
|
"framework",
|
|
@@ -43,4 +55,4 @@
|
|
|
43
55
|
"slicejs-web-framework": "latest",
|
|
44
56
|
"terser": "^5.43.1"
|
|
45
57
|
}
|
|
46
|
-
}
|
|
58
|
+
}
|
package/post.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
|
-
import { getProjectRoot } from './commands/utils/PathHelper.js';
|
|
4
|
+
import { getProjectRoot, getPath } from './commands/utils/PathHelper.js';
|
|
5
5
|
|
|
6
6
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
7
|
|
|
@@ -15,7 +15,7 @@ if (isGlobal) {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const projectRoot = getProjectRoot(import.meta.url);
|
|
18
|
-
const pkgPath =
|
|
18
|
+
const pkgPath = getPath(import.meta.url, 'package.json');
|
|
19
19
|
|
|
20
20
|
const sliceScripts = {
|
|
21
21
|
'slice:dev': 'slice dev',
|
|
@@ -4,6 +4,7 @@ import fs from 'fs-extra';
|
|
|
4
4
|
import os from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import BundleGenerator from '../commands/utils/bundling/BundleGenerator.js';
|
|
7
|
+
import { withTestProject } from './helpers/setup.js';
|
|
7
8
|
|
|
8
9
|
const createComponent = (name, deps = []) => ({
|
|
9
10
|
name,
|
|
@@ -78,18 +79,7 @@ test('loading policy is enabled when sliceConfig loading.enabled is true', () =>
|
|
|
78
79
|
});
|
|
79
80
|
|
|
80
81
|
test('loading policy falls back to project sliceConfig when analysisData lacks sliceConfig', async () => {
|
|
81
|
-
|
|
82
|
-
const srcDir = path.join(tempRoot, 'src');
|
|
83
|
-
const previousInitCwd = process.env.INIT_CWD;
|
|
84
|
-
|
|
85
|
-
await fs.ensureDir(srcDir);
|
|
86
|
-
await fs.writeJson(path.join(srcDir, 'sliceConfig.json'), {
|
|
87
|
-
loading: { enabled: true }
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
process.env.INIT_CWD = tempRoot;
|
|
91
|
-
|
|
92
|
-
try {
|
|
82
|
+
await withTestProject(async () => {
|
|
93
83
|
const generator = new BundleGenerator(import.meta.url, {
|
|
94
84
|
components: [],
|
|
95
85
|
routes: [],
|
|
@@ -103,14 +93,7 @@ test('loading policy falls back to project sliceConfig when analysisData lacks s
|
|
|
103
93
|
|
|
104
94
|
const config = generator.generateBundleConfig(null);
|
|
105
95
|
assert.equal(config.loadingPolicy, 'enabled');
|
|
106
|
-
}
|
|
107
|
-
if (previousInitCwd === undefined) {
|
|
108
|
-
delete process.env.INIT_CWD;
|
|
109
|
-
} else {
|
|
110
|
-
process.env.INIT_CWD = previousInitCwd;
|
|
111
|
-
}
|
|
112
|
-
await fs.remove(tempRoot);
|
|
113
|
-
}
|
|
96
|
+
});
|
|
114
97
|
});
|
|
115
98
|
|
|
116
99
|
test('loading enabled always includes Loading component in critical bundle', () => {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { createTestProject, cleanupTestProject, withTestProject } from './helpers/setup.js';
|
|
6
|
+
|
|
7
|
+
test('generateTypesFile parses JSON from components.js (no eval)', async () => {
|
|
8
|
+
const tmpRoot = await createTestProject({ visualComponents: ['Button'] });
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const srcDir = path.join(tmpRoot, 'src');
|
|
12
|
+
const { generateTypesFile } = await import('../commands/types/types.js');
|
|
13
|
+
const result = await generateTypesFile({
|
|
14
|
+
projectRoot: tmpRoot,
|
|
15
|
+
outputPath: path.join(srcDir, 'slice-build.generated.d.ts')
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
assert.ok(result.componentsProcessed > 0);
|
|
19
|
+
assert.equal(fs.existsSync(result.outputPath), true);
|
|
20
|
+
|
|
21
|
+
const declaration = fs.readFileSync(result.outputPath, 'utf8');
|
|
22
|
+
assert.match(declaration, /export interface ButtonProps/);
|
|
23
|
+
} finally {
|
|
24
|
+
await cleanupTestProject(tmpRoot);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('Validations componentExists with JSON.parse (no eval)', async () => {
|
|
29
|
+
await withTestProject(async (tmpDir) => {
|
|
30
|
+
const validations = (await import('../commands/Validations.js')).default;
|
|
31
|
+
assert.equal(validations.componentExists('Button'), true);
|
|
32
|
+
assert.equal(validations.componentExists('NonExistent'), false);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"server": {
|
|
3
|
+
"port": 3001,
|
|
4
|
+
"host": "localhost"
|
|
5
|
+
},
|
|
6
|
+
"debugger": {
|
|
7
|
+
"enabled": false,
|
|
8
|
+
"click": "right"
|
|
9
|
+
},
|
|
10
|
+
"events": {
|
|
11
|
+
"enabled": true,
|
|
12
|
+
"ui": {
|
|
13
|
+
"enabled": true,
|
|
14
|
+
"shortcut": "alt+shift+e"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"context": {
|
|
18
|
+
"enabled": true,
|
|
19
|
+
"ui": {
|
|
20
|
+
"enabled": true,
|
|
21
|
+
"shortcut": "alt+shift+c"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"stylesManager": {
|
|
25
|
+
"requestedStyles": ["sliceStyles"]
|
|
26
|
+
},
|
|
27
|
+
"themeManager": {
|
|
28
|
+
"enabled": true,
|
|
29
|
+
"defaultTheme": "Slice",
|
|
30
|
+
"saveThemeLocally": false,
|
|
31
|
+
"useBrowserTheme": false
|
|
32
|
+
},
|
|
33
|
+
"logger": {
|
|
34
|
+
"enabled": true,
|
|
35
|
+
"showLogs": {
|
|
36
|
+
"console": {
|
|
37
|
+
"error": true,
|
|
38
|
+
"warning": true,
|
|
39
|
+
"info": false
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"paths": {
|
|
44
|
+
"components": {
|
|
45
|
+
"AppComponents": {
|
|
46
|
+
"path": "/Components/AppComponents",
|
|
47
|
+
"type": "Visual"
|
|
48
|
+
},
|
|
49
|
+
"Visual": {
|
|
50
|
+
"path": "/Components/Visual",
|
|
51
|
+
"type": "Visual"
|
|
52
|
+
},
|
|
53
|
+
"Service": {
|
|
54
|
+
"path": "/Components/Service",
|
|
55
|
+
"type": "Service"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"themes": "/Themes",
|
|
59
|
+
"styles": "/Styles",
|
|
60
|
+
"routesFile": "/routes.js"
|
|
61
|
+
},
|
|
62
|
+
"router": {
|
|
63
|
+
"defaultRoute": "/"
|
|
64
|
+
},
|
|
65
|
+
"loading": {
|
|
66
|
+
"enabled": true
|
|
67
|
+
},
|
|
68
|
+
"publicFolders": [
|
|
69
|
+
"/Themes",
|
|
70
|
+
"/Styles",
|
|
71
|
+
"/assets",
|
|
72
|
+
"/images"
|
|
73
|
+
]
|
|
74
|
+
}
|