@shellui/cli 0.0.1 → 0.0.5
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 +53 -46
- package/bin/shellui.js +0 -1
- package/package.json +24 -17
- package/src/cli.js +5 -118
- package/src/commands/README.md +40 -0
- package/src/commands/build.js +200 -0
- package/src/commands/index.js +9 -0
- package/src/commands/start.js +180 -0
- package/src/utils/__tests__/config-loaders.test.js +211 -0
- package/src/utils/__tests__/config.test.js +146 -0
- package/src/utils/config-loaders.js +142 -0
- package/src/utils/config.js +69 -0
- package/src/utils/index.js +15 -0
- package/src/utils/package-path.js +54 -0
- package/src/utils/service-worker-plugin.js +151 -0
- package/src/utils/vite.js +82 -0
- package/src/app.jsx +0 -31
- package/src/index.html +0 -12
package/README.md
CHANGED
|
@@ -1,80 +1,87 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @shellui/cli
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
ShellUI is a CLI tool that spins up a React-based microfrontend shell. It is powered by Vite and designed to be easily configurable.
|
|
6
|
-
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
- 🚀 **Fast**: Built on top of Vite for instant server start.
|
|
10
|
-
- ⚛️ **React-based**: The shell is a React application.
|
|
11
|
-
- ⚙️ **Configurable**: Loads configuration from `shellui.json` in your project root.
|
|
12
|
-
- 🔌 **Injectable Config**: Configuration is automatically injected into the shell application.
|
|
3
|
+
ShellUI CLI - Command-line tool for ShellUI
|
|
13
4
|
|
|
14
5
|
## Installation
|
|
15
6
|
|
|
16
|
-
Install ShellUI globally or locally:
|
|
17
|
-
|
|
18
7
|
```bash
|
|
19
|
-
npm install -g shellui
|
|
8
|
+
npm install -g @shellui/cli
|
|
20
9
|
```
|
|
21
10
|
|
|
22
|
-
Or install
|
|
11
|
+
Or install as a dev dependency:
|
|
23
12
|
|
|
24
13
|
```bash
|
|
25
|
-
npm install --save-dev shellui
|
|
14
|
+
npm install --save-dev @shellui/cli
|
|
26
15
|
```
|
|
27
16
|
|
|
28
17
|
## Usage
|
|
29
18
|
|
|
30
|
-
After installation, you can use the `shellui` command directly:
|
|
31
|
-
|
|
32
19
|
```bash
|
|
33
|
-
|
|
20
|
+
shellui start [path/to/project]
|
|
21
|
+
shellui build [path/to/project]
|
|
34
22
|
```
|
|
35
23
|
|
|
36
|
-
|
|
24
|
+
### Commands
|
|
37
25
|
|
|
38
|
-
|
|
39
|
-
shellui start [path/to/project]
|
|
40
|
-
```
|
|
26
|
+
- **start** - Start the ShellUI development server
|
|
41
27
|
|
|
42
|
-
|
|
28
|
+
```bash
|
|
29
|
+
shellui start
|
|
30
|
+
shellui start ./my-project
|
|
31
|
+
```
|
|
43
32
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
```
|
|
33
|
+
- **build** - Build the ShellUI application for production
|
|
34
|
+
```bash
|
|
35
|
+
shellui build
|
|
36
|
+
shellui build ./my-project
|
|
37
|
+
```
|
|
52
38
|
|
|
53
|
-
|
|
39
|
+
## Project Structure
|
|
54
40
|
|
|
55
|
-
|
|
41
|
+
The CLI is organized for maintainability with a clear separation of concerns:
|
|
56
42
|
|
|
57
|
-
|
|
43
|
+
```
|
|
44
|
+
src/
|
|
45
|
+
├── cli.js # Main CLI orchestrator
|
|
46
|
+
├── commands/ # All commands in separate files
|
|
47
|
+
│ ├── index.js # Command registry
|
|
48
|
+
│ ├── start.js # Start command implementation
|
|
49
|
+
│ └── build.js # Build command implementation
|
|
50
|
+
└── utils/ # Utility functions
|
|
51
|
+
├── index.js # Utilities export
|
|
52
|
+
├── config.js # Configuration loading
|
|
53
|
+
└── vite.js # Vite-specific utilities
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Development
|
|
57
|
+
|
|
58
|
+
### Adding a New Command
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
1. Create a new file in `src/commands/` (e.g., `new-command.js`)
|
|
61
|
+
2. Export a command function:
|
|
60
62
|
|
|
61
|
-
```
|
|
62
|
-
{
|
|
63
|
-
|
|
63
|
+
```javascript
|
|
64
|
+
export async function newCommandCommand(args) {
|
|
65
|
+
// Command implementation
|
|
64
66
|
}
|
|
65
67
|
```
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
3. Register it in `src/cli.js`:
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
```javascript
|
|
72
|
+
import { newCommandCommand } from './commands/index.js';
|
|
70
73
|
|
|
71
|
-
|
|
74
|
+
cli.command('new-command [args]', 'Description').action(newCommandCommand);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
4. Export it from `src/commands/index.js`:
|
|
72
78
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
```javascript
|
|
80
|
+
export { newCommandCommand } from './new-command.js';
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
See `src/commands/README.md` for more details.
|
|
76
84
|
|
|
77
85
|
## License
|
|
78
86
|
|
|
79
87
|
MIT
|
|
80
|
-
|
package/bin/shellui.js
CHANGED
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shellui/cli",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "ShellUI -
|
|
5
|
-
"main": "
|
|
3
|
+
"version": "0.0.5",
|
|
4
|
+
"description": "ShellUI CLI - Command-line tool for ShellUI",
|
|
5
|
+
"main": "src/cli.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"shellui": "./bin/shellui.js"
|
|
@@ -13,27 +13,34 @@
|
|
|
13
13
|
"README.md",
|
|
14
14
|
"package.json"
|
|
15
15
|
],
|
|
16
|
-
"scripts": {
|
|
17
|
-
"start": "node bin/shellui.js start",
|
|
18
|
-
"build": "node bin/shellui.js build",
|
|
19
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
20
|
-
},
|
|
21
16
|
"keywords": [
|
|
22
|
-
"
|
|
23
|
-
"shell",
|
|
17
|
+
"shellui",
|
|
24
18
|
"cli",
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"frontend"
|
|
19
|
+
"microfrontend",
|
|
20
|
+
"vite"
|
|
28
21
|
],
|
|
29
22
|
"author": "ShellUI",
|
|
30
23
|
"license": "MIT",
|
|
31
24
|
"dependencies": {
|
|
25
|
+
"@tailwindcss/postcss": "^4.1.18",
|
|
32
26
|
"@vitejs/plugin-react": "^5.1.2",
|
|
27
|
+
"autoprefixer": "^10.4.23",
|
|
33
28
|
"cac": "^6.7.14",
|
|
34
29
|
"picocolors": "^1.1.1",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
30
|
+
"tsx": "^4.21.0",
|
|
31
|
+
"vite": "7.3.1",
|
|
32
|
+
"workbox-build": "^7.1.0",
|
|
33
|
+
"@shellui/core": "0.0.5"
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"vitest": "^4.0.16"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "echo 'CLI build complete'",
|
|
43
|
+
"test": "node scripts/test.js",
|
|
44
|
+
"test:watch": "vitest"
|
|
38
45
|
}
|
|
39
|
-
}
|
|
46
|
+
}
|
package/src/cli.js
CHANGED
|
@@ -1,127 +1,14 @@
|
|
|
1
1
|
import { cac } from 'cac';
|
|
2
|
-
import {
|
|
3
|
-
import react from '@vitejs/plugin-react';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import fs from 'fs';
|
|
6
|
-
import { fileURLToPath } from 'url';
|
|
7
|
-
import pc from 'picocolors';
|
|
2
|
+
import { startCommand, buildCommand } from './commands/index.js';
|
|
8
3
|
|
|
9
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
4
|
const cli = cac('shellui');
|
|
11
5
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
.action(async (root = '.') => {
|
|
15
|
-
const cwd = process.cwd();
|
|
16
|
-
const configDir = path.resolve(cwd, root);
|
|
17
|
-
const configPath = path.join(configDir, 'shellui.json');
|
|
18
|
-
const legacyConfigPath = path.join(configDir, 'shellioj.json');
|
|
6
|
+
// Register commands
|
|
7
|
+
cli.command('start [root]', 'Start the shellui server').action(startCommand);
|
|
19
8
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
let config = {};
|
|
23
|
-
let activeConfigPath = null;
|
|
24
|
-
|
|
25
|
-
if (fs.existsSync(configPath)) {
|
|
26
|
-
activeConfigPath = configPath;
|
|
27
|
-
} else if (fs.existsSync(legacyConfigPath)) {
|
|
28
|
-
activeConfigPath = legacyConfigPath;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (activeConfigPath) {
|
|
32
|
-
try {
|
|
33
|
-
const configFile = fs.readFileSync(activeConfigPath, 'utf-8');
|
|
34
|
-
config = JSON.parse(configFile);
|
|
35
|
-
console.log(pc.green(`Loaded config from ${activeConfigPath}`));
|
|
36
|
-
} catch (e) {
|
|
37
|
-
console.error(pc.red(`Failed to load config: ${e.message}`));
|
|
38
|
-
}
|
|
39
|
-
} else {
|
|
40
|
-
console.log(pc.yellow(`No shellui.json (or shellioj.json) found, using defaults.`));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Path to the index.html inside the package
|
|
44
|
-
const packageRoot = path.resolve(__dirname, '..');
|
|
45
|
-
const templateRoot = path.join(__dirname); // src folder
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
const server = await createServer({
|
|
49
|
-
root: templateRoot, // Serve from src/ where index.html is
|
|
50
|
-
plugins: [react()],
|
|
51
|
-
define: {
|
|
52
|
-
'__SHELLUI_CONFIG__': JSON.stringify(config),
|
|
53
|
-
},
|
|
54
|
-
server: {
|
|
55
|
-
port: config.port || 3000,
|
|
56
|
-
open: true,
|
|
57
|
-
fs: {
|
|
58
|
-
allow: [packageRoot, cwd]
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
await server.listen();
|
|
64
|
-
server.printUrls();
|
|
65
|
-
} catch (e) {
|
|
66
|
-
console.error(pc.red(`Error starting server: ${e.message}`));
|
|
67
|
-
process.exit(1);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
cli
|
|
72
|
-
.command('build [root]', 'Build the shellui application')
|
|
73
|
-
.action(async (root = '.') => {
|
|
74
|
-
const cwd = process.cwd();
|
|
75
|
-
const configDir = path.resolve(cwd, root);
|
|
76
|
-
const configPath = path.join(configDir, 'shellui.json');
|
|
77
|
-
const legacyConfigPath = path.join(configDir, 'shellioj.json');
|
|
78
|
-
|
|
79
|
-
console.log(pc.blue(`Building ShellUI...`));
|
|
80
|
-
|
|
81
|
-
let config = {};
|
|
82
|
-
let activeConfigPath = null;
|
|
83
|
-
|
|
84
|
-
if (fs.existsSync(configPath)) {
|
|
85
|
-
activeConfigPath = configPath;
|
|
86
|
-
} else if (fs.existsSync(legacyConfigPath)) {
|
|
87
|
-
activeConfigPath = legacyConfigPath;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (activeConfigPath) {
|
|
91
|
-
try {
|
|
92
|
-
const configFile = fs.readFileSync(activeConfigPath, 'utf-8');
|
|
93
|
-
config = JSON.parse(configFile);
|
|
94
|
-
console.log(pc.green(`Loaded config from ${activeConfigPath}`));
|
|
95
|
-
} catch (e) {
|
|
96
|
-
console.error(pc.red(`Failed to load config: ${e.message}`));
|
|
97
|
-
}
|
|
98
|
-
} else {
|
|
99
|
-
console.log(pc.yellow(`No shellui.json (or shellioj.json) found, using defaults.`));
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Path to the index.html inside the package
|
|
103
|
-
const templateRoot = path.join(__dirname); // src folder
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
await build({
|
|
107
|
-
root: templateRoot, // Serve from src/ where index.html is
|
|
108
|
-
plugins: [react()],
|
|
109
|
-
define: {
|
|
110
|
-
'__SHELLUI_CONFIG__': JSON.stringify(config),
|
|
111
|
-
},
|
|
112
|
-
build: {
|
|
113
|
-
outDir: path.resolve(cwd, 'dist'),
|
|
114
|
-
emptyOutDir: true,
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
console.log(pc.green('Build complete!'));
|
|
118
|
-
} catch (e) {
|
|
119
|
-
console.error(pc.red(`Error building: ${e.message}`));
|
|
120
|
-
process.exit(1);
|
|
121
|
-
}
|
|
122
|
-
});
|
|
9
|
+
cli.command('build [root]', 'Build the shellui application').action(buildCommand);
|
|
123
10
|
|
|
11
|
+
// Setup CLI metadata
|
|
124
12
|
cli.help();
|
|
125
13
|
cli.version('0.0.1');
|
|
126
14
|
cli.parse();
|
|
127
|
-
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# CLI Commands
|
|
2
|
+
|
|
3
|
+
This directory contains all CLI commands, each in its own file for better maintainability.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
Each command is a separate file that exports a command function:
|
|
8
|
+
|
|
9
|
+
- `start.js` - Start the ShellUI development server
|
|
10
|
+
- `build.js` - Build the ShellUI application for production
|
|
11
|
+
|
|
12
|
+
## Adding a New Command
|
|
13
|
+
|
|
14
|
+
1. Create a new file in this directory (e.g., `new-command.js`)
|
|
15
|
+
2. Export a function that implements the command logic:
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
export async function newCommandCommand(args) {
|
|
19
|
+
// Command implementation
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
3. Register it in `cli.js`:
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
import { newCommandCommand } from './commands/index.js';
|
|
27
|
+
|
|
28
|
+
cli.command('new-command [args]', 'Description of the command').action(newCommandCommand);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
4. Export it from `commands/index.js`:
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
export { newCommandCommand } from './new-command.js';
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Available Commands
|
|
38
|
+
|
|
39
|
+
- **start** - Starts the development server
|
|
40
|
+
- **build** - Builds the application for production
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { build } from 'vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import pc from 'picocolors';
|
|
6
|
+
import { injectManifest } from 'workbox-build';
|
|
7
|
+
import {
|
|
8
|
+
loadConfig,
|
|
9
|
+
getCoreSrcPath,
|
|
10
|
+
createResolveAlias,
|
|
11
|
+
createPostCSSConfig,
|
|
12
|
+
createViteDefine,
|
|
13
|
+
resolvePackagePath,
|
|
14
|
+
} from '../utils/index.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Recursively copy a directory
|
|
18
|
+
* @param {string} src - Source directory
|
|
19
|
+
* @param {string} dest - Destination directory
|
|
20
|
+
*/
|
|
21
|
+
function copyDir(src, dest) {
|
|
22
|
+
if (!fs.existsSync(src)) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!fs.existsSync(dest)) {
|
|
27
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
31
|
+
|
|
32
|
+
for (const entry of entries) {
|
|
33
|
+
const srcPath = path.join(src, entry.name);
|
|
34
|
+
const destPath = path.join(dest, entry.name);
|
|
35
|
+
|
|
36
|
+
if (entry.isDirectory()) {
|
|
37
|
+
copyDir(srcPath, destPath);
|
|
38
|
+
} else {
|
|
39
|
+
fs.copyFileSync(srcPath, destPath);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Build command - Builds the ShellUI application for production
|
|
46
|
+
* @param {string} root - Root directory (default: '.')
|
|
47
|
+
*/
|
|
48
|
+
export async function buildCommand(root = '.') {
|
|
49
|
+
const cwd = process.cwd();
|
|
50
|
+
|
|
51
|
+
console.log(pc.blue(`Building ShellUI...`));
|
|
52
|
+
|
|
53
|
+
// Set environment variable to indicate this is a build
|
|
54
|
+
// This allows shellui.config.ts to detect build mode and generate build ID
|
|
55
|
+
process.env.SHELLUI_BUILD = 'true';
|
|
56
|
+
process.env.NODE_ENV = 'production';
|
|
57
|
+
|
|
58
|
+
// Load configuration
|
|
59
|
+
const config = await loadConfig(root);
|
|
60
|
+
|
|
61
|
+
// Log config summary for debugging
|
|
62
|
+
console.log(pc.blue(`Config loaded:`));
|
|
63
|
+
console.log(pc.gray(` - Title: ${config.title || '(not set)'}`));
|
|
64
|
+
console.log(pc.gray(` - Navigation items: ${config.navigation?.length || 0}`));
|
|
65
|
+
console.log(pc.gray(` - Layout: ${config.layout || 'sidebar'}`));
|
|
66
|
+
|
|
67
|
+
// Verify config is serializable
|
|
68
|
+
try {
|
|
69
|
+
const testSerialize = JSON.parse(JSON.stringify(config));
|
|
70
|
+
console.log(pc.green(` ✓ Config is serializable`));
|
|
71
|
+
} catch (e) {
|
|
72
|
+
console.error(pc.red(` ✗ Config is not serializable: ${e.message}`));
|
|
73
|
+
throw e;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Get core package paths
|
|
77
|
+
const corePackagePath = resolvePackagePath('@shellui/core');
|
|
78
|
+
const coreSrcPath = getCoreSrcPath();
|
|
79
|
+
const resolveAlias = createResolveAlias();
|
|
80
|
+
const postcssConfig = createPostCSSConfig();
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
// Build main app
|
|
84
|
+
await build({
|
|
85
|
+
root: coreSrcPath,
|
|
86
|
+
plugins: [react()],
|
|
87
|
+
define: createViteDefine(config),
|
|
88
|
+
resolve: {
|
|
89
|
+
alias: resolveAlias,
|
|
90
|
+
},
|
|
91
|
+
css: {
|
|
92
|
+
postcss: postcssConfig,
|
|
93
|
+
},
|
|
94
|
+
build: {
|
|
95
|
+
outDir: path.resolve(cwd, 'dist'),
|
|
96
|
+
emptyOutDir: true,
|
|
97
|
+
sourcemap: true,
|
|
98
|
+
// Ensure every build generates unique filenames with content hashes
|
|
99
|
+
// Content hash changes when file content changes, ensuring cache busting
|
|
100
|
+
rollupOptions: {
|
|
101
|
+
input: {
|
|
102
|
+
main: path.join(coreSrcPath, 'index.html'),
|
|
103
|
+
},
|
|
104
|
+
output: {
|
|
105
|
+
// Use content hash in filenames for cache busting
|
|
106
|
+
// [hash] is based on file content, so same content = same hash
|
|
107
|
+
// Different content = different hash, ensuring unique filenames per build when content changes
|
|
108
|
+
entryFileNames: 'assets/[name]-[hash].js',
|
|
109
|
+
chunkFileNames: 'assets/[name]-[hash].js',
|
|
110
|
+
assetFileNames: 'assets/[name]-[hash].[ext]',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Build service worker with Vite first
|
|
117
|
+
console.log(pc.blue('Building service worker...'));
|
|
118
|
+
const swInputPath = path.join(corePackagePath, 'src', 'service-worker', 'sw.ts');
|
|
119
|
+
const distPath = path.resolve(cwd, 'dist');
|
|
120
|
+
const swTempPath = path.join(distPath, 'sw-temp.js');
|
|
121
|
+
|
|
122
|
+
// Build service worker TypeScript to JavaScript
|
|
123
|
+
await build({
|
|
124
|
+
root: coreSrcPath,
|
|
125
|
+
define: createViteDefine(config),
|
|
126
|
+
resolve: {
|
|
127
|
+
alias: resolveAlias,
|
|
128
|
+
},
|
|
129
|
+
build: {
|
|
130
|
+
outDir: distPath,
|
|
131
|
+
emptyOutDir: false,
|
|
132
|
+
sourcemap: true,
|
|
133
|
+
rollupOptions: {
|
|
134
|
+
input: swInputPath,
|
|
135
|
+
output: {
|
|
136
|
+
dir: distPath,
|
|
137
|
+
entryFileNames: 'sw-temp.js',
|
|
138
|
+
format: 'es',
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
write: true,
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Use workbox-build to inject manifest
|
|
146
|
+
const { count, size, warnings } = await injectManifest({
|
|
147
|
+
swSrc: swTempPath,
|
|
148
|
+
swDest: path.join(distPath, 'sw.js'),
|
|
149
|
+
globDirectory: distPath,
|
|
150
|
+
globPatterns: ['**/*.{js,css,html,svg,png,jpg,jpeg,gif,webp,woff,woff2,ttf,eot,ico}'],
|
|
151
|
+
// Don't precache the service worker itself or source maps
|
|
152
|
+
globIgnores: ['sw.js', 'sw-temp.js', '**/*.map', '**/node_modules/**'],
|
|
153
|
+
// Maximum file size to precache (5MB)
|
|
154
|
+
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Remove temporary file
|
|
158
|
+
if (fs.existsSync(swTempPath)) {
|
|
159
|
+
fs.unlinkSync(swTempPath);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (warnings.length > 0) {
|
|
163
|
+
warnings.forEach((warning) => console.warn(pc.yellow(`Warning: ${warning}`)));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
console.log(
|
|
167
|
+
pc.green(
|
|
168
|
+
`Service worker generated: ${count} files precached (${(size / 1024).toFixed(2)} KB)`,
|
|
169
|
+
),
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
// Copy static folder contents to dist if it exists
|
|
173
|
+
// This ensures icons are served from the same path in dev and prod
|
|
174
|
+
const staticPath = path.resolve(cwd, 'static');
|
|
175
|
+
|
|
176
|
+
if (fs.existsSync(staticPath)) {
|
|
177
|
+
console.log(pc.blue('Copying static assets...'));
|
|
178
|
+
// Copy contents of static directly to dist (not dist/static)
|
|
179
|
+
// This way /icons/... works in both dev and prod
|
|
180
|
+
copyDir(staticPath, distPath);
|
|
181
|
+
console.log(pc.green('Static assets copied!'));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Copy index.html to 404.html for SPA routing support
|
|
185
|
+
// This allows hosting providers (like Netlify, Vercel) to serve index.html for all routes
|
|
186
|
+
const indexPath = path.join(distPath, 'index.html');
|
|
187
|
+
const notFoundPath = path.join(distPath, '404.html');
|
|
188
|
+
|
|
189
|
+
if (fs.existsSync(indexPath)) {
|
|
190
|
+
console.log(pc.blue('Creating 404.html for SPA routing...'));
|
|
191
|
+
fs.copyFileSync(indexPath, notFoundPath);
|
|
192
|
+
console.log(pc.green('404.html created!'));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
console.log(pc.green('Build complete!'));
|
|
196
|
+
} catch (e) {
|
|
197
|
+
console.error(pc.red(`Error building: ${e.message}`));
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commands index - Export all available commands
|
|
3
|
+
*
|
|
4
|
+
* This file serves as a central registry of all CLI commands.
|
|
5
|
+
* Each command is in its own file for better maintainability.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export { startCommand } from './start.js';
|
|
9
|
+
export { buildCommand } from './build.js';
|